1# -*- coding: utf-8 -*- # 2# Copyright 2017 Google LLC. All Rights Reserved. 3# 4# Licensed under the Apache License, Version 2.0 (the "License"); 5# you may not use this file except in compliance with the License. 6# You may obtain a copy of the License at 7# 8# http://www.apache.org/licenses/LICENSE-2.0 9# 10# Unless required by applicable law or agreed to in writing, software 11# distributed under the License is distributed on an "AS IS" BASIS, 12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13# See the License for the specific language governing permissions and 14# limitations under the License. 15"""Utility functions for Cloud KMS integration with GCE. 16 17Collection of methods to handle Cloud KMS (Key Management Service) resources 18with Google Compute Engine (GCE). 19""" 20 21from __future__ import absolute_import 22from __future__ import division 23from __future__ import unicode_literals 24 25from googlecloudsdk.calliope import exceptions as calliope_exceptions 26from googlecloudsdk.core import properties 27from googlecloudsdk.core import resources 28 29KMS_HELP_URL = ('https://cloud.google.com/compute/docs/disks/' 30 'customer-managed-encryption') 31_KMS_ARGS = ['kms-key', 'kms-keyring', 'kms-location', 'kms-project', 32 'boot-disk-kms-key', 'boot-disk-kms-keyring', 33 'boot-disk-kms-location', 'boot-disk-kms-project'] 34 35 36def _GetSpecifiedKmsArgs(args): 37 """Returns the first KMS related argument as a string.""" 38 if not args: 39 return None 40 specified = set() 41 for keyword in _KMS_ARGS: 42 if getattr(args, keyword.replace('-', '_'), None): 43 specified.add('--' + keyword) 44 return specified 45 46 47def _GetSpecifiedKmsDict(args): 48 """Returns the first KMS related argument as a string.""" 49 if not args: 50 return None 51 specified = set() 52 for keyword in _KMS_ARGS: 53 if keyword in args: 54 specified.add(keyword) 55 return specified 56 57 58def _DictToKmsKey(args): 59 """Returns the Cloud KMS crypto key name based on the KMS args.""" 60 if not args: 61 return None 62 63 def GetValue(args, key): 64 def GetValueFunc(): 65 val = args[key] if key in args else None 66 if val: 67 return val 68 raise calliope_exceptions.InvalidArgumentException( 69 '--create-disk', 70 'KMS cryptokey resource was not fully specified. Key [{}] must ' 71 'be specified.'.format(key)) 72 return GetValueFunc 73 74 return resources.REGISTRY.Parse( 75 GetValue(args, 'kms-key')(), 76 params={ 77 'projectsId': args['kms-project'] if 'kms-project' in args else 78 properties.VALUES.core.project.GetOrFail, 79 'locationsId': GetValue(args, 'kms-location'), 80 'keyRingsId': GetValue(args, 'kms-keyring'), 81 'cryptoKeysId': GetValue(args, 'kms-key'), 82 }, 83 collection='cloudkms.projects.locations.keyRings.cryptoKeys') 84 85 86def _DictToMessage(args, messages): 87 """Returns the Cloud KMS crypto key name based on the values in the dict.""" 88 key = _DictToKmsKey(args) 89 if not key: 90 return None 91 return messages.CustomerEncryptionKey(kmsKeyName=key.RelativeName()) 92 93 94def MaybeGetKmsKey(args, messages, current_value, boot_disk_prefix=False): 95 """Gets the Cloud KMS CryptoKey reference from command arguments. 96 97 Args: 98 args: Namespaced command line arguments. 99 messages: Compute API messages module. 100 current_value: Current CustomerEncryptionKey value. 101 boot_disk_prefix: If the key flags have the 'boot-disk' prefix. 102 103 Returns: 104 CustomerEncryptionKey message with the KMS key populated if args has a key. 105 Raises: 106 ConflictingArgumentsException if an encryption key is already populated. 107 """ 108 key_arg = args.CONCEPTS.kms_key 109 key = key_arg.Parse() 110 if bool(_GetSpecifiedKmsArgs(args)) and not key: 111 flag = '--boot-disk-kms-key' if boot_disk_prefix else '--kms-key' 112 raise calliope_exceptions.InvalidArgumentException( 113 flag, 'KMS cryptokey resource was not fully specified.') 114 if key: 115 if current_value: 116 raise calliope_exceptions.ConflictingArgumentsException( 117 '--csek-key-file', *_GetSpecifiedKmsArgs(args)) 118 return messages.CustomerEncryptionKey(kmsKeyName=key.RelativeName()) 119 return current_value 120 121 122def MaybeGetKmsKeyFromDict(args, messages, current_value, 123 conflicting_arg='--csek-key-file'): 124 """Gets the Cloud KMS CryptoKey reference for a boot disk's initialize params. 125 126 Args: 127 args: A dictionary of a boot disk's initialize params. 128 messages: Compute API messages module. 129 current_value: Current CustomerEncryptionKey value. 130 conflicting_arg: name of conflicting argument 131 132 Returns: 133 CustomerEncryptionKey message with the KMS key populated if args has a key. 134 Raises: 135 ConflictingArgumentsException if an encryption key is already populated. 136 """ 137 if bool(_GetSpecifiedKmsDict(args)): 138 if current_value: 139 raise calliope_exceptions.ConflictingArgumentsException( 140 conflicting_arg, *_GetSpecifiedKmsArgs(args)) 141 return _DictToMessage(args, messages) 142 return current_value 143