File: //lib/google-cloud-sdk/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.calliope import 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.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 an asymmetric key,
or when creating 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, or ``external'' to create an
externally backed key.
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''.
## 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 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=encryption \
--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
"""
@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)
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 asymmetric 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 exceptions.ToolException(
'--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 exceptions.ToolException(
'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)),
skipInitialVersionCreation=args.skip_initial_version_creation)
flags.SetNextRotationTime(args, req.cryptoKey)
flags.SetRotationPeriod(args, req.cryptoKey)
return req
def Run(self, args):
client = cloudkms_base.GetClientInstance()
return client.projects_locations_keyRings_cryptoKeys.Create(
self._CreateRequest(args))