167 lines
5.4 KiB
Python
167 lines
5.4 KiB
Python
# -*- coding: utf-8 -*- #
|
|
# Copyright 2017 Google LLC. All Rights Reserved.
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
# you may not use this file except in compliance with the License.
|
|
# You may obtain a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
# See the License for the specific language governing permissions and
|
|
# limitations under the License.
|
|
"""Utility functions for Cloud KMS integration with GCE.
|
|
|
|
Collection of methods to handle Cloud KMS (Key Management Service) resources
|
|
with Google Compute Engine (GCE).
|
|
"""
|
|
|
|
from __future__ import absolute_import
|
|
from __future__ import division
|
|
from __future__ import unicode_literals
|
|
|
|
from googlecloudsdk.calliope import exceptions as calliope_exceptions
|
|
from googlecloudsdk.core import properties
|
|
from googlecloudsdk.core import resources
|
|
|
|
KMS_HELP_URL = ('https://cloud.google.com/compute/docs/disks/'
|
|
'customer-managed-encryption')
|
|
_KMS_ARGS = [
|
|
'kms-key', 'kms-keyring', 'kms-location', 'kms-project',
|
|
'boot-disk-kms-key', 'boot-disk-kms-keyring', 'boot-disk-kms-location',
|
|
'boot-disk-kms-project', 'instance-kms-key', 'instance-kms-keyring',
|
|
'instance-kms-location', 'instance-kms-project'
|
|
]
|
|
|
|
|
|
def _GetSpecifiedKmsArgs(args):
|
|
"""Returns the first KMS related argument as a string."""
|
|
if not args:
|
|
return None
|
|
specified = set()
|
|
for keyword in _KMS_ARGS:
|
|
if getattr(args, keyword.replace('-', '_'), None):
|
|
specified.add('--' + keyword)
|
|
return specified
|
|
|
|
|
|
def _GetSpecifiedKmsDict(args):
|
|
"""Returns the first KMS related argument as a string."""
|
|
if not args:
|
|
return None
|
|
specified = set()
|
|
for keyword in _KMS_ARGS:
|
|
if keyword in args:
|
|
specified.add(keyword)
|
|
return specified
|
|
|
|
|
|
def _DictToKmsKey(args):
|
|
"""Returns the Cloud KMS crypto key name based on the KMS args."""
|
|
if not args:
|
|
return None
|
|
|
|
def GetValue(args, key):
|
|
|
|
def GetValueFunc():
|
|
val = args[key] if key in args else None
|
|
if val:
|
|
return val
|
|
raise calliope_exceptions.InvalidArgumentException(
|
|
'--create-disk',
|
|
'KMS cryptokey resource was not fully specified. Key [{}] must '
|
|
'be specified.'.format(key))
|
|
|
|
return GetValueFunc
|
|
|
|
return resources.REGISTRY.Parse(
|
|
GetValue(args, 'kms-key')(),
|
|
params={
|
|
'projectsId':
|
|
args['kms-project'] if 'kms-project' in args else
|
|
properties.VALUES.core.project.GetOrFail,
|
|
'locationsId':
|
|
GetValue(args, 'kms-location'),
|
|
'keyRingsId':
|
|
GetValue(args, 'kms-keyring'),
|
|
'cryptoKeysId':
|
|
GetValue(args, 'kms-key'),
|
|
},
|
|
collection='cloudkms.projects.locations.keyRings.cryptoKeys')
|
|
|
|
|
|
def _DictToMessage(args, messages):
|
|
"""Returns the Cloud KMS crypto key name based on the values in the dict."""
|
|
key = _DictToKmsKey(args)
|
|
if not key:
|
|
return None
|
|
return messages.CustomerEncryptionKey(kmsKeyName=key.RelativeName())
|
|
|
|
|
|
def MaybeGetKmsKey(args,
|
|
messages,
|
|
current_value,
|
|
boot_disk_prefix=False,
|
|
instance_prefix=False):
|
|
"""Gets the Cloud KMS CryptoKey reference from command arguments.
|
|
|
|
Args:
|
|
args: Namespaced command line arguments.
|
|
messages: Compute API messages module.
|
|
current_value: Current CustomerEncryptionKey value.
|
|
boot_disk_prefix: If the key flags have the 'boot-disk' prefix.
|
|
instance_prefix: If the key flags have the 'instance' prefix.
|
|
|
|
Returns:
|
|
CustomerEncryptionKey message with the KMS key populated if args has a key.
|
|
Raises:
|
|
ConflictingArgumentsException if an encryption key is already populated.
|
|
"""
|
|
if boot_disk_prefix:
|
|
key_arg = args.CONCEPTS.boot_disk_kms_key
|
|
flag = '--boot-disk-kms-key'
|
|
elif instance_prefix:
|
|
key_arg = args.CONCEPTS.instance_kms_key
|
|
flag = '--instance-kms-key'
|
|
else:
|
|
key_arg = args.CONCEPTS.kms_key
|
|
flag = '--kms-key'
|
|
key = key_arg.Parse()
|
|
|
|
if flag in _GetSpecifiedKmsArgs(args) and not key:
|
|
raise calliope_exceptions.InvalidArgumentException(
|
|
flag, 'KMS cryptokey resource was not fully specified.')
|
|
if key:
|
|
if current_value:
|
|
raise calliope_exceptions.ConflictingArgumentsException(
|
|
'--csek-key-file', *_GetSpecifiedKmsArgs(args))
|
|
return messages.CustomerEncryptionKey(kmsKeyName=key.RelativeName())
|
|
return current_value
|
|
|
|
|
|
def MaybeGetKmsKeyFromDict(args,
|
|
messages,
|
|
current_value,
|
|
conflicting_arg='--csek-key-file'):
|
|
"""Gets the Cloud KMS CryptoKey reference for a boot disk's initialize params.
|
|
|
|
Args:
|
|
args: A dictionary of a boot disk's initialize params.
|
|
messages: Compute API messages module.
|
|
current_value: Current CustomerEncryptionKey value.
|
|
conflicting_arg: name of conflicting argument
|
|
|
|
Returns:
|
|
CustomerEncryptionKey message with the KMS key populated if args has a key.
|
|
Raises:
|
|
ConflictingArgumentsException if an encryption key is already populated.
|
|
"""
|
|
if bool(_GetSpecifiedKmsDict(args)):
|
|
if current_value:
|
|
raise calliope_exceptions.ConflictingArgumentsException(
|
|
conflicting_arg, *_GetSpecifiedKmsArgs(args))
|
|
return _DictToMessage(args, messages)
|
|
return current_value
|