File: //snap/google-cloud-cli/current/lib/surface/kms/keys/create.py
# -*- 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.
"""Create a key."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.api_lib.cloudkms import base as cloudkms_base
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.kms import exceptions as kms_exceptions
from googlecloudsdk.command_lib.kms import flags
from googlecloudsdk.command_lib.kms import maps
from googlecloudsdk.command_lib.kms import resource_args
from googlecloudsdk.command_lib.util.args import labels_util
@base.UniverseCompatible
@base.ReleaseTracks(
base.ReleaseTrack.ALPHA, base.ReleaseTrack.BETA, base.ReleaseTrack.GA
)
class Create(base.CreateCommand):
r"""Create a new key.
Creates a new key within the given keyring.
The flag `--purpose` is always required when creating a key.
The flag `--default-algorithm` is required when creating a symmetric signing
key, an asymmetric key, or an external key. Algorithm and purpose should be
compatible.
The optional flags `--rotation-period` and `--next-rotation-time` define a
rotation schedule for the key. A schedule can also be defined
by the `--create-rotation-schedule` command.
The flag `--next-rotation-time` must be in ISO 8601 or RFC3339 format,
and `rotation-period` must be in the form INTEGER[UNIT], where units
can be one of seconds (s), minutes (m), hours (h) or days (d).
The optional flag `--protection-level` specifies the physical environment
where crypto operations with the key happen. The default is ``software''; use
``hsm'' to create a hardware-backed key, ``external'' to create an
externally backed key, or ``external-vpc'' to create an external key over vpc.
The optional flag `--labels` defines a user specified key/value pair for the
given key.
The flag `--skip-initial-version-creation` creates a CryptoKey with no
versions. If you import into the CryptoKey, or create a new version in that
CryptoKey, there will be no primary version until one is set using the
`--set-primary-version` command. You must include
`--skip-initial-version-creation` when creating a CryptoKey with protection
level ``external'' or ``external-vpc''.
The optional flag `--import-only` restricts the key to imported key versions
only. To do so, the flag `--skip-initial-version-creation` must also be set.
The optional flag `--destroy-scheduled-duration` defines the destroy schedule
for the key, and must be in the form INTEGER[UNIT], where units can be one of
seconds (s), minutes (m), hours (h) or days (d).
The flag `--crypto-key-backend` defines the resource name for the
backend where the key resides. Required for ``external-vpc'' keys.
The optional flag `--allowed-access-reasons` defines the Key Access
Justifications Policy for the key, and is specified as a comma separated list
of zero or more justification codes defined in
https://cloud.google.com/assured-workloads/key-access-justifications/docs/justification-codes.
The key must be enrolled in Key Access Justifications to use this flag.
## EXAMPLES
The following command creates a key named ``frodo'' with protection level
``software'' within the keyring ``fellowship'' and location ``us-east1'':
$ {command} frodo \
--location=us-east1 \
--keyring=fellowship \
--purpose=encryption
The following command creates a key named ``strider'' with protection level
``software'' within the keyring ``rangers'' and location ``global'' with a
specified rotation schedule:
$ {command} strider \
--location=global --keyring=rangers \
--purpose=encryption \
--rotation-period=30d \
--next-rotation-time=2017-10-12T12:34:56.1234Z
The following command creates a raw encryption key named ``foo'' with
protection level ``software'' within the keyring ``fellowship'' and location
``us-east1'' with two specified labels:
$ {command} foo \
--location=us-east1 \
--keyring=fellowship \
--purpose=raw-encryption \
--default-algorithm=aes-128-cbc
--labels=env=prod,team=kms
The following command creates an asymmetric key named ``samwise'' with
protection level ``software'' and default algorithm ``ec-sign-p256-sha256''
within the keyring ``fellowship'' and location ``us-east1'':
$ {command} samwise \
--location=us-east1 \
--keyring=fellowship \
--purpose=asymmetric-signing \
--default-algorithm=ec-sign-p256-sha256
The following command creates a key named ``gimli'' with protection level
``hsm'' and default algorithm ``google-symmetric-encryption'' within the
keyring ``fellowship'' and location ``us-east1'':
$ {command} gimli \
--location=us-east1 \
--keyring=fellowship \
--purpose=encryption \
--protection-level=hsm
The following command creates a key named ``legolas'' with protection level
``external'' and default algorithm ``external-symmetric-encryption'' within
the keyring ``fellowship'' and location ``us-central1'':
$ {command} legolas \
--location=us-central1 \
--keyring=fellowship \
--purpose=encryption \
--default-algorithm=external-symmetric-encryption \
--protection-level=external
--skip-initial-version-creation
The following command creates a key named ``bilbo'' with protection level
``external-vpc'' and default algorithm ``external-symmetric-encryption'' and
an EkmConnection of ``eagles'' within the keyring ``fellowship'' and location
``us-central1'':
$ {command} bilbo \
--location=us-central1 \
--keyring=fellowship \
--purpose=encryption \
--default-algorithm=external-symmetric-encryption \
--protection-level=external-vpc
--skip-initial-version-creation
--crypto-key-backend="projects/$(gcloud config get project)/
locations/us-central1/ekmConnections/eagles"
The following command creates a key named ``arwen'' with protection level
``software'' within the keyring ``fellowship'' and location ``us-east1'' with
a Key Access Justifications policy that allows access reasons
``customer-initiated-access'' and ``google-initiated-system-operation'':
$ {command} arwen \
--location=us-east1 \
--keyring=fellowship \
--purpose=encryption \
--allowed-access-reasons=customer-initiated-access,google-initiated-system-operation
"""
@staticmethod
def Args(parser):
resource_args.AddKmsKeyResourceArgForKMS(parser, True, 'key')
flags.AddRotationPeriodFlag(parser)
flags.AddNextRotationTimeFlag(parser)
flags.AddSkipInitialVersionCreationFlag(parser)
labels_util.AddCreateLabelsFlags(parser)
parser.add_argument(
'--purpose',
choices=sorted(maps.PURPOSE_MAP.keys()),
required=True,
help='The "purpose" of the key.')
parser.display_info.AddCacheUpdater(flags.KeyRingCompleter)
flags.AddProtectionLevelFlag(parser)
flags.AddDefaultAlgorithmFlag(parser)
flags.AddImportOnlyFlag(parser)
flags.AddDestroyScheduledDurationFlag(parser)
flags.AddCryptoKeyBackendFlag(parser)
flags.AddAllowedAccessReasonsFlag(parser)
def _CreateRequest(self, args):
messages = cloudkms_base.GetMessagesModule()
purpose = maps.PURPOSE_MAP[args.purpose]
valid_algorithms = maps.VALID_ALGORITHMS_MAP[purpose]
# Check default algorithm has been specified for non-symmetric-encryption
# keys. For backward compatibility, the algorithm is
# google-symmetric-encryption by default if the purpose is encryption.
if not args.default_algorithm:
if args.purpose != 'encryption':
raise kms_exceptions.ArgumentError(
'--default-algorithm needs to be specified when creating a key with'
' --purpose={}. The valid algorithms are: {}'.format(
args.purpose, ', '.join(valid_algorithms)))
args.default_algorithm = 'google-symmetric-encryption'
# Check default algorithm and purpose are compatible.
if args.default_algorithm not in valid_algorithms:
raise kms_exceptions.ArgumentError(
'Default algorithm and purpose are incompatible. Here are the valid '
'algorithms for --purpose={}: {}'.format(args.purpose,
', '.join(valid_algorithms)))
crypto_key_ref = args.CONCEPTS.key.Parse()
parent_ref = crypto_key_ref.Parent()
req = messages.CloudkmsProjectsLocationsKeyRingsCryptoKeysCreateRequest(
parent=parent_ref.RelativeName(),
cryptoKeyId=crypto_key_ref.Name(),
cryptoKey=messages.CryptoKey(
purpose=purpose,
versionTemplate=messages.CryptoKeyVersionTemplate(
protectionLevel=maps.PROTECTION_LEVEL_MAPPER.GetEnumForChoice(
args.protection_level),
algorithm=maps.ALGORITHM_MAPPER.GetEnumForChoice(
args.default_algorithm)),
labels=labels_util.ParseCreateArgs(args,
messages.CryptoKey.LabelsValue),
importOnly=args.import_only,
cryptoKeyBackend=args.crypto_key_backend),
skipInitialVersionCreation=args.skip_initial_version_creation)
flags.SetNextRotationTime(args, req.cryptoKey)
flags.SetRotationPeriod(args, req.cryptoKey)
flags.SetDestroyScheduledDuration(args, req.cryptoKey)
flags.SetKeyAccessJustificationsPolicy(args, req.cryptoKey)
return req
def Run(self, args):
client = cloudkms_base.GetClientInstance()
return client.projects_locations_keyRings_cryptoKeys.Create(
self._CreateRequest(args))