From c3dae4864a7e6273c1e8b45a97decf7680e27cde Mon Sep 17 00:00:00 2001 From: Ryan Matsumoto Date: Tue, 7 Feb 2017 13:15:52 -0800 Subject: [PATCH 001/136] Python KMS Apiary P1 samples [(#779)](https://github.com/GoogleCloudPlatform/python-docs-samples/issues/779) * Draft of first half of KMS samples * reversed wrong change * KMS Apiary Python samples - P1 * Few minor style issues * Adding back in space i accidentally deleted * Addressed all code review comments * Renamed api directory to api-client * Addressed more code review comments * Formatting change * Fix quickstart test Change-Id: Ib79dc1345c9c40547f3fd4e9c3c9a48963a3b399 * Update readme Change-Id: Icf4a66083f56d6f51be76ba1cf3b5dc8daf2c4c1 * Add readme Change-Id: I2fbaa55092ef8787f1423d499aa310cab258c0c1 * Added parsers * Final minor changes to parsers * Added autogenerated README * Changed snippets_test keyring name and cryptokey name --- kms/snippets/README.rst | 109 ++++++++++ kms/snippets/README.rst.in | 20 ++ kms/snippets/quickstart.py | 48 +++++ kms/snippets/quickstart_test.py | 19 ++ kms/snippets/requirements.txt | 1 + kms/snippets/snippets.py | 371 ++++++++++++++++++++++++++++++++ kms/snippets/snippets_test.py | 147 +++++++++++++ 7 files changed, 715 insertions(+) create mode 100644 kms/snippets/README.rst create mode 100644 kms/snippets/README.rst.in create mode 100644 kms/snippets/quickstart.py create mode 100644 kms/snippets/quickstart_test.py create mode 100644 kms/snippets/requirements.txt create mode 100644 kms/snippets/snippets.py create mode 100644 kms/snippets/snippets_test.py diff --git a/kms/snippets/README.rst b/kms/snippets/README.rst new file mode 100644 index 000000000000..4c660232385b --- /dev/null +++ b/kms/snippets/README.rst @@ -0,0 +1,109 @@ +.. This file is automatically generated. Do not edit this file directly. + +Google Cloud KMS API Python Samples +=============================================================================== + +This directory contains samples for Google Cloud KMS API. The `Google Cloud KMS API`_ is a service that allows you to keep encryption keys centrally in the cloud, for direct use by cloud services. + + + + +.. _Google Cloud KMS API: https://cloud.google.com/kms/docs/ + +Setup +------------------------------------------------------------------------------- + + +Authentication +++++++++++++++ + +Authentication is typically done through `Application Default Credentials`_, +which means you do not have to change the code to authenticate as long as +your environment has credentials. You have a few options for setting up +authentication: + +#. When running locally, use the `Google Cloud SDK`_ + + .. code-block:: bash + + gcloud beta auth application-default login + + +#. When running on App Engine or Compute Engine, credentials are already + set-up. However, you may need to configure your Compute Engine instance + with `additional scopes`_. + +#. You can create a `Service Account key file`_. This file can be used to + authenticate to Google Cloud Platform services from any environment. To use + the file, set the ``GOOGLE_APPLICATION_CREDENTIALS`` environment variable to + the path to the key file, for example: + + .. code-block:: bash + + export GOOGLE_APPLICATION_CREDENTIALS=/path/to/service_account.json + +.. _Application Default Credentials: https://cloud.google.com/docs/authentication#getting_credentials_for_server-centric_flow +.. _additional scopes: https://cloud.google.com/compute/docs/authentication#using +.. _Service Account key file: https://developers.google.com/identity/protocols/OAuth2ServiceAccount#creatinganaccount + +Install Dependencies +++++++++++++++++++++ + +#. Install `pip`_ and `virtualenv`_ if you do not already have them. + +#. Create a virtualenv. Samples are compatible with Python 2.7 and 3.4+. + + .. code-block:: bash + + $ virtualenv env + $ source env/bin/activate + +#. Install the dependencies needed to run the samples. + + .. code-block:: bash + + $ pip install -r requirements.txt + +.. _pip: https://pip.pypa.io/ +.. _virtualenv: https://virtualenv.pypa.io/ + +Samples +------------------------------------------------------------------------------- + +Quickstart ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + + + +To run this sample: + +.. code-block:: bash + + $ python quickstart.py + + +Snippets ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + + + +To run this sample: + +.. code-block:: bash + + $ python snippets.py + + usage: snippets.py [-h] + {create_keyring,create_cryptokey,encrypt,decrypt,disable_cryptokey_version,destroy_cryptokey_version,add_member_to_cryptokey_policy,get_keyring_policy} + ... + + positional arguments: + {create_keyring,create_cryptokey,encrypt,decrypt,disable_cryptokey_version,destroy_cryptokey_version,add_member_to_cryptokey_policy,get_keyring_policy} + + optional arguments: + -h, --help show this help message and exit + + + + +.. _Google Cloud SDK: https://cloud.google.com/sdk/ \ No newline at end of file diff --git a/kms/snippets/README.rst.in b/kms/snippets/README.rst.in new file mode 100644 index 000000000000..9489051c2c63 --- /dev/null +++ b/kms/snippets/README.rst.in @@ -0,0 +1,20 @@ +# This file is used to generate README.rst + +product: + name: Google Cloud KMS API + short_name: Cloud KMS API + url: https://cloud.google.com/kms/docs/ + description: > + The `Google Cloud KMS API`_ is a service that allows you to keep encryption + keys centrally in the cloud, for direct use by cloud services. + +setup: +- auth +- install_deps + +samples: +- name: Quickstart + file: quickstart.py +- name: Snippets + file: snippets.py + show_help: True diff --git a/kms/snippets/quickstart.py b/kms/snippets/quickstart.py new file mode 100644 index 000000000000..4e94a669118a --- /dev/null +++ b/kms/snippets/quickstart.py @@ -0,0 +1,48 @@ +#!/usr/bin/env python + +# Copyright 2017 Google, Inc +# +# 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 + + +def run_quickstart(): + # [START kms_quickstart] + # Imports the Google APIs client library + from googleapiclient import discovery + + # Your Google Cloud Platform project ID + project_id = 'YOUR_PROJECT_ID' + + # Lists keys in the "global" location. + location = 'global' + + # Creates an API client for the KMS API. + kms_client = discovery.build('cloudkms', 'v1beta1') + + # The resource name of the location associated with the key rings. + parent = 'projects/{}/locations/{}'.format(project_id, location) + + # Lists key rings + request = kms_client.projects().locations().keyRings().list(parent=parent) + response = request.execute() + + if 'keyRings' in response and response['keyRings']: + print('Key rings:') + for key_ring in response['keyRings']: + print(key_ring['name']) + else: + print('No key rings found.') + # [END kms_quickstart] + + +if __name__ == '__main__': + run_quickstart() diff --git a/kms/snippets/quickstart_test.py b/kms/snippets/quickstart_test.py new file mode 100644 index 000000000000..0db901e6bf3e --- /dev/null +++ b/kms/snippets/quickstart_test.py @@ -0,0 +1,19 @@ +# Copyright 2017 Google Inc. 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. + + +def test_quickstart(api_client_inject_project_id): + import quickstart + + quickstart.run_quickstart() diff --git a/kms/snippets/requirements.txt b/kms/snippets/requirements.txt new file mode 100644 index 000000000000..ce6a9bf5bad7 --- /dev/null +++ b/kms/snippets/requirements.txt @@ -0,0 +1 @@ +google-api-python-client==1.6.1 diff --git a/kms/snippets/snippets.py b/kms/snippets/snippets.py new file mode 100644 index 000000000000..9469b9398dd8 --- /dev/null +++ b/kms/snippets/snippets.py @@ -0,0 +1,371 @@ +#!/usr/bin/env python + +# Copyright 2017 Google, Inc +# +# 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 + +import argparse +import base64 +import io + +from googleapiclient import discovery + + +# [START kms_create_keyring] +def create_keyring(project_id, location, keyring): + """Creates a KeyRing in the given location (e.g. global).""" + + # Creates an API client for the KMS API. + kms_client = discovery.build('cloudkms', 'v1beta1') + + # The resource name of the location associated with the KeyRing. + parent = 'projects/{}/locations/{}'.format(project_id, location) + + # Create KeyRing + request = kms_client.projects().locations().keyRings().create( + parent=parent, body={}, keyRingId=keyring) + response = request.execute() + + print('Created KeyRing {}.'.format(response['name'])) +# [END kms_create_keyring] + + +# [START kms_create_cryptokey] +def create_cryptokey(project_id, location, keyring, cryptokey): + """Creates a CryptoKey within a KeyRing in the given location.""" + + # Creates an API client for the KMS API. + kms_client = discovery.build('cloudkms', 'v1beta1') + + # The resource name of the KeyRing associated with the CryptoKey. + parent = 'projects/{}/locations/{}/keyRings/{}'.format( + project_id, location, keyring) + + # Create a CryptoKey for the given KeyRing. + request = kms_client.projects().locations().keyRings().cryptoKeys().create( + parent=parent, body={'purpose': 'ENCRYPT_DECRYPT'}, + cryptoKeyId=cryptokey) + response = request.execute() + + print('Created CryptoKey {}.'.format(response['name'])) +# [END kms_create_cryptokey] + + +# [START kms_encrypt] +def encrypt(project_id, location, keyring, cryptokey, plaintext_file_name, + encrypted_file_name): + """Encrypts data from a plaintext_file_name using the provided CryptoKey + and saves it to an encrypted_file_name so it can only be recovered with a + call to decrypt.""" + + # Creates an API client for the KMS API. + kms_client = discovery.build('cloudkms', 'v1beta1') + + # The resource name of the CryptoKey. + name = 'projects/{}/locations/{}/keyRings/{}/cryptoKeys/{}'.format( + project_id, location, keyring, cryptokey) + + # Read text from the input file. + with io.open(plaintext_file_name, 'rb') as plaintext_file: + plaintext = plaintext_file.read() + encoded_text = base64.b64encode(plaintext) + + # Use the KMS API to encrypt the text. + cryptokeys = kms_client.projects().locations().keyRings().cryptoKeys() + request = cryptokeys.encrypt( + name=name, body={'plaintext': encoded_text.decode('utf-8')}) + response = request.execute() + + # Write the encrypted text to a file. + with io.open(encrypted_file_name, 'wb') as encrypted_file: + encrypted_file.write(response['ciphertext'].encode('utf-8')) + + print('Saved encrypted text to {}.'.format(encrypted_file_name)) +# [END kms_encrypt] + + +# [START kms_decrypt] +def decrypt(project_id, location, keyring, cryptokey, encrypted_file_name, + decrypted_file_name): + """Decrypts data from encrypted_file_name that was previously encrypted + using the CryptoKey with a call to encrypt. Outputs decrypted data to + decrpyted_file_name.""" + + # Creates an API client for the KMS API. + kms_client = discovery.build('cloudkms', 'v1beta1') + + # The resource name of the CryptoKey. + name = 'projects/{}/locations/{}/keyRings/{}/cryptoKeys/{}'.format( + project_id, location, keyring, cryptokey) + + # Read cipher text from the input file. + with io.open(encrypted_file_name, 'rb') as encrypted_file: + cipher_text = encrypted_file.read() + + # Use the KMS API to decrypt the text. + cryptokeys = kms_client.projects().locations().keyRings().cryptoKeys() + request = cryptokeys.decrypt( + name=name, body={'ciphertext': cipher_text.decode('utf-8')}) + response = request.execute() + + # Write the plain text to a file. + with io.open(decrypted_file_name, 'wb') as decrypted_file: + plaintext_encoded = response['plaintext'] + plaintext_decoded = base64.b64decode(plaintext_encoded) + decrypted_file.write(plaintext_decoded) + + print('Saved decrypted text to {}.'.format(decrypted_file_name)) +# [END kms_decrypt] + + +# [START kms_disable_cryptokey_version] +def disable_cryptokey_version(project_id, location, keyring, cryptokey, + version): + """Disables a CryptoKeyVersion associated with a given CryptoKey and + KeyRing.""" + + # Creates an API client for the KMS API. + kms_client = discovery.build('cloudkms', 'v1beta1') + + # Construct the resource name of the CryptoKeyVersion. + name = ( + 'projects/{}/locations/{}/keyRings/{}/cryptoKeys/{}/' + 'cryptoKeyVersions/{}' + .format(project_id, location, keyring, cryptokey, version)) + + # Use the KMS API to disable the CryptoKeyVersion. + cryptokeys = kms_client.projects().locations().keyRings().cryptoKeys() + request = cryptokeys.cryptoKeyVersions().patch( + name=name, body={'state': 'DISABLED'}, updateMask='state') + response = request.execute() + + print('CryptoKeyVersion {}\'s state has been set to {}.'.format( + name, response['state'])) +# [END kms_disable_cryptokey_version] + + +# [START kms_destroy_cryptokey_version] +def destroy_cryptokey_version( + project_id, location, keyring, cryptokey, version): + """Schedules a CryptoKeyVersion associated with a given CryptoKey and + KeyRing for destruction 24 hours in the future.""" + + # Creates an API client for the KMS API. + kms_client = discovery.build('cloudkms', 'v1beta1') + + # Construct the resource name of the CryptoKeyVersion. + name = ( + 'projects/{}/locations/{}/keyRings/{}/cryptoKeys/{}/' + 'cryptoKeyVersions/{}' + .format(project_id, location, keyring, cryptokey, version)) + + # Use the KMS API to schedule the CryptoKeyVersion for destruction. + cryptokeys = kms_client.projects().locations().keyRings().cryptoKeys() + request = cryptokeys.cryptoKeyVersions().destroy(name=name, body={}) + response = request.execute() + + print('CryptoKeyVersion {}\'s state has been set to {}.'.format( + name, response['state'])) +# [END kms_destroy_cryptokey_version] + + +# [START kms_add_member_to_cryptokey_policy] +def add_member_to_cryptokey_policy( + project_id, location, keyring, cryptokey, member, role): + """Adds a member with a given role to the Identity and Access Management + (IAM) policy for a given CryptoKey associated with a KeyRing.""" + + # Creates an API client for the KMS API. + kms_client = discovery.build('cloudkms', 'v1beta1') + + # The resource name of the CryptoKey. + parent = 'projects/{}/locations/{}/keyRings/{}/cryptoKeys/{}'.format( + project_id, location, keyring, cryptokey) + + # Get the current IAM policy and add the new member to it. + cryptokeys = kms_client.projects().locations().keyRings().cryptoKeys() + policy_request = cryptokeys.getIamPolicy(resource=parent) + policy_response = policy_request.execute() + bindings = [] + if 'bindings' in policy_response.keys(): + bindings = policy_response['bindings'] + members = [] + members.append(member) + new_binding = dict() + new_binding['role'] = role + new_binding['members'] = members + bindings.append(new_binding) + policy_response['bindings'] = bindings + + # Set the new IAM Policy. + cryptokeys = kms_client.projects().locations().keyRings().cryptoKeys() + request = cryptokeys.setIamPolicy( + resource=parent, body={'policy': policy_response}) + request.execute() + + print_msg = ( + 'Member {} added with role {} to policy for CryptoKey {} in KeyRing {}' + .format(member, role, cryptokey, keyring)) + print(print_msg) +# [END kms_add_member_to_cryptokey_policy] + + +# [START kms_get_keyring_policy] +def get_keyring_policy(project_id, location, keyring): + """Gets the Identity and Access Management (IAM) policy for a given KeyRing + and prints out roles and the members assigned to those roles.""" + + # Creates an API client for the KMS API. + kms_client = discovery.build('cloudkms', 'v1beta1') + + # The resource name of the KeyRing. + parent = 'projects/{}/locations/{}/keyRings/{}'.format( + project_id, location, keyring) + + # Get the current IAM policy. + request = kms_client.projects().locations().keyRings().getIamPolicy( + resource=parent) + response = request.execute() + + if 'bindings' in response.keys(): + print('Printing IAM policy for resource {}:'.format(parent)) + for binding in response['bindings']: + print('') + print('Role: {}'.format(binding['role'])) + print('Members:') + for member in binding['members']: + print(member) + print('') + else: + print('No roles found for resource {}.'.format(parent)) +# [END kms_get_keyring_policy] + + +if __name__ == '__main__': + parser = argparse.ArgumentParser( + description=__doc__, + formatter_class=argparse.RawDescriptionHelpFormatter) + subparsers = parser.add_subparsers(dest='command') + + create_keyring_parser = subparsers.add_parser('create_keyring') + create_keyring_parser.add_argument('project_id') + create_keyring_parser.add_argument('location') + create_keyring_parser.add_argument('keyring') + + create_cryptokey_parser = subparsers.add_parser('create_cryptokey') + create_cryptokey_parser.add_argument('project_id') + create_cryptokey_parser.add_argument('location') + create_cryptokey_parser.add_argument('keyring') + create_cryptokey_parser.add_argument('cryptokey') + + encrypt_parser = subparsers.add_parser('encrypt') + encrypt_parser.add_argument('project_id') + encrypt_parser.add_argument('location') + encrypt_parser.add_argument('keyring') + encrypt_parser.add_argument('cryptokey') + encrypt_parser.add_argument('infile') + encrypt_parser.add_argument('outfile') + + decrypt_parser = subparsers.add_parser('decrypt') + decrypt_parser.add_argument('project_id') + decrypt_parser.add_argument('location') + decrypt_parser.add_argument('keyring') + decrypt_parser.add_argument('cryptokey') + decrypt_parser.add_argument('infile') + decrypt_parser.add_argument('outfile') + + disable_cryptokey_version_parser = subparsers.add_parser( + 'disable_cryptokey_version') + disable_cryptokey_version_parser.add_argument('project_id') + disable_cryptokey_version_parser.add_argument('location') + disable_cryptokey_version_parser.add_argument('keyring') + disable_cryptokey_version_parser.add_argument('cryptokey') + disable_cryptokey_version_parser.add_argument('version') + + destroy_cryptokey_version_parser = subparsers.add_parser( + 'destroy_cryptokey_version') + destroy_cryptokey_version_parser.add_argument('project_id') + destroy_cryptokey_version_parser.add_argument('location') + destroy_cryptokey_version_parser.add_argument('keyring') + destroy_cryptokey_version_parser.add_argument('cryptokey') + destroy_cryptokey_version_parser.add_argument('version') + + add_member_to_cryptokey_policy_parser = subparsers.add_parser( + 'add_member_to_cryptokey_policy') + add_member_to_cryptokey_policy_parser.add_argument('project_id') + add_member_to_cryptokey_policy_parser.add_argument('location') + add_member_to_cryptokey_policy_parser.add_argument('keyring') + add_member_to_cryptokey_policy_parser.add_argument('cryptokey') + add_member_to_cryptokey_policy_parser.add_argument('member') + add_member_to_cryptokey_policy_parser.add_argument('role') + + get_keyring_policy_parser = subparsers.add_parser('get_keyring_policy') + get_keyring_policy_parser.add_argument('project_id') + get_keyring_policy_parser.add_argument('location') + get_keyring_policy_parser.add_argument('keyring') + + args = parser.parse_args() + + if args.command == 'create_keyring': + create_keyring( + args.project_id, + args.location, + args.keyring) + elif args.command == 'create_cryptokey': + create_cryptokey( + args.project_id, + args.location, + args.keyring, + args.cryptokey) + elif args.command == 'encrypt': + encrypt( + args.project_id, + args.location, + args.keyring, + args.cryptokey, + args.infile, + args.outfile) + elif args.command == 'decrypt': + decrypt( + args.project_id, + args.location, + args.keyring, + args.cryptokey, + args.infile, + args.outfile) + elif args.command == 'disable_cryptokey_version': + disable_cryptokey_version( + args.project_id, + args.location, + args.keyring, + args.cryptokey, + args.version) + elif args.command == 'destroy_cryptokey_version': + destroy_cryptokey_version( + args.project_id, + args.location, + args.keyring, + args.cryptokey, + args.version) + elif args.command == 'add_member_to_cryptokey_policy': + add_member_to_cryptokey_policy( + args.project_id, + args.location, + args.keyring, + args.cryptokey, + args.member, + args.role) + elif args.command == 'get_keyring_policy': + get_keyring_policy( + args.project_id, + args.location, + args.keyring) diff --git a/kms/snippets/snippets_test.py b/kms/snippets/snippets_test.py new file mode 100644 index 000000000000..e4deda1c1280 --- /dev/null +++ b/kms/snippets/snippets_test.py @@ -0,0 +1,147 @@ +#!/usr/bin/env python + +# Copyright 2017 Google, Inc +# +# 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 + +from googleapiclient import discovery + +import snippets + + +# Your Google Cloud Platform Key Location +LOCATION = 'global' + +# Your Google Cloud Platform KeyRing name +KEYRING = 'sample-keyring-43' + +# Your Google Cloud Platform CryptoKey name +CRYPTOKEY = 'sample-key-43' + +# Your Google Cloud Platform CryptoKeyVersion name +VERSION = 1 + +# A member to add to our IAM policy +MEMBER = 'user:ryanmats@google.com' + +# The role we want our new member to have for our IAM policy +ROLE = 'roles/owner' + + +def test_create_keyring(capsys, cloud_config): + snippets.create_keyring(cloud_config.project, LOCATION, KEYRING) + out, _ = capsys.readouterr() + expected = 'Created KeyRing projects/{}/locations/{}/keyRings/{}.'.format( + cloud_config.project, LOCATION, KEYRING) + assert expected in out + + +def test_create_cryptokey(capsys, cloud_config): + snippets.create_cryptokey( + cloud_config.project, LOCATION, KEYRING, CRYPTOKEY) + out, _ = capsys.readouterr() + expected = ( + 'Created CryptoKey projects/{}/locations/{}/keyRings/{}/cryptoKeys/{}.' + .format(cloud_config.project, LOCATION, KEYRING, CRYPTOKEY)) + assert expected in out + + +def test_encrypt_decrypt(capsys, cloud_config, tmpdir): + # Write to a plaintext file. + tmpdir.join('in.txt').write('SampleText') + + # Construct temporary files. + plaintext_file = tmpdir.join('in.txt') + encrypted_file = tmpdir.join('out.txt') + decrypted_file = tmpdir.join('out2.txt') + + # Encrypt text and then decrypt it. + snippets.encrypt( + cloud_config.project, LOCATION, KEYRING, CRYPTOKEY, + str(plaintext_file), str(encrypted_file)) + snippets.decrypt( + cloud_config.project, LOCATION, KEYRING, CRYPTOKEY, + str(encrypted_file), str(decrypted_file)) + + # Make sure the decrypted text matches the original text. + decrypted_text = decrypted_file.read() + assert decrypted_text == 'SampleText' + + # Make sure other output is as expected. + out, _ = capsys.readouterr() + assert 'Saved encrypted text to {}.'.format(str(encrypted_file)) in out + assert 'Saved decrypted text to {}.'.format(str(decrypted_file)) in out + + +def test_disable_cryptokey_version(capsys, cloud_config): + snippets.disable_cryptokey_version( + cloud_config.project, LOCATION, KEYRING, CRYPTOKEY, VERSION) + out, _ = capsys.readouterr() + expected = ( + 'CryptoKeyVersion projects/{}/locations/{}/keyRings/{}/cryptoKeys/{}/' + 'cryptoKeyVersions/{}\'s state has been set to {}.' + .format( + cloud_config.project, LOCATION, KEYRING, CRYPTOKEY, VERSION, + 'DISABLED')) + assert expected in out + + +def test_destroy_cryptokey_version(capsys, cloud_config): + snippets.destroy_cryptokey_version( + cloud_config.project, LOCATION, KEYRING, CRYPTOKEY, VERSION) + out, _ = capsys.readouterr() + expected = ( + 'CryptoKeyVersion projects/{}/locations/{}/keyRings/{}/cryptoKeys/{}/' + 'cryptoKeyVersions/{}\'s state has been set to {}.' + .format( + cloud_config.project, LOCATION, KEYRING, CRYPTOKEY, VERSION, + 'DESTROY_SCHEDULED')) + assert expected in out + + +def test_add_member_to_cryptokey_policy(capsys, cloud_config): + snippets.add_member_to_cryptokey_policy( + cloud_config.project, LOCATION, KEYRING, CRYPTOKEY, MEMBER, ROLE) + out, _ = capsys.readouterr() + expected = ( + 'Member {} added with role {} to policy for CryptoKey {} in KeyRing {}' + .format(MEMBER, ROLE, CRYPTOKEY, KEYRING)) + assert expected in out + + kms_client = discovery.build('cloudkms', 'v1beta1') + parent = 'projects/{}/locations/{}/keyRings/{}/cryptoKeys/{}'.format( + cloud_config.project, LOCATION, KEYRING, CRYPTOKEY) + cryptokeys = kms_client.projects().locations().keyRings().cryptoKeys() + policy_request = cryptokeys.getIamPolicy(resource=parent) + policy_response = policy_request.execute() + assert 'bindings' in policy_response.keys() + bindings = policy_response['bindings'] + found_member_role_pair = False + for binding in bindings: + if binding['role'] == ROLE: + for user in binding['members']: + if user == MEMBER: + found_member_role_pair = True + assert found_member_role_pair + + +def test_get_keyring_policy(capsys, cloud_config): + project_id = cloud_config.project + snippets.get_keyring_policy(project_id, LOCATION, KEYRING) + out, _ = capsys.readouterr() + expected_roles_exist = ( + 'Printing IAM policy for resource projects/{}/locations/{}/keyRings/{}' + ':'.format(project_id, LOCATION, KEYRING)) + expected_no_roles = ( + 'No roles found for resource projects/{}/locations/{}/keyRings/{}.' + .format(project_id, LOCATION, KEYRING)) + assert (expected_roles_exist in out) or (expected_no_roles in out) From c031a3470ca7e0d8a7f8d15364b39634ce64509e Mon Sep 17 00:00:00 2001 From: Ryan Matsumoto Date: Wed, 8 Feb 2017 14:41:11 -0800 Subject: [PATCH 002/136] random generation of keyring / cryptokey names [(#786)](https://github.com/GoogleCloudPlatform/python-docs-samples/issues/786) * random generation of keyring / cryptokey names * Fixed formatting of keyring name and cryptokey name --- kms/snippets/snippets_test.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/kms/snippets/snippets_test.py b/kms/snippets/snippets_test.py index e4deda1c1280..2ea0b12c3a54 100644 --- a/kms/snippets/snippets_test.py +++ b/kms/snippets/snippets_test.py @@ -13,6 +13,9 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and +import random +import string + from googleapiclient import discovery import snippets @@ -22,10 +25,12 @@ LOCATION = 'global' # Your Google Cloud Platform KeyRing name -KEYRING = 'sample-keyring-43' +KEYRING = ''.join( + random.choice(string.ascii_lowercase + string.digits) for _ in range(12)) # Your Google Cloud Platform CryptoKey name -CRYPTOKEY = 'sample-key-43' +CRYPTOKEY = ''.join( + random.choice(string.ascii_lowercase + string.digits) for _ in range(12)) # Your Google Cloud Platform CryptoKeyVersion name VERSION = 1 From cc8e1b4975f87e21526544b6fd6300ecfdd62fb3 Mon Sep 17 00:00:00 2001 From: DPE bot Date: Thu, 9 Feb 2017 08:59:42 -0800 Subject: [PATCH 003/136] Auto-update dependencies. [(#790)](https://github.com/GoogleCloudPlatform/python-docs-samples/issues/790) --- kms/snippets/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kms/snippets/requirements.txt b/kms/snippets/requirements.txt index ce6a9bf5bad7..4f77d6936d70 100644 --- a/kms/snippets/requirements.txt +++ b/kms/snippets/requirements.txt @@ -1 +1 @@ -google-api-python-client==1.6.1 +google-api-python-client==1.6.2 From 7147ccf09b8f509f8b5e8f9ef4e1c8c52a749cb3 Mon Sep 17 00:00:00 2001 From: Jon Wayne Parrott Date: Thu, 16 Feb 2017 17:07:45 -0800 Subject: [PATCH 004/136] Remove usage of GoogleCredentials [(#810)](https://github.com/GoogleCloudPlatform/python-docs-samples/issues/810) --- kms/snippets/quickstart.py | 4 ++-- kms/snippets/snippets.py | 18 +++++++++--------- kms/snippets/snippets_test.py | 4 ++-- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/kms/snippets/quickstart.py b/kms/snippets/quickstart.py index 4e94a669118a..f4e4c7bed61b 100644 --- a/kms/snippets/quickstart.py +++ b/kms/snippets/quickstart.py @@ -17,7 +17,7 @@ def run_quickstart(): # [START kms_quickstart] # Imports the Google APIs client library - from googleapiclient import discovery + import googleapiclient.discovery # Your Google Cloud Platform project ID project_id = 'YOUR_PROJECT_ID' @@ -26,7 +26,7 @@ def run_quickstart(): location = 'global' # Creates an API client for the KMS API. - kms_client = discovery.build('cloudkms', 'v1beta1') + kms_client = googleapiclient.discovery.build('cloudkms', 'v1beta1') # The resource name of the location associated with the key rings. parent = 'projects/{}/locations/{}'.format(project_id, location) diff --git a/kms/snippets/snippets.py b/kms/snippets/snippets.py index 9469b9398dd8..1c0a52923920 100644 --- a/kms/snippets/snippets.py +++ b/kms/snippets/snippets.py @@ -17,7 +17,7 @@ import base64 import io -from googleapiclient import discovery +import googleapiclient.discovery # [START kms_create_keyring] @@ -25,7 +25,7 @@ def create_keyring(project_id, location, keyring): """Creates a KeyRing in the given location (e.g. global).""" # Creates an API client for the KMS API. - kms_client = discovery.build('cloudkms', 'v1beta1') + kms_client = googleapiclient.discovery.build('cloudkms', 'v1beta1') # The resource name of the location associated with the KeyRing. parent = 'projects/{}/locations/{}'.format(project_id, location) @@ -44,7 +44,7 @@ def create_cryptokey(project_id, location, keyring, cryptokey): """Creates a CryptoKey within a KeyRing in the given location.""" # Creates an API client for the KMS API. - kms_client = discovery.build('cloudkms', 'v1beta1') + kms_client = googleapiclient.discovery.build('cloudkms', 'v1beta1') # The resource name of the KeyRing associated with the CryptoKey. parent = 'projects/{}/locations/{}/keyRings/{}'.format( @@ -68,7 +68,7 @@ def encrypt(project_id, location, keyring, cryptokey, plaintext_file_name, call to decrypt.""" # Creates an API client for the KMS API. - kms_client = discovery.build('cloudkms', 'v1beta1') + kms_client = googleapiclient.discovery.build('cloudkms', 'v1beta1') # The resource name of the CryptoKey. name = 'projects/{}/locations/{}/keyRings/{}/cryptoKeys/{}'.format( @@ -101,7 +101,7 @@ def decrypt(project_id, location, keyring, cryptokey, encrypted_file_name, decrpyted_file_name.""" # Creates an API client for the KMS API. - kms_client = discovery.build('cloudkms', 'v1beta1') + kms_client = googleapiclient.discovery.build('cloudkms', 'v1beta1') # The resource name of the CryptoKey. name = 'projects/{}/locations/{}/keyRings/{}/cryptoKeys/{}'.format( @@ -134,7 +134,7 @@ def disable_cryptokey_version(project_id, location, keyring, cryptokey, KeyRing.""" # Creates an API client for the KMS API. - kms_client = discovery.build('cloudkms', 'v1beta1') + kms_client = googleapiclient.discovery.build('cloudkms', 'v1beta1') # Construct the resource name of the CryptoKeyVersion. name = ( @@ -160,7 +160,7 @@ def destroy_cryptokey_version( KeyRing for destruction 24 hours in the future.""" # Creates an API client for the KMS API. - kms_client = discovery.build('cloudkms', 'v1beta1') + kms_client = googleapiclient.discovery.build('cloudkms', 'v1beta1') # Construct the resource name of the CryptoKeyVersion. name = ( @@ -185,7 +185,7 @@ def add_member_to_cryptokey_policy( (IAM) policy for a given CryptoKey associated with a KeyRing.""" # Creates an API client for the KMS API. - kms_client = discovery.build('cloudkms', 'v1beta1') + kms_client = googleapiclient.discovery.build('cloudkms', 'v1beta1') # The resource name of the CryptoKey. parent = 'projects/{}/locations/{}/keyRings/{}/cryptoKeys/{}'.format( @@ -225,7 +225,7 @@ def get_keyring_policy(project_id, location, keyring): and prints out roles and the members assigned to those roles.""" # Creates an API client for the KMS API. - kms_client = discovery.build('cloudkms', 'v1beta1') + kms_client = googleapiclient.discovery.build('cloudkms', 'v1beta1') # The resource name of the KeyRing. parent = 'projects/{}/locations/{}/keyRings/{}'.format( diff --git a/kms/snippets/snippets_test.py b/kms/snippets/snippets_test.py index 2ea0b12c3a54..dc532bcea346 100644 --- a/kms/snippets/snippets_test.py +++ b/kms/snippets/snippets_test.py @@ -16,7 +16,7 @@ import random import string -from googleapiclient import discovery +import googleapiclient.discovery import snippets @@ -122,7 +122,7 @@ def test_add_member_to_cryptokey_policy(capsys, cloud_config): .format(MEMBER, ROLE, CRYPTOKEY, KEYRING)) assert expected in out - kms_client = discovery.build('cloudkms', 'v1beta1') + kms_client = googleapiclient.discovery.build('cloudkms', 'v1beta1') parent = 'projects/{}/locations/{}/keyRings/{}/cryptoKeys/{}'.format( cloud_config.project, LOCATION, KEYRING, CRYPTOKEY) cryptokeys = kms_client.projects().locations().keyRings().cryptoKeys() From 69a7649cf2925b8a5ae1a5167436f94ffbe68912 Mon Sep 17 00:00:00 2001 From: Phil Coakley Date: Thu, 16 Mar 2017 17:20:15 -0400 Subject: [PATCH 005/136] Updates Could-KMS sample code to use V1 libraries. [(#856)](https://github.com/GoogleCloudPlatform/python-docs-samples/issues/856) --- kms/snippets/quickstart.py | 2 +- kms/snippets/snippets.py | 16 ++++++++-------- kms/snippets/snippets_test.py | 2 +- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/kms/snippets/quickstart.py b/kms/snippets/quickstart.py index f4e4c7bed61b..042bcae9ecb8 100644 --- a/kms/snippets/quickstart.py +++ b/kms/snippets/quickstart.py @@ -26,7 +26,7 @@ def run_quickstart(): location = 'global' # Creates an API client for the KMS API. - kms_client = googleapiclient.discovery.build('cloudkms', 'v1beta1') + kms_client = googleapiclient.discovery.build('cloudkms', 'v1') # The resource name of the location associated with the key rings. parent = 'projects/{}/locations/{}'.format(project_id, location) diff --git a/kms/snippets/snippets.py b/kms/snippets/snippets.py index 1c0a52923920..8196c5840f03 100644 --- a/kms/snippets/snippets.py +++ b/kms/snippets/snippets.py @@ -25,7 +25,7 @@ def create_keyring(project_id, location, keyring): """Creates a KeyRing in the given location (e.g. global).""" # Creates an API client for the KMS API. - kms_client = googleapiclient.discovery.build('cloudkms', 'v1beta1') + kms_client = googleapiclient.discovery.build('cloudkms', 'v1') # The resource name of the location associated with the KeyRing. parent = 'projects/{}/locations/{}'.format(project_id, location) @@ -44,7 +44,7 @@ def create_cryptokey(project_id, location, keyring, cryptokey): """Creates a CryptoKey within a KeyRing in the given location.""" # Creates an API client for the KMS API. - kms_client = googleapiclient.discovery.build('cloudkms', 'v1beta1') + kms_client = googleapiclient.discovery.build('cloudkms', 'v1') # The resource name of the KeyRing associated with the CryptoKey. parent = 'projects/{}/locations/{}/keyRings/{}'.format( @@ -68,7 +68,7 @@ def encrypt(project_id, location, keyring, cryptokey, plaintext_file_name, call to decrypt.""" # Creates an API client for the KMS API. - kms_client = googleapiclient.discovery.build('cloudkms', 'v1beta1') + kms_client = googleapiclient.discovery.build('cloudkms', 'v1') # The resource name of the CryptoKey. name = 'projects/{}/locations/{}/keyRings/{}/cryptoKeys/{}'.format( @@ -101,7 +101,7 @@ def decrypt(project_id, location, keyring, cryptokey, encrypted_file_name, decrpyted_file_name.""" # Creates an API client for the KMS API. - kms_client = googleapiclient.discovery.build('cloudkms', 'v1beta1') + kms_client = googleapiclient.discovery.build('cloudkms', 'v1') # The resource name of the CryptoKey. name = 'projects/{}/locations/{}/keyRings/{}/cryptoKeys/{}'.format( @@ -134,7 +134,7 @@ def disable_cryptokey_version(project_id, location, keyring, cryptokey, KeyRing.""" # Creates an API client for the KMS API. - kms_client = googleapiclient.discovery.build('cloudkms', 'v1beta1') + kms_client = googleapiclient.discovery.build('cloudkms', 'v1') # Construct the resource name of the CryptoKeyVersion. name = ( @@ -160,7 +160,7 @@ def destroy_cryptokey_version( KeyRing for destruction 24 hours in the future.""" # Creates an API client for the KMS API. - kms_client = googleapiclient.discovery.build('cloudkms', 'v1beta1') + kms_client = googleapiclient.discovery.build('cloudkms', 'v1') # Construct the resource name of the CryptoKeyVersion. name = ( @@ -185,7 +185,7 @@ def add_member_to_cryptokey_policy( (IAM) policy for a given CryptoKey associated with a KeyRing.""" # Creates an API client for the KMS API. - kms_client = googleapiclient.discovery.build('cloudkms', 'v1beta1') + kms_client = googleapiclient.discovery.build('cloudkms', 'v1') # The resource name of the CryptoKey. parent = 'projects/{}/locations/{}/keyRings/{}/cryptoKeys/{}'.format( @@ -225,7 +225,7 @@ def get_keyring_policy(project_id, location, keyring): and prints out roles and the members assigned to those roles.""" # Creates an API client for the KMS API. - kms_client = googleapiclient.discovery.build('cloudkms', 'v1beta1') + kms_client = googleapiclient.discovery.build('cloudkms', 'v1') # The resource name of the KeyRing. parent = 'projects/{}/locations/{}/keyRings/{}'.format( diff --git a/kms/snippets/snippets_test.py b/kms/snippets/snippets_test.py index dc532bcea346..873ce90d8f01 100644 --- a/kms/snippets/snippets_test.py +++ b/kms/snippets/snippets_test.py @@ -122,7 +122,7 @@ def test_add_member_to_cryptokey_policy(capsys, cloud_config): .format(MEMBER, ROLE, CRYPTOKEY, KEYRING)) assert expected in out - kms_client = googleapiclient.discovery.build('cloudkms', 'v1beta1') + kms_client = googleapiclient.discovery.build('cloudkms', 'v1') parent = 'projects/{}/locations/{}/keyRings/{}/cryptoKeys/{}'.format( cloud_config.project, LOCATION, KEYRING, CRYPTOKEY) cryptokeys = kms_client.projects().locations().keyRings().cryptoKeys() From e67c399d2213314c276c1c43a0c9fc03de7bdca3 Mon Sep 17 00:00:00 2001 From: Jon Wayne Parrott Date: Tue, 4 Apr 2017 16:08:30 -0700 Subject: [PATCH 006/136] Remove cloud config fixture [(#887)](https://github.com/GoogleCloudPlatform/python-docs-samples/issues/887) * Remove cloud config fixture * Fix client secrets * Fix bigtable instance --- kms/snippets/snippets_test.py | 42 ++++++++++++++++++----------------- 1 file changed, 22 insertions(+), 20 deletions(-) diff --git a/kms/snippets/snippets_test.py b/kms/snippets/snippets_test.py index 873ce90d8f01..b3c4800d3360 100644 --- a/kms/snippets/snippets_test.py +++ b/kms/snippets/snippets_test.py @@ -13,6 +13,7 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and +import os import random import string @@ -20,6 +21,7 @@ import snippets +PROJECT = os.environ['GCLOUD_PROJECT'] # Your Google Cloud Platform Key Location LOCATION = 'global' @@ -42,25 +44,25 @@ ROLE = 'roles/owner' -def test_create_keyring(capsys, cloud_config): - snippets.create_keyring(cloud_config.project, LOCATION, KEYRING) +def test_create_keyring(capsys): + snippets.create_keyring(PROJECT, LOCATION, KEYRING) out, _ = capsys.readouterr() expected = 'Created KeyRing projects/{}/locations/{}/keyRings/{}.'.format( - cloud_config.project, LOCATION, KEYRING) + PROJECT, LOCATION, KEYRING) assert expected in out -def test_create_cryptokey(capsys, cloud_config): +def test_create_cryptokey(capsys): snippets.create_cryptokey( - cloud_config.project, LOCATION, KEYRING, CRYPTOKEY) + PROJECT, LOCATION, KEYRING, CRYPTOKEY) out, _ = capsys.readouterr() expected = ( 'Created CryptoKey projects/{}/locations/{}/keyRings/{}/cryptoKeys/{}.' - .format(cloud_config.project, LOCATION, KEYRING, CRYPTOKEY)) + .format(PROJECT, LOCATION, KEYRING, CRYPTOKEY)) assert expected in out -def test_encrypt_decrypt(capsys, cloud_config, tmpdir): +def test_encrypt_decrypt(capsys, tmpdir): # Write to a plaintext file. tmpdir.join('in.txt').write('SampleText') @@ -71,10 +73,10 @@ def test_encrypt_decrypt(capsys, cloud_config, tmpdir): # Encrypt text and then decrypt it. snippets.encrypt( - cloud_config.project, LOCATION, KEYRING, CRYPTOKEY, + PROJECT, LOCATION, KEYRING, CRYPTOKEY, str(plaintext_file), str(encrypted_file)) snippets.decrypt( - cloud_config.project, LOCATION, KEYRING, CRYPTOKEY, + PROJECT, LOCATION, KEYRING, CRYPTOKEY, str(encrypted_file), str(decrypted_file)) # Make sure the decrypted text matches the original text. @@ -87,35 +89,35 @@ def test_encrypt_decrypt(capsys, cloud_config, tmpdir): assert 'Saved decrypted text to {}.'.format(str(decrypted_file)) in out -def test_disable_cryptokey_version(capsys, cloud_config): +def test_disable_cryptokey_version(capsys): snippets.disable_cryptokey_version( - cloud_config.project, LOCATION, KEYRING, CRYPTOKEY, VERSION) + PROJECT, LOCATION, KEYRING, CRYPTOKEY, VERSION) out, _ = capsys.readouterr() expected = ( 'CryptoKeyVersion projects/{}/locations/{}/keyRings/{}/cryptoKeys/{}/' 'cryptoKeyVersions/{}\'s state has been set to {}.' .format( - cloud_config.project, LOCATION, KEYRING, CRYPTOKEY, VERSION, + PROJECT, LOCATION, KEYRING, CRYPTOKEY, VERSION, 'DISABLED')) assert expected in out -def test_destroy_cryptokey_version(capsys, cloud_config): +def test_destroy_cryptokey_version(capsys): snippets.destroy_cryptokey_version( - cloud_config.project, LOCATION, KEYRING, CRYPTOKEY, VERSION) + PROJECT, LOCATION, KEYRING, CRYPTOKEY, VERSION) out, _ = capsys.readouterr() expected = ( 'CryptoKeyVersion projects/{}/locations/{}/keyRings/{}/cryptoKeys/{}/' 'cryptoKeyVersions/{}\'s state has been set to {}.' .format( - cloud_config.project, LOCATION, KEYRING, CRYPTOKEY, VERSION, + PROJECT, LOCATION, KEYRING, CRYPTOKEY, VERSION, 'DESTROY_SCHEDULED')) assert expected in out -def test_add_member_to_cryptokey_policy(capsys, cloud_config): +def test_add_member_to_cryptokey_policy(capsys): snippets.add_member_to_cryptokey_policy( - cloud_config.project, LOCATION, KEYRING, CRYPTOKEY, MEMBER, ROLE) + PROJECT, LOCATION, KEYRING, CRYPTOKEY, MEMBER, ROLE) out, _ = capsys.readouterr() expected = ( 'Member {} added with role {} to policy for CryptoKey {} in KeyRing {}' @@ -124,7 +126,7 @@ def test_add_member_to_cryptokey_policy(capsys, cloud_config): kms_client = googleapiclient.discovery.build('cloudkms', 'v1') parent = 'projects/{}/locations/{}/keyRings/{}/cryptoKeys/{}'.format( - cloud_config.project, LOCATION, KEYRING, CRYPTOKEY) + PROJECT, LOCATION, KEYRING, CRYPTOKEY) cryptokeys = kms_client.projects().locations().keyRings().cryptoKeys() policy_request = cryptokeys.getIamPolicy(resource=parent) policy_response = policy_request.execute() @@ -139,8 +141,8 @@ def test_add_member_to_cryptokey_policy(capsys, cloud_config): assert found_member_role_pair -def test_get_keyring_policy(capsys, cloud_config): - project_id = cloud_config.project +def test_get_keyring_policy(capsys): + project_id = PROJECT snippets.get_keyring_policy(project_id, LOCATION, KEYRING) out, _ = capsys.readouterr() expected_roles_exist = ( From 5b298d51566a9c56dc42c9c39e94dc0754d779df Mon Sep 17 00:00:00 2001 From: Jon Wayne Parrott Date: Thu, 27 Apr 2017 09:54:41 -0700 Subject: [PATCH 007/136] Re-generate all readmes --- kms/snippets/README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kms/snippets/README.rst b/kms/snippets/README.rst index 4c660232385b..74dc229fe3fd 100644 --- a/kms/snippets/README.rst +++ b/kms/snippets/README.rst @@ -26,7 +26,7 @@ authentication: .. code-block:: bash - gcloud beta auth application-default login + gcloud auth application-default login #. When running on App Engine or Compute Engine, credentials are already From 480435a0318351fb8cbd8325d220d5c2f2619d32 Mon Sep 17 00:00:00 2001 From: Russ Amos Date: Wed, 16 Aug 2017 13:08:28 -0400 Subject: [PATCH 008/136] KMS: Clean up base64 logic in the encrypt and decrypt functions. [(#1074)](https://github.com/GoogleCloudPlatform/python-docs-samples/issues/1074) The use of base64 is essentially an implementation detail of the Cloud KMS REST API: it is required only so that arbitrary binary data can be included in a JSON string, which only allows Unicode characters. Therefore, the "encrypt" sample function should decode the base64-encoded ciphertext before writing the file. Similarly, "decrypt" should not assume that an input file is base64-encoded, but should perform the base64-encoding itself before sending the encrypted data to KMS. This aligns with how the "gcloud kms encrypt" and "gcloud kms decrypt" commands behave. See https://stackoverflow.com/q/45699472 for an example of user confusion caused by the mismatch. --- kms/snippets/snippets.py | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/kms/snippets/snippets.py b/kms/snippets/snippets.py index 8196c5840f03..9400ffdf066a 100644 --- a/kms/snippets/snippets.py +++ b/kms/snippets/snippets.py @@ -77,17 +77,18 @@ def encrypt(project_id, location, keyring, cryptokey, plaintext_file_name, # Read text from the input file. with io.open(plaintext_file_name, 'rb') as plaintext_file: plaintext = plaintext_file.read() - encoded_text = base64.b64encode(plaintext) # Use the KMS API to encrypt the text. cryptokeys = kms_client.projects().locations().keyRings().cryptoKeys() request = cryptokeys.encrypt( - name=name, body={'plaintext': encoded_text.decode('utf-8')}) + name=name, + body={'plaintext': base64.b64encode(plaintext).decode('ascii')}) response = request.execute() + ciphertext = base64.b64decode(response['ciphertext'].encode('ascii')) # Write the encrypted text to a file. with io.open(encrypted_file_name, 'wb') as encrypted_file: - encrypted_file.write(response['ciphertext'].encode('utf-8')) + encrypted_file.write(ciphertext) print('Saved encrypted text to {}.'.format(encrypted_file_name)) # [END kms_encrypt] @@ -109,19 +110,19 @@ def decrypt(project_id, location, keyring, cryptokey, encrypted_file_name, # Read cipher text from the input file. with io.open(encrypted_file_name, 'rb') as encrypted_file: - cipher_text = encrypted_file.read() + ciphertext = encrypted_file.read() # Use the KMS API to decrypt the text. cryptokeys = kms_client.projects().locations().keyRings().cryptoKeys() request = cryptokeys.decrypt( - name=name, body={'ciphertext': cipher_text.decode('utf-8')}) + name=name, + body={'ciphertext': base64.b64encode(ciphertext).decode('ascii')}) response = request.execute() + plaintext = base64.b64decode(response['plaintext'].encode('ascii')) # Write the plain text to a file. with io.open(decrypted_file_name, 'wb') as decrypted_file: - plaintext_encoded = response['plaintext'] - plaintext_decoded = base64.b64decode(plaintext_encoded) - decrypted_file.write(plaintext_decoded) + decrypted_file.write(plaintext) print('Saved decrypted text to {}.'.format(decrypted_file_name)) # [END kms_decrypt] From adefefe065cd4a630974db0604e43b1fcc088003 Mon Sep 17 00:00:00 2001 From: Russ Amos Date: Thu, 17 Aug 2017 12:10:28 -0400 Subject: [PATCH 009/136] KMS: Make the samples consistent with the other languages. [(#1075)](https://github.com/GoogleCloudPlatform/python-docs-samples/issues/1075) In particular, this change: - changes to use a consistent "_id" suffix for resource name components - uses "data" instead of "text", since encryption is not restricted to text - substitutes "ciphertext" for "encrypted {text, data}" - spells "crypto key" and "key ring" each as two separate words, as in the API Tracking bug: http://b/64758639 --- kms/snippets/README.rst | 4 +- kms/snippets/snippets.py | 270 +++++++++++++++++----------------- kms/snippets/snippets_test.py | 65 ++++---- 3 files changed, 170 insertions(+), 169 deletions(-) diff --git a/kms/snippets/README.rst b/kms/snippets/README.rst index 74dc229fe3fd..d1b495e833e5 100644 --- a/kms/snippets/README.rst +++ b/kms/snippets/README.rst @@ -94,11 +94,11 @@ To run this sample: $ python snippets.py usage: snippets.py [-h] - {create_keyring,create_cryptokey,encrypt,decrypt,disable_cryptokey_version,destroy_cryptokey_version,add_member_to_cryptokey_policy,get_keyring_policy} + {create_key_ring,create_crypto_key,encrypt,decrypt,disable_crypto_key_version,destroy_crypto_key_version,add_member_to_crypto_key_policy,get_key_ring_policy} ... positional arguments: - {create_keyring,create_cryptokey,encrypt,decrypt,disable_cryptokey_version,destroy_cryptokey_version,add_member_to_cryptokey_policy,get_keyring_policy} + {create_key_ring,create_crypto_key,encrypt,decrypt,disable_crypto_key_version,destroy_crypto_key_version,add_member_to_crypto_key_policy,get_key_ring_policy} optional arguments: -h, --help show this help message and exit diff --git a/kms/snippets/snippets.py b/kms/snippets/snippets.py index 9400ffdf066a..4f8ed56f0f69 100644 --- a/kms/snippets/snippets.py +++ b/kms/snippets/snippets.py @@ -21,18 +21,18 @@ # [START kms_create_keyring] -def create_keyring(project_id, location, keyring): +def create_key_ring(project_id, location_id, key_ring_id): """Creates a KeyRing in the given location (e.g. global).""" # Creates an API client for the KMS API. kms_client = googleapiclient.discovery.build('cloudkms', 'v1') # The resource name of the location associated with the KeyRing. - parent = 'projects/{}/locations/{}'.format(project_id, location) + parent = 'projects/{}/locations/{}'.format(project_id, location_id) # Create KeyRing request = kms_client.projects().locations().keyRings().create( - parent=parent, body={}, keyRingId=keyring) + parent=parent, body={}, keyRingId=key_ring_id) response = request.execute() print('Created KeyRing {}.'.format(response['name'])) @@ -40,7 +40,7 @@ def create_keyring(project_id, location, keyring): # [START kms_create_cryptokey] -def create_cryptokey(project_id, location, keyring, cryptokey): +def create_crypto_key(project_id, location_id, key_ring_id, crypto_key_id): """Creates a CryptoKey within a KeyRing in the given location.""" # Creates an API client for the KMS API. @@ -48,12 +48,12 @@ def create_cryptokey(project_id, location, keyring, cryptokey): # The resource name of the KeyRing associated with the CryptoKey. parent = 'projects/{}/locations/{}/keyRings/{}'.format( - project_id, location, keyring) + project_id, location_id, key_ring_id) # Create a CryptoKey for the given KeyRing. request = kms_client.projects().locations().keyRings().cryptoKeys().create( parent=parent, body={'purpose': 'ENCRYPT_DECRYPT'}, - cryptoKeyId=cryptokey) + cryptoKeyId=crypto_key_id) response = request.execute() print('Created CryptoKey {}.'.format(response['name'])) @@ -61,76 +61,76 @@ def create_cryptokey(project_id, location, keyring, cryptokey): # [START kms_encrypt] -def encrypt(project_id, location, keyring, cryptokey, plaintext_file_name, - encrypted_file_name): - """Encrypts data from a plaintext_file_name using the provided CryptoKey - and saves it to an encrypted_file_name so it can only be recovered with a - call to decrypt.""" +def encrypt(project_id, location_id, key_ring_id, crypto_key_id, + plaintext_file_name, ciphertext_file_name): + """Encrypts data from plaintext_file_name using the provided CryptoKey and + saves it to ciphertext_file_name so it can only be recovered with a call to + decrypt. + """ # Creates an API client for the KMS API. kms_client = googleapiclient.discovery.build('cloudkms', 'v1') # The resource name of the CryptoKey. name = 'projects/{}/locations/{}/keyRings/{}/cryptoKeys/{}'.format( - project_id, location, keyring, cryptokey) + project_id, location_id, key_ring_id, crypto_key_id) - # Read text from the input file. + # Read data from the input file. with io.open(plaintext_file_name, 'rb') as plaintext_file: plaintext = plaintext_file.read() - # Use the KMS API to encrypt the text. - cryptokeys = kms_client.projects().locations().keyRings().cryptoKeys() - request = cryptokeys.encrypt( + # Use the KMS API to encrypt the data. + crypto_keys = kms_client.projects().locations().keyRings().cryptoKeys() + request = crypto_keys.encrypt( name=name, body={'plaintext': base64.b64encode(plaintext).decode('ascii')}) response = request.execute() ciphertext = base64.b64decode(response['ciphertext'].encode('ascii')) - # Write the encrypted text to a file. - with io.open(encrypted_file_name, 'wb') as encrypted_file: - encrypted_file.write(ciphertext) + # Write the encrypted data to a file. + with io.open(ciphertext_file_name, 'wb') as ciphertext_file: + ciphertext_file.write(ciphertext) - print('Saved encrypted text to {}.'.format(encrypted_file_name)) + print('Saved ciphertext to {}.'.format(ciphertext_file_name)) # [END kms_encrypt] # [START kms_decrypt] -def decrypt(project_id, location, keyring, cryptokey, encrypted_file_name, - decrypted_file_name): - """Decrypts data from encrypted_file_name that was previously encrypted - using the CryptoKey with a call to encrypt. Outputs decrypted data to - decrpyted_file_name.""" +def decrypt(project_id, location_id, key_ring_id, crypto_key_id, + ciphertext_file_name, plaintext_file_name): + """Decrypts data from ciphertext_file_name that was previously encrypted + using the provided CryptoKey and saves it to plaintext_file_name.""" # Creates an API client for the KMS API. kms_client = googleapiclient.discovery.build('cloudkms', 'v1') # The resource name of the CryptoKey. name = 'projects/{}/locations/{}/keyRings/{}/cryptoKeys/{}'.format( - project_id, location, keyring, cryptokey) + project_id, location_id, key_ring_id, crypto_key_id) - # Read cipher text from the input file. - with io.open(encrypted_file_name, 'rb') as encrypted_file: - ciphertext = encrypted_file.read() + # Read encrypted data from the input file. + with io.open(ciphertext_file_name, 'rb') as ciphertext_file: + ciphertext = ciphertext_file.read() - # Use the KMS API to decrypt the text. - cryptokeys = kms_client.projects().locations().keyRings().cryptoKeys() - request = cryptokeys.decrypt( + # Use the KMS API to decrypt the data. + crypto_keys = kms_client.projects().locations().keyRings().cryptoKeys() + request = crypto_keys.decrypt( name=name, body={'ciphertext': base64.b64encode(ciphertext).decode('ascii')}) response = request.execute() plaintext = base64.b64decode(response['plaintext'].encode('ascii')) - # Write the plain text to a file. - with io.open(decrypted_file_name, 'wb') as decrypted_file: - decrypted_file.write(plaintext) + # Write the decrypted data to a file. + with io.open(plaintext_file_name, 'wb') as plaintext_file: + plaintext_file.write(plaintext) - print('Saved decrypted text to {}.'.format(decrypted_file_name)) + print('Saved plaintext to {}.'.format(plaintext_file_name)) # [END kms_decrypt] # [START kms_disable_cryptokey_version] -def disable_cryptokey_version(project_id, location, keyring, cryptokey, - version): +def disable_crypto_key_version(project_id, location_id, key_ring_id, + crypto_key_id, version_id): """Disables a CryptoKeyVersion associated with a given CryptoKey and KeyRing.""" @@ -141,11 +141,12 @@ def disable_cryptokey_version(project_id, location, keyring, cryptokey, name = ( 'projects/{}/locations/{}/keyRings/{}/cryptoKeys/{}/' 'cryptoKeyVersions/{}' - .format(project_id, location, keyring, cryptokey, version)) + .format( + project_id, location_id, key_ring_id, crypto_key_id, version_id)) # Use the KMS API to disable the CryptoKeyVersion. - cryptokeys = kms_client.projects().locations().keyRings().cryptoKeys() - request = cryptokeys.cryptoKeyVersions().patch( + crypto_keys = kms_client.projects().locations().keyRings().cryptoKeys() + request = crypto_keys.cryptoKeyVersions().patch( name=name, body={'state': 'DISABLED'}, updateMask='state') response = request.execute() @@ -155,8 +156,8 @@ def disable_cryptokey_version(project_id, location, keyring, cryptokey, # [START kms_destroy_cryptokey_version] -def destroy_cryptokey_version( - project_id, location, keyring, cryptokey, version): +def destroy_crypto_key_version( + project_id, location_id, key_ring_id, crypto_key_id, version_id): """Schedules a CryptoKeyVersion associated with a given CryptoKey and KeyRing for destruction 24 hours in the future.""" @@ -167,11 +168,12 @@ def destroy_cryptokey_version( name = ( 'projects/{}/locations/{}/keyRings/{}/cryptoKeys/{}/' 'cryptoKeyVersions/{}' - .format(project_id, location, keyring, cryptokey, version)) + .format( + project_id, location_id, key_ring_id, crypto_key_id, version_id)) # Use the KMS API to schedule the CryptoKeyVersion for destruction. - cryptokeys = kms_client.projects().locations().keyRings().cryptoKeys() - request = cryptokeys.cryptoKeyVersions().destroy(name=name, body={}) + crypto_keys = kms_client.projects().locations().keyRings().cryptoKeys() + request = crypto_keys.cryptoKeyVersions().destroy(name=name, body={}) response = request.execute() print('CryptoKeyVersion {}\'s state has been set to {}.'.format( @@ -180,8 +182,8 @@ def destroy_cryptokey_version( # [START kms_add_member_to_cryptokey_policy] -def add_member_to_cryptokey_policy( - project_id, location, keyring, cryptokey, member, role): +def add_member_to_crypto_key_policy( + project_id, location_id, key_ring_id, crypto_key_id, member, role): """Adds a member with a given role to the Identity and Access Management (IAM) policy for a given CryptoKey associated with a KeyRing.""" @@ -190,11 +192,11 @@ def add_member_to_cryptokey_policy( # The resource name of the CryptoKey. parent = 'projects/{}/locations/{}/keyRings/{}/cryptoKeys/{}'.format( - project_id, location, keyring, cryptokey) + project_id, location_id, key_ring_id, crypto_key_id) # Get the current IAM policy and add the new member to it. - cryptokeys = kms_client.projects().locations().keyRings().cryptoKeys() - policy_request = cryptokeys.getIamPolicy(resource=parent) + crypto_keys = kms_client.projects().locations().keyRings().cryptoKeys() + policy_request = crypto_keys.getIamPolicy(resource=parent) policy_response = policy_request.execute() bindings = [] if 'bindings' in policy_response.keys(): @@ -208,20 +210,20 @@ def add_member_to_cryptokey_policy( policy_response['bindings'] = bindings # Set the new IAM Policy. - cryptokeys = kms_client.projects().locations().keyRings().cryptoKeys() - request = cryptokeys.setIamPolicy( + crypto_keys = kms_client.projects().locations().keyRings().cryptoKeys() + request = crypto_keys.setIamPolicy( resource=parent, body={'policy': policy_response}) request.execute() print_msg = ( 'Member {} added with role {} to policy for CryptoKey {} in KeyRing {}' - .format(member, role, cryptokey, keyring)) + .format(member, role, crypto_key_id, key_ring_id)) print(print_msg) # [END kms_add_member_to_cryptokey_policy] # [START kms_get_keyring_policy] -def get_keyring_policy(project_id, location, keyring): +def get_key_ring_policy(project_id, location_id, key_ring_id): """Gets the Identity and Access Management (IAM) policy for a given KeyRing and prints out roles and the members assigned to those roles.""" @@ -230,7 +232,7 @@ def get_keyring_policy(project_id, location, keyring): # The resource name of the KeyRing. parent = 'projects/{}/locations/{}/keyRings/{}'.format( - project_id, location, keyring) + project_id, location_id, key_ring_id) # Get the current IAM policy. request = kms_client.projects().locations().keyRings().getIamPolicy( @@ -257,116 +259,116 @@ def get_keyring_policy(project_id, location, keyring): formatter_class=argparse.RawDescriptionHelpFormatter) subparsers = parser.add_subparsers(dest='command') - create_keyring_parser = subparsers.add_parser('create_keyring') - create_keyring_parser.add_argument('project_id') - create_keyring_parser.add_argument('location') - create_keyring_parser.add_argument('keyring') + create_key_ring_parser = subparsers.add_parser('create_key_ring') + create_key_ring_parser.add_argument('project') + create_key_ring_parser.add_argument('location') + create_key_ring_parser.add_argument('key_ring') - create_cryptokey_parser = subparsers.add_parser('create_cryptokey') - create_cryptokey_parser.add_argument('project_id') - create_cryptokey_parser.add_argument('location') - create_cryptokey_parser.add_argument('keyring') - create_cryptokey_parser.add_argument('cryptokey') + create_crypto_key_parser = subparsers.add_parser('create_crypto_key') + create_crypto_key_parser.add_argument('project') + create_crypto_key_parser.add_argument('location') + create_crypto_key_parser.add_argument('key_ring') + create_crypto_key_parser.add_argument('crypto_key') encrypt_parser = subparsers.add_parser('encrypt') - encrypt_parser.add_argument('project_id') + encrypt_parser.add_argument('project') encrypt_parser.add_argument('location') - encrypt_parser.add_argument('keyring') - encrypt_parser.add_argument('cryptokey') + encrypt_parser.add_argument('key_ring') + encrypt_parser.add_argument('crypto_key') encrypt_parser.add_argument('infile') encrypt_parser.add_argument('outfile') decrypt_parser = subparsers.add_parser('decrypt') - decrypt_parser.add_argument('project_id') + decrypt_parser.add_argument('project') decrypt_parser.add_argument('location') - decrypt_parser.add_argument('keyring') - decrypt_parser.add_argument('cryptokey') + decrypt_parser.add_argument('key_ring') + decrypt_parser.add_argument('crypto_key') decrypt_parser.add_argument('infile') decrypt_parser.add_argument('outfile') - disable_cryptokey_version_parser = subparsers.add_parser( - 'disable_cryptokey_version') - disable_cryptokey_version_parser.add_argument('project_id') - disable_cryptokey_version_parser.add_argument('location') - disable_cryptokey_version_parser.add_argument('keyring') - disable_cryptokey_version_parser.add_argument('cryptokey') - disable_cryptokey_version_parser.add_argument('version') - - destroy_cryptokey_version_parser = subparsers.add_parser( - 'destroy_cryptokey_version') - destroy_cryptokey_version_parser.add_argument('project_id') - destroy_cryptokey_version_parser.add_argument('location') - destroy_cryptokey_version_parser.add_argument('keyring') - destroy_cryptokey_version_parser.add_argument('cryptokey') - destroy_cryptokey_version_parser.add_argument('version') - - add_member_to_cryptokey_policy_parser = subparsers.add_parser( - 'add_member_to_cryptokey_policy') - add_member_to_cryptokey_policy_parser.add_argument('project_id') - add_member_to_cryptokey_policy_parser.add_argument('location') - add_member_to_cryptokey_policy_parser.add_argument('keyring') - add_member_to_cryptokey_policy_parser.add_argument('cryptokey') - add_member_to_cryptokey_policy_parser.add_argument('member') - add_member_to_cryptokey_policy_parser.add_argument('role') - - get_keyring_policy_parser = subparsers.add_parser('get_keyring_policy') - get_keyring_policy_parser.add_argument('project_id') - get_keyring_policy_parser.add_argument('location') - get_keyring_policy_parser.add_argument('keyring') + disable_crypto_key_version_parser = subparsers.add_parser( + 'disable_crypto_key_version') + disable_crypto_key_version_parser.add_argument('project') + disable_crypto_key_version_parser.add_argument('location') + disable_crypto_key_version_parser.add_argument('key_ring') + disable_crypto_key_version_parser.add_argument('crypto_key') + disable_crypto_key_version_parser.add_argument('version') + + destroy_crypto_key_version_parser = subparsers.add_parser( + 'destroy_crypto_key_version') + destroy_crypto_key_version_parser.add_argument('project') + destroy_crypto_key_version_parser.add_argument('location') + destroy_crypto_key_version_parser.add_argument('key_ring') + destroy_crypto_key_version_parser.add_argument('crypto_key') + destroy_crypto_key_version_parser.add_argument('version') + + add_member_to_crypto_key_policy_parser = subparsers.add_parser( + 'add_member_to_crypto_key_policy') + add_member_to_crypto_key_policy_parser.add_argument('project') + add_member_to_crypto_key_policy_parser.add_argument('location') + add_member_to_crypto_key_policy_parser.add_argument('key_ring') + add_member_to_crypto_key_policy_parser.add_argument('crypto_key') + add_member_to_crypto_key_policy_parser.add_argument('member') + add_member_to_crypto_key_policy_parser.add_argument('role') + + get_key_ring_policy_parser = subparsers.add_parser('get_key_ring_policy') + get_key_ring_policy_parser.add_argument('project') + get_key_ring_policy_parser.add_argument('location') + get_key_ring_policy_parser.add_argument('key_ring') args = parser.parse_args() - if args.command == 'create_keyring': - create_keyring( - args.project_id, + if args.command == 'create_key_ring': + create_key_ring( + args.project, args.location, - args.keyring) - elif args.command == 'create_cryptokey': - create_cryptokey( - args.project_id, + args.key_ring) + elif args.command == 'create_crypto_key': + create_crypto_key( + args.project, args.location, - args.keyring, - args.cryptokey) + args.key_ring, + args.crypto_key) elif args.command == 'encrypt': encrypt( - args.project_id, + args.project, args.location, - args.keyring, - args.cryptokey, + args.key_ring, + args.crypto_key, args.infile, args.outfile) elif args.command == 'decrypt': decrypt( - args.project_id, + args.project, args.location, - args.keyring, - args.cryptokey, + args.key_ring, + args.crypto_key, args.infile, args.outfile) - elif args.command == 'disable_cryptokey_version': - disable_cryptokey_version( - args.project_id, + elif args.command == 'disable_crypto_key_version': + disable_crypto_key_version( + args.project, args.location, - args.keyring, - args.cryptokey, + args.key_ring, + args.crypto_key, args.version) - elif args.command == 'destroy_cryptokey_version': - destroy_cryptokey_version( - args.project_id, + elif args.command == 'destroy_crypto_key_version': + destroy_crypto_key_version( + args.project, args.location, - args.keyring, - args.cryptokey, + args.key_ring, + args.crypto_key, args.version) - elif args.command == 'add_member_to_cryptokey_policy': - add_member_to_cryptokey_policy( - args.project_id, + elif args.command == 'add_member_to_crypto_key_policy': + add_member_to_crypto_key_policy( + args.project, args.location, - args.keyring, - args.cryptokey, + args.key_ring, + args.crypto_key, args.member, args.role) - elif args.command == 'get_keyring_policy': - get_keyring_policy( - args.project_id, + elif args.command == 'get_key_ring_policy': + get_key_ring_policy( + args.project, args.location, - args.keyring) + args.key_ring) diff --git a/kms/snippets/snippets_test.py b/kms/snippets/snippets_test.py index b3c4800d3360..1cfd7f219a8e 100644 --- a/kms/snippets/snippets_test.py +++ b/kms/snippets/snippets_test.py @@ -27,11 +27,11 @@ LOCATION = 'global' # Your Google Cloud Platform KeyRing name -KEYRING = ''.join( +KEY_RING = ''.join( random.choice(string.ascii_lowercase + string.digits) for _ in range(12)) # Your Google Cloud Platform CryptoKey name -CRYPTOKEY = ''.join( +CRYPTO_KEY = ''.join( random.choice(string.ascii_lowercase + string.digits) for _ in range(12)) # Your Google Cloud Platform CryptoKeyVersion name @@ -44,21 +44,21 @@ ROLE = 'roles/owner' -def test_create_keyring(capsys): - snippets.create_keyring(PROJECT, LOCATION, KEYRING) +def test_create_key_ring(capsys): + snippets.create_key_ring(PROJECT, LOCATION, KEY_RING) out, _ = capsys.readouterr() expected = 'Created KeyRing projects/{}/locations/{}/keyRings/{}.'.format( - PROJECT, LOCATION, KEYRING) + PROJECT, LOCATION, KEY_RING) assert expected in out -def test_create_cryptokey(capsys): - snippets.create_cryptokey( - PROJECT, LOCATION, KEYRING, CRYPTOKEY) +def test_create_crypto_key(capsys): + snippets.create_crypto_key( + PROJECT, LOCATION, KEY_RING, CRYPTO_KEY) out, _ = capsys.readouterr() expected = ( 'Created CryptoKey projects/{}/locations/{}/keyRings/{}/cryptoKeys/{}.' - .format(PROJECT, LOCATION, KEYRING, CRYPTOKEY)) + .format(PROJECT, LOCATION, KEY_RING, CRYPTO_KEY)) assert expected in out @@ -73,10 +73,10 @@ def test_encrypt_decrypt(capsys, tmpdir): # Encrypt text and then decrypt it. snippets.encrypt( - PROJECT, LOCATION, KEYRING, CRYPTOKEY, + PROJECT, LOCATION, KEY_RING, CRYPTO_KEY, str(plaintext_file), str(encrypted_file)) snippets.decrypt( - PROJECT, LOCATION, KEYRING, CRYPTOKEY, + PROJECT, LOCATION, KEY_RING, CRYPTO_KEY, str(encrypted_file), str(decrypted_file)) # Make sure the decrypted text matches the original text. @@ -85,50 +85,50 @@ def test_encrypt_decrypt(capsys, tmpdir): # Make sure other output is as expected. out, _ = capsys.readouterr() - assert 'Saved encrypted text to {}.'.format(str(encrypted_file)) in out - assert 'Saved decrypted text to {}.'.format(str(decrypted_file)) in out + assert 'Saved ciphertext to {}.'.format(str(encrypted_file)) in out + assert 'Saved plaintext to {}.'.format(str(decrypted_file)) in out -def test_disable_cryptokey_version(capsys): - snippets.disable_cryptokey_version( - PROJECT, LOCATION, KEYRING, CRYPTOKEY, VERSION) +def test_disable_crypto_key_version(capsys): + snippets.disable_crypto_key_version( + PROJECT, LOCATION, KEY_RING, CRYPTO_KEY, VERSION) out, _ = capsys.readouterr() expected = ( 'CryptoKeyVersion projects/{}/locations/{}/keyRings/{}/cryptoKeys/{}/' 'cryptoKeyVersions/{}\'s state has been set to {}.' .format( - PROJECT, LOCATION, KEYRING, CRYPTOKEY, VERSION, + PROJECT, LOCATION, KEY_RING, CRYPTO_KEY, VERSION, 'DISABLED')) assert expected in out -def test_destroy_cryptokey_version(capsys): - snippets.destroy_cryptokey_version( - PROJECT, LOCATION, KEYRING, CRYPTOKEY, VERSION) +def test_destroy_crypto_key_version(capsys): + snippets.destroy_crypto_key_version( + PROJECT, LOCATION, KEY_RING, CRYPTO_KEY, VERSION) out, _ = capsys.readouterr() expected = ( 'CryptoKeyVersion projects/{}/locations/{}/keyRings/{}/cryptoKeys/{}/' 'cryptoKeyVersions/{}\'s state has been set to {}.' .format( - PROJECT, LOCATION, KEYRING, CRYPTOKEY, VERSION, + PROJECT, LOCATION, KEY_RING, CRYPTO_KEY, VERSION, 'DESTROY_SCHEDULED')) assert expected in out -def test_add_member_to_cryptokey_policy(capsys): - snippets.add_member_to_cryptokey_policy( - PROJECT, LOCATION, KEYRING, CRYPTOKEY, MEMBER, ROLE) +def test_add_member_to_crypto_key_policy(capsys): + snippets.add_member_to_crypto_key_policy( + PROJECT, LOCATION, KEY_RING, CRYPTO_KEY, MEMBER, ROLE) out, _ = capsys.readouterr() expected = ( 'Member {} added with role {} to policy for CryptoKey {} in KeyRing {}' - .format(MEMBER, ROLE, CRYPTOKEY, KEYRING)) + .format(MEMBER, ROLE, CRYPTO_KEY, KEY_RING)) assert expected in out kms_client = googleapiclient.discovery.build('cloudkms', 'v1') parent = 'projects/{}/locations/{}/keyRings/{}/cryptoKeys/{}'.format( - PROJECT, LOCATION, KEYRING, CRYPTOKEY) - cryptokeys = kms_client.projects().locations().keyRings().cryptoKeys() - policy_request = cryptokeys.getIamPolicy(resource=parent) + PROJECT, LOCATION, KEY_RING, CRYPTO_KEY) + crypto_keys = kms_client.projects().locations().keyRings().cryptoKeys() + policy_request = crypto_keys.getIamPolicy(resource=parent) policy_response = policy_request.execute() assert 'bindings' in policy_response.keys() bindings = policy_response['bindings'] @@ -141,14 +141,13 @@ def test_add_member_to_cryptokey_policy(capsys): assert found_member_role_pair -def test_get_keyring_policy(capsys): - project_id = PROJECT - snippets.get_keyring_policy(project_id, LOCATION, KEYRING) +def test_get_key_ring_policy(capsys): + snippets.get_key_ring_policy(PROJECT, LOCATION, KEY_RING) out, _ = capsys.readouterr() expected_roles_exist = ( 'Printing IAM policy for resource projects/{}/locations/{}/keyRings/{}' - ':'.format(project_id, LOCATION, KEYRING)) + ':'.format(PROJECT, LOCATION, KEY_RING)) expected_no_roles = ( 'No roles found for resource projects/{}/locations/{}/keyRings/{}.' - .format(project_id, LOCATION, KEYRING)) + .format(PROJECT, LOCATION, KEY_RING)) assert (expected_roles_exist in out) or (expected_no_roles in out) From b97884fc69bd827dba7312bc66880606daaa761b Mon Sep 17 00:00:00 2001 From: DPE bot Date: Wed, 30 Aug 2017 10:15:58 -0700 Subject: [PATCH 010/136] Auto-update dependencies. [(#1094)](https://github.com/GoogleCloudPlatform/python-docs-samples/issues/1094) * Auto-update dependencies. * Relax assertions in the ocr_nl sample Change-Id: I6d37e5846a8d6dd52429cb30d501f448c52cbba1 * Drop unused logging apiary samples Change-Id: I545718283773cb729a5e0def8a76ebfa40829d51 --- kms/snippets/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kms/snippets/requirements.txt b/kms/snippets/requirements.txt index 4f77d6936d70..28ef89127f4b 100644 --- a/kms/snippets/requirements.txt +++ b/kms/snippets/requirements.txt @@ -1 +1 @@ -google-api-python-client==1.6.2 +google-api-python-client==1.6.3 From 38d062df12554a23f209fa6fa4f3ab5dfa9b0afd Mon Sep 17 00:00:00 2001 From: Jon Wayne Parrott Date: Mon, 18 Sep 2017 11:04:05 -0700 Subject: [PATCH 011/136] Update all generated readme auth instructions [(#1121)](https://github.com/GoogleCloudPlatform/python-docs-samples/issues/1121) Change-Id: I03b5eaef8b17ac3dc3c0339fd2c7447bd3e11bd2 --- kms/snippets/README.rst | 32 +++++--------------------------- 1 file changed, 5 insertions(+), 27 deletions(-) diff --git a/kms/snippets/README.rst b/kms/snippets/README.rst index d1b495e833e5..8e2648523d3d 100644 --- a/kms/snippets/README.rst +++ b/kms/snippets/README.rst @@ -17,34 +17,12 @@ Setup Authentication ++++++++++++++ -Authentication is typically done through `Application Default Credentials`_, -which means you do not have to change the code to authenticate as long as -your environment has credentials. You have a few options for setting up -authentication: +This sample requires you to have authentication setup. Refer to the +`Authentication Getting Started Guide`_ for instructions on setting up +credentials for applications. -#. When running locally, use the `Google Cloud SDK`_ - - .. code-block:: bash - - gcloud auth application-default login - - -#. When running on App Engine or Compute Engine, credentials are already - set-up. However, you may need to configure your Compute Engine instance - with `additional scopes`_. - -#. You can create a `Service Account key file`_. This file can be used to - authenticate to Google Cloud Platform services from any environment. To use - the file, set the ``GOOGLE_APPLICATION_CREDENTIALS`` environment variable to - the path to the key file, for example: - - .. code-block:: bash - - export GOOGLE_APPLICATION_CREDENTIALS=/path/to/service_account.json - -.. _Application Default Credentials: https://cloud.google.com/docs/authentication#getting_credentials_for_server-centric_flow -.. _additional scopes: https://cloud.google.com/compute/docs/authentication#using -.. _Service Account key file: https://developers.google.com/identity/protocols/OAuth2ServiceAccount#creatinganaccount +.. _Authentication Getting Started Guide: + https://cloud.google.com/docs/authentication/getting-started Install Dependencies ++++++++++++++++++++ From 832a6be7f952edd42af3cb45b34b108a1e1e1373 Mon Sep 17 00:00:00 2001 From: DPE bot Date: Thu, 21 Sep 2017 13:40:34 -0700 Subject: [PATCH 012/136] Auto-update dependencies. [(#1133)](https://github.com/GoogleCloudPlatform/python-docs-samples/issues/1133) * Auto-update dependencies. * Fix missing http library Change-Id: I99faa600f2f3f1f50f57694fc9835d7f35bda250 --- kms/snippets/requirements.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/kms/snippets/requirements.txt b/kms/snippets/requirements.txt index 28ef89127f4b..af5ec8147bf1 100644 --- a/kms/snippets/requirements.txt +++ b/kms/snippets/requirements.txt @@ -1 +1,3 @@ -google-api-python-client==1.6.3 +google-api-python-client==1.6.4 +google-auth==1.1.1 +google-auth-httplib2==0.0.2 From d65342d07e4ac545012c1c5c4ff72613903c382c Mon Sep 17 00:00:00 2001 From: michaelawyu Date: Thu, 12 Oct 2017 10:16:11 -0700 Subject: [PATCH 013/136] Added Link to Python Setup Guide [(#1158)](https://github.com/GoogleCloudPlatform/python-docs-samples/issues/1158) * Update Readme.rst to add Python setup guide As requested in b/64770713. This sample is linked in documentation https://cloud.google.com/bigtable/docs/scaling, and it would make more sense to update the guide here than in the documentation. * Update README.rst * Update README.rst * Update README.rst * Update README.rst * Update README.rst * Update install_deps.tmpl.rst * Updated readmegen scripts and re-generated related README files * Fixed the lint error --- kms/snippets/README.rst | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/kms/snippets/README.rst b/kms/snippets/README.rst index 8e2648523d3d..410fa8da1d45 100644 --- a/kms/snippets/README.rst +++ b/kms/snippets/README.rst @@ -27,7 +27,10 @@ credentials for applications. Install Dependencies ++++++++++++++++++++ -#. Install `pip`_ and `virtualenv`_ if you do not already have them. +#. Install `pip`_ and `virtualenv`_ if you do not already have them. You may want to refer to the `Python Development Environment Setup Guide`_ for Google Cloud Platform for instructions. + + .. _Python Development Environment Setup Guide: + https://cloud.google.com/python/setup #. Create a virtualenv. Samples are compatible with Python 2.7 and 3.4+. From 409a57fe7eea5161a373fce3f55b5441994ff800 Mon Sep 17 00:00:00 2001 From: DPE bot Date: Wed, 1 Nov 2017 12:30:10 -0700 Subject: [PATCH 014/136] Auto-update dependencies. [(#1186)](https://github.com/GoogleCloudPlatform/python-docs-samples/issues/1186) --- kms/snippets/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kms/snippets/requirements.txt b/kms/snippets/requirements.txt index af5ec8147bf1..558e42c22ec8 100644 --- a/kms/snippets/requirements.txt +++ b/kms/snippets/requirements.txt @@ -1,3 +1,3 @@ google-api-python-client==1.6.4 -google-auth==1.1.1 +google-auth==1.2.0 google-auth-httplib2==0.0.2 From 6d2a5f9ab7c919bf7e553e5ebe2c2b6a96bb9033 Mon Sep 17 00:00:00 2001 From: Walter Poupore Date: Tue, 7 Nov 2017 15:11:55 -0800 Subject: [PATCH 015/136] Adds snippets for enabling and restoring a key version [(#1196)](https://github.com/GoogleCloudPlatform/python-docs-samples/issues/1196) * Adds snippets for enabling and restoring a key version * Fixed lint issues --- kms/snippets/snippets.py | 82 +++++++++++++++++++++++++++++++++++ kms/snippets/snippets_test.py | 26 +++++++++++ 2 files changed, 108 insertions(+) diff --git a/kms/snippets/snippets.py b/kms/snippets/snippets.py index 4f8ed56f0f69..73e4a65d812b 100644 --- a/kms/snippets/snippets.py +++ b/kms/snippets/snippets.py @@ -155,6 +155,33 @@ def disable_crypto_key_version(project_id, location_id, key_ring_id, # [END kms_disable_cryptokey_version] +# [START kms_enable_cryptokey_version] +def enable_crypto_key_version(project_id, location_id, key_ring_id, + crypto_key_id, version_id): + """Enables a CryptoKeyVersion associated with a given CryptoKey and + KeyRing.""" + + # Creates an API client for the KMS API. + kms_client = googleapiclient.discovery.build('cloudkms', 'v1') + + # Construct the resource name of the CryptoKeyVersion. + name = ( + 'projects/{}/locations/{}/keyRings/{}/cryptoKeys/{}/' + 'cryptoKeyVersions/{}' + .format( + project_id, location_id, key_ring_id, crypto_key_id, version_id)) + + # Use the KMS API to enable the CryptoKeyVersion. + crypto_keys = kms_client.projects().locations().keyRings().cryptoKeys() + request = crypto_keys.cryptoKeyVersions().patch( + name=name, body={'state': 'ENABLED'}, updateMask='state') + response = request.execute() + + print('CryptoKeyVersion {}\'s state has been set to {}.'.format( + name, response['state'])) +# [END kms_enable_cryptokey_version] + + # [START kms_destroy_cryptokey_version] def destroy_crypto_key_version( project_id, location_id, key_ring_id, crypto_key_id, version_id): @@ -181,6 +208,31 @@ def destroy_crypto_key_version( # [END kms_destroy_cryptokey_version] +# [START kms_restore_cryptokey_version] +def restore_crypto_key_version( + project_id, location_id, key_ring_id, crypto_key_id, version_id): + """Restores a CryptoKeyVersion that is scheduled for destruction.""" + + # Creates an API client for the KMS API. + kms_client = googleapiclient.discovery.build('cloudkms', 'v1') + + # Construct the resource name of the CryptoKeyVersion. + name = ( + 'projects/{}/locations/{}/keyRings/{}/cryptoKeys/{}/' + 'cryptoKeyVersions/{}' + .format( + project_id, location_id, key_ring_id, crypto_key_id, version_id)) + + # Use the KMS API to restore the CryptoKeyVersion. + crypto_keys = kms_client.projects().locations().keyRings().cryptoKeys() + request = crypto_keys.cryptoKeyVersions().restore(name=name, body={}) + response = request.execute() + + print('CryptoKeyVersion {}\'s state has been set to {}.'.format( + name, response['state'])) +# [END kms_restore_cryptokey_version] + + # [START kms_add_member_to_cryptokey_policy] def add_member_to_crypto_key_policy( project_id, location_id, key_ring_id, crypto_key_id, member, role): @@ -294,6 +346,14 @@ def get_key_ring_policy(project_id, location_id, key_ring_id): disable_crypto_key_version_parser.add_argument('crypto_key') disable_crypto_key_version_parser.add_argument('version') + enable_crypto_key_version_parser = subparsers.add_parser( + 'enable_crypto_key_version') + enable_crypto_key_version_parser.add_argument('project') + enable_crypto_key_version_parser.add_argument('location') + enable_crypto_key_version_parser.add_argument('key_ring') + enable_crypto_key_version_parser.add_argument('crypto_key') + enable_crypto_key_version_parser.add_argument('version') + destroy_crypto_key_version_parser = subparsers.add_parser( 'destroy_crypto_key_version') destroy_crypto_key_version_parser.add_argument('project') @@ -302,6 +362,14 @@ def get_key_ring_policy(project_id, location_id, key_ring_id): destroy_crypto_key_version_parser.add_argument('crypto_key') destroy_crypto_key_version_parser.add_argument('version') + restore_crypto_key_version_parser = subparsers.add_parser( + 'restore_crypto_key_version') + restore_crypto_key_version_parser.add_argument('project') + restore_crypto_key_version_parser.add_argument('location') + restore_crypto_key_version_parser.add_argument('key_ring') + restore_crypto_key_version_parser.add_argument('crypto_key') + restore_crypto_key_version_parser.add_argument('version') + add_member_to_crypto_key_policy_parser = subparsers.add_parser( 'add_member_to_crypto_key_policy') add_member_to_crypto_key_policy_parser.add_argument('project') @@ -352,6 +420,13 @@ def get_key_ring_policy(project_id, location_id, key_ring_id): args.key_ring, args.crypto_key, args.version) + elif args.command == 'enable_crypto_key_version': + enable_crypto_key_version( + args.project, + args.location, + args.key_ring, + args.crypto_key, + args.version) elif args.command == 'destroy_crypto_key_version': destroy_crypto_key_version( args.project, @@ -359,6 +434,13 @@ def get_key_ring_policy(project_id, location_id, key_ring_id): args.key_ring, args.crypto_key, args.version) + elif args.command == 'restore_crypto_key_version': + restore_crypto_key_version( + args.project, + args.location, + args.key_ring, + args.crypto_key, + args.version) elif args.command == 'add_member_to_crypto_key_policy': add_member_to_crypto_key_policy( args.project, diff --git a/kms/snippets/snippets_test.py b/kms/snippets/snippets_test.py index 1cfd7f219a8e..b36d9644b9ef 100644 --- a/kms/snippets/snippets_test.py +++ b/kms/snippets/snippets_test.py @@ -102,6 +102,19 @@ def test_disable_crypto_key_version(capsys): assert expected in out +def test_enable_crypto_key_version(capsys): + snippets.enable_crypto_key_version( + PROJECT, LOCATION, KEY_RING, CRYPTO_KEY, VERSION) + out, _ = capsys.readouterr() + expected = ( + 'CryptoKeyVersion projects/{}/locations/{}/keyRings/{}/cryptoKeys/{}/' + 'cryptoKeyVersions/{}\'s state has been set to {}.' + .format( + PROJECT, LOCATION, KEY_RING, CRYPTO_KEY, VERSION, + 'ENABLED')) + assert expected in out + + def test_destroy_crypto_key_version(capsys): snippets.destroy_crypto_key_version( PROJECT, LOCATION, KEY_RING, CRYPTO_KEY, VERSION) @@ -115,6 +128,19 @@ def test_destroy_crypto_key_version(capsys): assert expected in out +def test_restore_crypto_key_version(capsys): + snippets.restore_crypto_key_version( + PROJECT, LOCATION, KEY_RING, CRYPTO_KEY, VERSION) + out, _ = capsys.readouterr() + expected = ( + 'CryptoKeyVersion projects/{}/locations/{}/keyRings/{}/cryptoKeys/{}/' + 'cryptoKeyVersions/{}\'s state has been set to {}.' + .format( + PROJECT, LOCATION, KEY_RING, CRYPTO_KEY, VERSION, + 'DISABLED')) + assert expected in out + + def test_add_member_to_crypto_key_policy(capsys): snippets.add_member_to_crypto_key_policy( PROJECT, LOCATION, KEY_RING, CRYPTO_KEY, MEMBER, ROLE) From 38da19436927612c36bccdae9647d84c0e29f6fe Mon Sep 17 00:00:00 2001 From: DPE bot Date: Wed, 15 Nov 2017 12:18:33 -0800 Subject: [PATCH 016/136] Auto-update dependencies. [(#1217)](https://github.com/GoogleCloudPlatform/python-docs-samples/issues/1217) --- kms/snippets/requirements.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kms/snippets/requirements.txt b/kms/snippets/requirements.txt index 558e42c22ec8..edd6472fec65 100644 --- a/kms/snippets/requirements.txt +++ b/kms/snippets/requirements.txt @@ -1,3 +1,3 @@ google-api-python-client==1.6.4 -google-auth==1.2.0 -google-auth-httplib2==0.0.2 +google-auth==1.2.1 +google-auth-httplib2==0.0.3 From 515d306dca934bdfd1db0a91e696a958f34e3b7d Mon Sep 17 00:00:00 2001 From: michaelawyu Date: Thu, 7 Dec 2017 10:34:29 -0800 Subject: [PATCH 017/136] Added "Open in Cloud Shell" buttons to README files [(#1254)](https://github.com/GoogleCloudPlatform/python-docs-samples/issues/1254) --- kms/snippets/README.rst | 21 +++++++++++++++++---- kms/snippets/README.rst.in | 2 ++ 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/kms/snippets/README.rst b/kms/snippets/README.rst index 410fa8da1d45..8fdace9c3e66 100644 --- a/kms/snippets/README.rst +++ b/kms/snippets/README.rst @@ -3,6 +3,10 @@ Google Cloud KMS API Python Samples =============================================================================== +.. image:: https://gstatic.com/cloudssh/images/open-btn.png + :target: https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/GoogleCloudPlatform/python-docs-samples&page=editor&open_in_editor=kms/api-client/README.rst + + This directory contains samples for Google Cloud KMS API. The `Google Cloud KMS API`_ is a service that allows you to keep encryption keys centrally in the cloud, for direct use by cloud services. @@ -54,6 +58,10 @@ Samples Quickstart +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +.. image:: https://gstatic.com/cloudssh/images/open-btn.png + :target: https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/GoogleCloudPlatform/python-docs-samples&page=editor&open_in_editor=kms/api-client/quickstart.py;kms/api-client/README.rst + + To run this sample: @@ -66,6 +74,10 @@ To run this sample: Snippets +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +.. image:: https://gstatic.com/cloudssh/images/open-btn.png + :target: https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/GoogleCloudPlatform/python-docs-samples&page=editor&open_in_editor=kms/api-client/snippets.py;kms/api-client/README.rst + + To run this sample: @@ -75,16 +87,17 @@ To run this sample: $ python snippets.py usage: snippets.py [-h] - {create_key_ring,create_crypto_key,encrypt,decrypt,disable_crypto_key_version,destroy_crypto_key_version,add_member_to_crypto_key_policy,get_key_ring_policy} + {create_key_ring,create_crypto_key,encrypt,decrypt,disable_crypto_key_version,enable_crypto_key_version,destroy_crypto_key_version,restore_crypto_key_version,add_member_to_crypto_key_policy,get_key_ring_policy} ... - + positional arguments: - {create_key_ring,create_crypto_key,encrypt,decrypt,disable_crypto_key_version,destroy_crypto_key_version,add_member_to_crypto_key_policy,get_key_ring_policy} - + {create_key_ring,create_crypto_key,encrypt,decrypt,disable_crypto_key_version,enable_crypto_key_version,destroy_crypto_key_version,restore_crypto_key_version,add_member_to_crypto_key_policy,get_key_ring_policy} + optional arguments: -h, --help show this help message and exit + .. _Google Cloud SDK: https://cloud.google.com/sdk/ \ No newline at end of file diff --git a/kms/snippets/README.rst.in b/kms/snippets/README.rst.in index 9489051c2c63..6299b5a0a535 100644 --- a/kms/snippets/README.rst.in +++ b/kms/snippets/README.rst.in @@ -18,3 +18,5 @@ samples: - name: Snippets file: snippets.py show_help: True + +folder: kms/api-client \ No newline at end of file From a4fe3963756dffd2644ef4a322129b3297d7064a Mon Sep 17 00:00:00 2001 From: DPE bot Date: Wed, 10 Jan 2018 09:07:00 -0800 Subject: [PATCH 018/136] Auto-update dependencies. [(#1309)](https://github.com/GoogleCloudPlatform/python-docs-samples/issues/1309) --- kms/snippets/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kms/snippets/requirements.txt b/kms/snippets/requirements.txt index edd6472fec65..8bb83f801683 100644 --- a/kms/snippets/requirements.txt +++ b/kms/snippets/requirements.txt @@ -1,3 +1,3 @@ google-api-python-client==1.6.4 -google-auth==1.2.1 +google-auth==1.3.0 google-auth-httplib2==0.0.3 From 6db525e21d5d0699496c2c280ba463ce204b1de4 Mon Sep 17 00:00:00 2001 From: DPE bot Date: Thu, 1 Feb 2018 22:20:35 -0800 Subject: [PATCH 019/136] Auto-update dependencies. [(#1320)](https://github.com/GoogleCloudPlatform/python-docs-samples/issues/1320) --- kms/snippets/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kms/snippets/requirements.txt b/kms/snippets/requirements.txt index 8bb83f801683..4bafec3019aa 100644 --- a/kms/snippets/requirements.txt +++ b/kms/snippets/requirements.txt @@ -1,3 +1,3 @@ -google-api-python-client==1.6.4 +google-api-python-client==1.6.5 google-auth==1.3.0 google-auth-httplib2==0.0.3 From 650cc53ac7839780b97cb3ac8b943ee5f8d9783a Mon Sep 17 00:00:00 2001 From: DPE bot Date: Fri, 9 Feb 2018 10:46:48 -0800 Subject: [PATCH 020/136] Auto-update dependencies. [(#1355)](https://github.com/GoogleCloudPlatform/python-docs-samples/issues/1355) --- kms/snippets/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kms/snippets/requirements.txt b/kms/snippets/requirements.txt index 4bafec3019aa..3578404331b4 100644 --- a/kms/snippets/requirements.txt +++ b/kms/snippets/requirements.txt @@ -1,3 +1,3 @@ google-api-python-client==1.6.5 -google-auth==1.3.0 +google-auth==1.4.0 google-auth-httplib2==0.0.3 From 3ad2bc04cf6f59a7fa911f626fac50db747dff5a Mon Sep 17 00:00:00 2001 From: DPE bot Date: Mon, 26 Feb 2018 09:03:37 -0800 Subject: [PATCH 021/136] Auto-update dependencies. [(#1359)](https://github.com/GoogleCloudPlatform/python-docs-samples/issues/1359) --- kms/snippets/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kms/snippets/requirements.txt b/kms/snippets/requirements.txt index 3578404331b4..500e732f5322 100644 --- a/kms/snippets/requirements.txt +++ b/kms/snippets/requirements.txt @@ -1,3 +1,3 @@ google-api-python-client==1.6.5 -google-auth==1.4.0 +google-auth==1.4.1 google-auth-httplib2==0.0.3 From 3161da4e1e932e95389ea7971098b45c769a3afe Mon Sep 17 00:00:00 2001 From: DPE bot Date: Mon, 2 Apr 2018 02:51:10 -0700 Subject: [PATCH 022/136] Auto-update dependencies. --- kms/snippets/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kms/snippets/requirements.txt b/kms/snippets/requirements.txt index 500e732f5322..e5f3a6c5cd6b 100644 --- a/kms/snippets/requirements.txt +++ b/kms/snippets/requirements.txt @@ -1,3 +1,3 @@ -google-api-python-client==1.6.5 +google-api-python-client==1.6.6 google-auth==1.4.1 google-auth-httplib2==0.0.3 From 00bcfc8119aa51a370a174eede4a6ee078cddc08 Mon Sep 17 00:00:00 2001 From: chenyumic Date: Fri, 6 Apr 2018 22:57:36 -0700 Subject: [PATCH 023/136] Regenerate the README files and fix the Open in Cloud Shell link for some samples [(#1441)](https://github.com/GoogleCloudPlatform/python-docs-samples/issues/1441) --- kms/snippets/README.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/kms/snippets/README.rst b/kms/snippets/README.rst index 8fdace9c3e66..9bf0471bde92 100644 --- a/kms/snippets/README.rst +++ b/kms/snippets/README.rst @@ -12,7 +12,7 @@ This directory contains samples for Google Cloud KMS API. The `Google Cloud KMS -.. _Google Cloud KMS API: https://cloud.google.com/kms/docs/ +.. _Google Cloud KMS API: https://cloud.google.com/kms/docs/ Setup ------------------------------------------------------------------------------- @@ -59,7 +59,7 @@ Quickstart +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ .. image:: https://gstatic.com/cloudssh/images/open-btn.png - :target: https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/GoogleCloudPlatform/python-docs-samples&page=editor&open_in_editor=kms/api-client/quickstart.py;kms/api-client/README.rst + :target: https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/GoogleCloudPlatform/python-docs-samples&page=editor&open_in_editor=kms/api-client/quickstart.py,kms/api-client/README.rst @@ -75,7 +75,7 @@ Snippets +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ .. image:: https://gstatic.com/cloudssh/images/open-btn.png - :target: https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/GoogleCloudPlatform/python-docs-samples&page=editor&open_in_editor=kms/api-client/snippets.py;kms/api-client/README.rst + :target: https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/GoogleCloudPlatform/python-docs-samples&page=editor&open_in_editor=kms/api-client/snippets.py,kms/api-client/README.rst From 72fee9859cb6f87d5ebfa820f9bf944c78c98669 Mon Sep 17 00:00:00 2001 From: Frank Natividad Date: Thu, 26 Apr 2018 10:26:41 -0700 Subject: [PATCH 024/136] Update READMEs to fix numbering and add git clone [(#1464)](https://github.com/GoogleCloudPlatform/python-docs-samples/issues/1464) --- kms/snippets/README.rst | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/kms/snippets/README.rst b/kms/snippets/README.rst index 9bf0471bde92..28777c841d84 100644 --- a/kms/snippets/README.rst +++ b/kms/snippets/README.rst @@ -31,10 +31,16 @@ credentials for applications. Install Dependencies ++++++++++++++++++++ +#. Clone python-docs-samples and change directory to the sample directory you want to use. + + .. code-block:: bash + + $ git clone https://github.com/GoogleCloudPlatform/python-docs-samples.git + #. Install `pip`_ and `virtualenv`_ if you do not already have them. You may want to refer to the `Python Development Environment Setup Guide`_ for Google Cloud Platform for instructions. - .. _Python Development Environment Setup Guide: - https://cloud.google.com/python/setup + .. _Python Development Environment Setup Guide: + https://cloud.google.com/python/setup #. Create a virtualenv. Samples are compatible with Python 2.7 and 3.4+. From 8aa3024d03831b8d3df17c77227d1663b5334efe Mon Sep 17 00:00:00 2001 From: Daniel Sanche Date: Fri, 17 Aug 2018 09:44:26 -0700 Subject: [PATCH 025/136] added kms asymmetric samples [(#1638)](https://github.com/GoogleCloudPlatform/python-docs-samples/issues/1638) --- kms/snippets/asymmetric.py | 136 ++++++++++++++++++++++++++++++ kms/snippets/asymmetric_test.py | 141 ++++++++++++++++++++++++++++++++ kms/snippets/requirements.txt | 1 + 3 files changed, 278 insertions(+) create mode 100644 kms/snippets/asymmetric.py create mode 100644 kms/snippets/asymmetric_test.py diff --git a/kms/snippets/asymmetric.py b/kms/snippets/asymmetric.py new file mode 100644 index 000000000000..4127148f49b4 --- /dev/null +++ b/kms/snippets/asymmetric.py @@ -0,0 +1,136 @@ +#!/bin/python +# Copyright 2018 Google Inc. +# +# 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.rom googleapiclient import discovery + +import base64 +import hashlib + +from cryptography.exceptions import InvalidSignature +from cryptography.hazmat.backends import default_backend +from cryptography.hazmat.primitives import hashes, serialization +from cryptography.hazmat.primitives.asymmetric import ec, padding, utils + + +# [START kms_get_asymmetric_public] +def getAsymmetricPublicKey(client, key_path): + """Retrieves the public key from a saved asymmetric key pair on Cloud KMS + """ + request = client.projects() \ + .locations() \ + .keyRings() \ + .cryptoKeys() \ + .cryptoKeyVersions() \ + .getPublicKey(name=key_path) + response = request.execute() + key_txt = response['pem'].encode('ascii') + key = serialization.load_pem_public_key(key_txt, default_backend()) + return key +# [END kms_get_asymmetric_public] + + +# [START kms_decrypt_rsa] +def decryptRSA(ciphertext, client, key_path): + """Decrypt a given ciphertext using an RSA private key stored on Cloud KMS + """ + request = client.projects() \ + .locations() \ + .keyRings() \ + .cryptoKeys() \ + .cryptoKeyVersions() \ + .asymmetricDecrypt(name=key_path, + body={'ciphertext': ciphertext}) + response = request.execute() + plaintext = base64.b64decode(response['plaintext']).decode('utf-8') + return plaintext +# [END kms_decrypt_rsa] + + +# [START kms_encrypt_rsa] +def encryptRSA(message, client, key_path): + """Encrypt message locally using an RSA public key retrieved from Cloud KMS + """ + public_key = getAsymmetricPublicKey(client, key_path) + pad = padding.OAEP(mgf=padding.MGF1(algorithm=hashes.SHA256()), + algorithm=hashes.SHA256(), + label=None) + ciphertext = public_key.encrypt(message.encode('ascii'), pad) + ciphertext = base64.b64encode(ciphertext).decode('utf-8') + return ciphertext +# [END kms_encrypt_rsa] + + +# [START kms_sign_asymmetric] +def signAsymmetric(message, client, key_path): + """Create a signature for a message using a private key stored on Cloud KMS + """ + digest_bytes = hashlib.sha256(message.encode('ascii')).digest() + digest64 = base64.b64encode(digest_bytes) + + digest_JSON = {'sha256': digest64.decode('utf-8')} + request = client.projects() \ + .locations() \ + .keyRings() \ + .cryptoKeys() \ + .cryptoKeyVersions() \ + .asymmetricSign(name=key_path, + body={'digest': digest_JSON}) + response = request.execute() + return response.get('signature', None) +# [END kms_sign_asymmetric] + + +# [START kms_verify_signature_rsa] +def verifySignatureRSA(signature, message, client, key_path): + """Verify the validity of an 'RSA_SIGN_PSS_2048_SHA256' signature + for the specified plaintext message + """ + public_key = getAsymmetricPublicKey(client, key_path) + + digest_bytes = hashlib.sha256(message.encode('ascii')).digest() + sig_bytes = base64.b64decode(signature) + + try: + # Attempt verification + public_key.verify(sig_bytes, + digest_bytes, + padding.PSS(mgf=padding.MGF1(hashes.SHA256()), + salt_length=32), + utils.Prehashed(hashes.SHA256())) + # No errors were thrown. Verification was successful + return True + except InvalidSignature: + return False +# [END kms_verify_signature_rsa] + + +# [START kms_verify_signature_ec] +def verifySignatureEC(signature, message, client, key_path): + """Verify the validity of an 'EC_SIGN_P224_SHA256' signature + for the specified plaintext message + """ + public_key = getAsymmetricPublicKey(client, key_path) + + digest_bytes = hashlib.sha256(message.encode('ascii')).digest() + sig_bytes = base64.b64decode(signature) + + try: + # Attempt verification + public_key.verify(sig_bytes, + digest_bytes, + ec.ECDSA(utils.Prehashed(hashes.SHA256()))) + # No errors were thrown. Verification was successful + return True + except InvalidSignature: + return False +# [END kms_verify_signature_ec] diff --git a/kms/snippets/asymmetric_test.py b/kms/snippets/asymmetric_test.py new file mode 100644 index 000000000000..20119ce590ac --- /dev/null +++ b/kms/snippets/asymmetric_test.py @@ -0,0 +1,141 @@ +#!/bin/python +# Copyright 2018 Google Inc. +# +# 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. + + +from os import environ +from time import sleep + +from cryptography.hazmat.backends.openssl.ec import _EllipticCurvePublicKey +from cryptography.hazmat.backends.openssl.rsa import _RSAPublicKey +from googleapiclient import discovery +from googleapiclient.errors import HttpError +import sample + + +def create_key_helper(key_id, key_path, purpose, algorithm, t): + try: + t.client.projects() \ + .locations() \ + .keyRings() \ + .cryptoKeys() \ + .create(parent='{}/keyRings/{}'.format(t.parent, t.keyring), + body={'purpose': purpose, + 'versionTemplate': { + 'algorithm': algorithm + } + }, + cryptoKeyId=key_id) \ + .execute() + return True + except HttpError: + # key already exists + return False + + +def setup_module(module): + """ + Set up keys in project if needed + """ + t = TestKMSSamples() + try: + # create keyring + t.client.projects() \ + .locations() \ + .keyRings() \ + .create(parent=t.parent, body={}, keyRingId=t.keyring) \ + .execute() + except HttpError: + # keyring already exists + pass + s1 = create_key_helper(t.rsaDecryptId, t.rsaDecrypt, 'ASYMMETRIC_DECRYPT', + 'RSA_DECRYPT_OAEP_2048_SHA256', t) + s2 = create_key_helper(t.rsaSignId, t.rsaSign, 'ASYMMETRIC_SIGN', + 'RSA_SIGN_PSS_2048_SHA256', t) + s3 = create_key_helper(t.ecSignId, t.ecSign, 'ASYMMETRIC_SIGN', + 'EC_SIGN_P224_SHA256', t) + if s1 or s2 or s3: + # leave time for keys to initialize + sleep(20) + + +class TestKMSSamples: + + project_id = environ['GCLOUD_PROJECT'] + keyring = 'kms-asymmetric-samples4' + parent = 'projects/{}/locations/global'.format(project_id) + + rsaSignId = 'rsa-sign' + rsaDecryptId = 'rsa-decrypt' + ecSignId = 'ec-sign' + + rsaSign = '{}/keyRings/{}/cryptoKeys/{}/cryptoKeyVersions/1' \ + .format(parent, keyring, rsaSignId) + rsaDecrypt = '{}/keyRings/{}/cryptoKeys/{}/cryptoKeyVersions/1' \ + .format(parent, keyring, rsaDecryptId) + ecSign = '{}/keyRings/{}/cryptoKeys/{}/cryptoKeyVersions/1' \ + .format(parent, keyring, ecSignId) + + message = 'test message 123' + + client = discovery.build('cloudkms', 'v1') + + def test_get_public_key(self): + rsa_key = sample.getAsymmetricPublicKey(self.client, self.rsaDecrypt) + assert isinstance(rsa_key, _RSAPublicKey), 'expected RSA key' + ec_key = sample.getAsymmetricPublicKey(self.client, self.ecSign) + assert isinstance(ec_key, _EllipticCurvePublicKey), 'expected EC key' + + def test_rsa_encrypt_decrypt(self): + ciphertext = sample.encryptRSA(self.message, + self.client, + self.rsaDecrypt) + # ciphertext should be 344 characters with base64 and RSA 2048 + assert len(ciphertext) == 344, \ + 'ciphertext should be 344 chars; got {}'.format(len(ciphertext)) + assert ciphertext[-2:] == '==', 'cipher text should end with ==' + plaintext = sample.decryptRSA(ciphertext, self.client, self.rsaDecrypt) + assert plaintext == self.message + + def test_rsa_sign_verify(self): + sig = sample.signAsymmetric(self.message, self.client, self.rsaSign) + # ciphertext should be 344 characters with base64 and RSA 2048 + assert len(sig) == 344, \ + 'sig should be 344 chars; got {}'.format(len(sig)) + assert sig[-2:] == '==', 'sig should end with ==' + success = sample.verifySignatureRSA(sig, + self.message, + self.client, + self.rsaSign) + assert success is True, 'RSA verification failed' + success = sample.verifySignatureRSA(sig, + self.message+'.', + self.client, + self.rsaSign) + assert success is False, 'verify should fail with modified message' + + def test_ec_sign_verify(self): + sig = sample.signAsymmetric(self.message, self.client, self.ecSign) + assert len(sig) > 50 and len(sig) < 300, \ + 'sig outside expected length range' + success = sample.verifySignatureEC(sig, + self.message, + self.client, + self.ecSign) + assert success is True, 'EC verification failed' + success = sample.verifySignatureEC(sig, + self.message+'.', + self.client, + self.ecSign) + assert success is False, 'verify should fail with modified message' diff --git a/kms/snippets/requirements.txt b/kms/snippets/requirements.txt index e5f3a6c5cd6b..e18999655f7f 100644 --- a/kms/snippets/requirements.txt +++ b/kms/snippets/requirements.txt @@ -1,3 +1,4 @@ google-api-python-client==1.6.6 google-auth==1.4.1 google-auth-httplib2==0.0.3 +cryptography==2.3.1 From 366fa72dce6d967bfcf5cfa1013dc1d972574d5a Mon Sep 17 00:00:00 2001 From: Daniel Sanche Date: Tue, 21 Aug 2018 18:45:02 -0700 Subject: [PATCH 026/136] kms text fixes [(#1647)](https://github.com/GoogleCloudPlatform/python-docs-samples/issues/1647) --- kms/snippets/asymmetric.py | 24 +++++++++++++++++------- kms/snippets/asymmetric_test.py | 2 +- 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/kms/snippets/asymmetric.py b/kms/snippets/asymmetric.py index 4127148f49b4..4d4ebcb4f3b2 100644 --- a/kms/snippets/asymmetric.py +++ b/kms/snippets/asymmetric.py @@ -24,7 +24,8 @@ # [START kms_get_asymmetric_public] def getAsymmetricPublicKey(client, key_path): - """Retrieves the public key from a saved asymmetric key pair on Cloud KMS + """ + Retrieves the public key from a saved asymmetric key pair on Cloud KMS """ request = client.projects() \ .locations() \ @@ -41,7 +42,9 @@ def getAsymmetricPublicKey(client, key_path): # [START kms_decrypt_rsa] def decryptRSA(ciphertext, client, key_path): - """Decrypt a given ciphertext using an RSA private key stored on Cloud KMS + """ + Decrypt a given ciphertext using an 'RSA_DECRYPT_OAEP_2048_SHA256' private + key stored on Cloud KMS """ request = client.projects() \ .locations() \ @@ -58,7 +61,9 @@ def decryptRSA(ciphertext, client, key_path): # [START kms_encrypt_rsa] def encryptRSA(message, client, key_path): - """Encrypt message locally using an RSA public key retrieved from Cloud KMS + """ + Encrypt message locally using an 'RSA_DECRYPT_OAEP_2048_SHA256' public + key retrieved from Cloud KMS """ public_key = getAsymmetricPublicKey(client, key_path) pad = padding.OAEP(mgf=padding.MGF1(algorithm=hashes.SHA256()), @@ -72,8 +77,11 @@ def encryptRSA(message, client, key_path): # [START kms_sign_asymmetric] def signAsymmetric(message, client, key_path): - """Create a signature for a message using a private key stored on Cloud KMS """ + Create a signature for a message using a private key stored on Cloud KMS + """ + # Note: some key algorithms will require a different hash function + # For example, EC_SIGN_P384_SHA384 requires SHA384 digest_bytes = hashlib.sha256(message.encode('ascii')).digest() digest64 = base64.b64encode(digest_bytes) @@ -92,8 +100,9 @@ def signAsymmetric(message, client, key_path): # [START kms_verify_signature_rsa] def verifySignatureRSA(signature, message, client, key_path): - """Verify the validity of an 'RSA_SIGN_PSS_2048_SHA256' signature - for the specified plaintext message + """ + Verify the validity of an 'RSA_SIGN_PSS_2048_SHA256' signature for the + specified plaintext message """ public_key = getAsymmetricPublicKey(client, key_path) @@ -116,7 +125,8 @@ def verifySignatureRSA(signature, message, client, key_path): # [START kms_verify_signature_ec] def verifySignatureEC(signature, message, client, key_path): - """Verify the validity of an 'EC_SIGN_P224_SHA256' signature + """ + Verify the validity of an 'EC_SIGN_P256_SHA256' signature for the specified plaintext message """ public_key = getAsymmetricPublicKey(client, key_path) diff --git a/kms/snippets/asymmetric_test.py b/kms/snippets/asymmetric_test.py index 20119ce590ac..a4b1c34f9cf1 100644 --- a/kms/snippets/asymmetric_test.py +++ b/kms/snippets/asymmetric_test.py @@ -64,7 +64,7 @@ def setup_module(module): s2 = create_key_helper(t.rsaSignId, t.rsaSign, 'ASYMMETRIC_SIGN', 'RSA_SIGN_PSS_2048_SHA256', t) s3 = create_key_helper(t.ecSignId, t.ecSign, 'ASYMMETRIC_SIGN', - 'EC_SIGN_P224_SHA256', t) + 'EC_SIGN_P256_SHA256', t) if s1 or s2 or s3: # leave time for keys to initialize sleep(20) From 887f48f55f10af59c9ca5f8b9782c08fd18c3b21 Mon Sep 17 00:00:00 2001 From: Daniel Sanche Date: Fri, 7 Sep 2018 08:55:04 -0700 Subject: [PATCH 027/136] KMS test fix [(#1690)](https://github.com/GoogleCloudPlatform/python-docs-samples/issues/1690) --- kms/snippets/asymmetric_test.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/kms/snippets/asymmetric_test.py b/kms/snippets/asymmetric_test.py index a4b1c34f9cf1..5f969be7db68 100644 --- a/kms/snippets/asymmetric_test.py +++ b/kms/snippets/asymmetric_test.py @@ -21,7 +21,8 @@ from cryptography.hazmat.backends.openssl.rsa import _RSAPublicKey from googleapiclient import discovery from googleapiclient.errors import HttpError -import sample + +import asymmetric as sample def create_key_helper(key_id, key_path, purpose, algorithm, t): From 909a24b587dfbf27aaefb4057e889dd781678684 Mon Sep 17 00:00:00 2001 From: Daniel Sanche Date: Fri, 28 Sep 2018 16:34:48 -0700 Subject: [PATCH 028/136] KMS changes [(#1723)](https://github.com/GoogleCloudPlatform/python-docs-samples/issues/1723) use byte parameters instead of strings --- kms/snippets/asymmetric.py | 41 +++++++++++++++------------------ kms/snippets/asymmetric_test.py | 40 +++++++++++++++++++------------- 2 files changed, 43 insertions(+), 38 deletions(-) diff --git a/kms/snippets/asymmetric.py b/kms/snippets/asymmetric.py index 4d4ebcb4f3b2..bc313aaa8494 100644 --- a/kms/snippets/asymmetric.py +++ b/kms/snippets/asymmetric.py @@ -13,6 +13,7 @@ # See the License for the specific language governing permissions and # limitations under the License.rom googleapiclient import discovery +# [START kms_asymmetric_imports] import base64 import hashlib @@ -20,6 +21,7 @@ from cryptography.hazmat.backends import default_backend from cryptography.hazmat.primitives import hashes, serialization from cryptography.hazmat.primitives.asymmetric import ec, padding, utils +# [END kms_asymmetric_imports] # [START kms_get_asymmetric_public] @@ -43,35 +45,34 @@ def getAsymmetricPublicKey(client, key_path): # [START kms_decrypt_rsa] def decryptRSA(ciphertext, client, key_path): """ - Decrypt a given ciphertext using an 'RSA_DECRYPT_OAEP_2048_SHA256' private - key stored on Cloud KMS + Decrypt the input ciphertext (bytes) using an + 'RSA_DECRYPT_OAEP_2048_SHA256' private key stored on Cloud KMS """ + request_body = {'ciphertext': base64.b64encode(ciphertext).decode('utf-8')} request = client.projects() \ .locations() \ .keyRings() \ .cryptoKeys() \ .cryptoKeyVersions() \ .asymmetricDecrypt(name=key_path, - body={'ciphertext': ciphertext}) + body=request_body) response = request.execute() - plaintext = base64.b64decode(response['plaintext']).decode('utf-8') + plaintext = base64.b64decode(response['plaintext']) return plaintext # [END kms_decrypt_rsa] # [START kms_encrypt_rsa] -def encryptRSA(message, client, key_path): +def encryptRSA(plaintext, client, key_path): """ - Encrypt message locally using an 'RSA_DECRYPT_OAEP_2048_SHA256' public - key retrieved from Cloud KMS + Encrypt the input plaintext (bytes) locally using an + 'RSA_DECRYPT_OAEP_2048_SHA256' public key retrieved from Cloud KMS """ public_key = getAsymmetricPublicKey(client, key_path) pad = padding.OAEP(mgf=padding.MGF1(algorithm=hashes.SHA256()), algorithm=hashes.SHA256(), label=None) - ciphertext = public_key.encrypt(message.encode('ascii'), pad) - ciphertext = base64.b64encode(ciphertext).decode('utf-8') - return ciphertext + return public_key.encrypt(plaintext, pad) # [END kms_encrypt_rsa] @@ -82,7 +83,7 @@ def signAsymmetric(message, client, key_path): """ # Note: some key algorithms will require a different hash function # For example, EC_SIGN_P384_SHA384 requires SHA384 - digest_bytes = hashlib.sha256(message.encode('ascii')).digest() + digest_bytes = hashlib.sha256(message).digest() digest64 = base64.b64encode(digest_bytes) digest_JSON = {'sha256': digest64.decode('utf-8')} @@ -94,7 +95,7 @@ def signAsymmetric(message, client, key_path): .asymmetricSign(name=key_path, body={'digest': digest_JSON}) response = request.execute() - return response.get('signature', None) + return base64.b64decode(response.get('signature', None)) # [END kms_sign_asymmetric] @@ -102,16 +103,14 @@ def signAsymmetric(message, client, key_path): def verifySignatureRSA(signature, message, client, key_path): """ Verify the validity of an 'RSA_SIGN_PSS_2048_SHA256' signature for the - specified plaintext message + specified message """ public_key = getAsymmetricPublicKey(client, key_path) - - digest_bytes = hashlib.sha256(message.encode('ascii')).digest() - sig_bytes = base64.b64decode(signature) + digest_bytes = hashlib.sha256(message).digest() try: # Attempt verification - public_key.verify(sig_bytes, + public_key.verify(signature, digest_bytes, padding.PSS(mgf=padding.MGF1(hashes.SHA256()), salt_length=32), @@ -127,16 +126,14 @@ def verifySignatureRSA(signature, message, client, key_path): def verifySignatureEC(signature, message, client, key_path): """ Verify the validity of an 'EC_SIGN_P256_SHA256' signature - for the specified plaintext message + for the specified message """ public_key = getAsymmetricPublicKey(client, key_path) - - digest_bytes = hashlib.sha256(message.encode('ascii')).digest() - sig_bytes = base64.b64decode(signature) + digest_bytes = hashlib.sha256(message).digest() try: # Attempt verification - public_key.verify(sig_bytes, + public_key.verify(signature, digest_bytes, ec.ECDSA(utils.Prehashed(hashes.SHA256()))) # No errors were thrown. Verification was successful diff --git a/kms/snippets/asymmetric_test.py b/kms/snippets/asymmetric_test.py index 5f969be7db68..4ce9b32aed5b 100644 --- a/kms/snippets/asymmetric_test.py +++ b/kms/snippets/asymmetric_test.py @@ -13,7 +13,6 @@ # See the License for the specific language governing permissions and # limitations under the License. - from os import environ from time import sleep @@ -89,6 +88,7 @@ class TestKMSSamples: .format(parent, keyring, ecSignId) message = 'test message 123' + message_bytes = message.encode('utf-8') client = discovery.build('cloudkms', 'v1') @@ -99,44 +99,52 @@ def test_get_public_key(self): assert isinstance(ec_key, _EllipticCurvePublicKey), 'expected EC key' def test_rsa_encrypt_decrypt(self): - ciphertext = sample.encryptRSA(self.message, + ciphertext = sample.encryptRSA(self.message_bytes, self.client, self.rsaDecrypt) - # ciphertext should be 344 characters with base64 and RSA 2048 - assert len(ciphertext) == 344, \ - 'ciphertext should be 344 chars; got {}'.format(len(ciphertext)) - assert ciphertext[-2:] == '==', 'cipher text should end with ==' - plaintext = sample.decryptRSA(ciphertext, self.client, self.rsaDecrypt) + # ciphertext should be 256 characters with base64 and RSA 2048 + assert len(ciphertext) == 256, \ + 'ciphertext should be 256 chars; got {}'.format(len(ciphertext)) + plaintext_bytes = sample.decryptRSA(ciphertext, + self.client, + self.rsaDecrypt) + assert plaintext_bytes == self.message_bytes + plaintext = plaintext_bytes.decode('utf-8') assert plaintext == self.message def test_rsa_sign_verify(self): - sig = sample.signAsymmetric(self.message, self.client, self.rsaSign) + sig = sample.signAsymmetric(self.message_bytes, + self.client, + self.rsaSign) # ciphertext should be 344 characters with base64 and RSA 2048 - assert len(sig) == 344, \ - 'sig should be 344 chars; got {}'.format(len(sig)) - assert sig[-2:] == '==', 'sig should end with ==' + assert len(sig) == 256, \ + 'sig should be 256 chars; got {}'.format(len(sig)) success = sample.verifySignatureRSA(sig, - self.message, + self.message_bytes, self.client, self.rsaSign) assert success is True, 'RSA verification failed' + changed_bytes = self.message_bytes + b'.' success = sample.verifySignatureRSA(sig, - self.message+'.', + changed_bytes, self.client, self.rsaSign) assert success is False, 'verify should fail with modified message' def test_ec_sign_verify(self): - sig = sample.signAsymmetric(self.message, self.client, self.ecSign) + sig = sample.signAsymmetric(self.message_bytes, + self.client, + self.ecSign) assert len(sig) > 50 and len(sig) < 300, \ 'sig outside expected length range' success = sample.verifySignatureEC(sig, - self.message, + self.message_bytes, self.client, self.ecSign) assert success is True, 'EC verification failed' + changed_bytes = self.message_bytes + b'.' success = sample.verifySignatureEC(sig, - self.message+'.', + changed_bytes, self.client, self.ecSign) assert success is False, 'verify should fail with modified message' From ce34f1083a23d08aa9cda9d756856fe7d9834009 Mon Sep 17 00:00:00 2001 From: Daniel Sanche Date: Thu, 25 Oct 2018 10:11:43 -0700 Subject: [PATCH 029/136] KMS import comments [(#1771)](https://github.com/GoogleCloudPlatform/python-docs-samples/issues/1771) added import comments to snippets --- kms/snippets/asymmetric.py | 31 +++++++++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/kms/snippets/asymmetric.py b/kms/snippets/asymmetric.py index bc313aaa8494..7f0d11aa608f 100644 --- a/kms/snippets/asymmetric.py +++ b/kms/snippets/asymmetric.py @@ -13,7 +13,6 @@ # See the License for the specific language governing permissions and # limitations under the License.rom googleapiclient import discovery -# [START kms_asymmetric_imports] import base64 import hashlib @@ -21,13 +20,16 @@ from cryptography.hazmat.backends import default_backend from cryptography.hazmat.primitives import hashes, serialization from cryptography.hazmat.primitives.asymmetric import ec, padding, utils -# [END kms_asymmetric_imports] # [START kms_get_asymmetric_public] def getAsymmetricPublicKey(client, key_path): """ Retrieves the public key from a saved asymmetric key pair on Cloud KMS + + Requires: + cryptography.hazmat.backends.default_backend + cryptography.hazmat.primitives.serialization """ request = client.projects() \ .locations() \ @@ -47,6 +49,9 @@ def decryptRSA(ciphertext, client, key_path): """ Decrypt the input ciphertext (bytes) using an 'RSA_DECRYPT_OAEP_2048_SHA256' private key stored on Cloud KMS + + Requires: + base64 """ request_body = {'ciphertext': base64.b64encode(ciphertext).decode('utf-8')} request = client.projects() \ @@ -67,6 +72,10 @@ def encryptRSA(plaintext, client, key_path): """ Encrypt the input plaintext (bytes) locally using an 'RSA_DECRYPT_OAEP_2048_SHA256' public key retrieved from Cloud KMS + + Requires: + cryptography.hazmat.primitives.asymmetric.padding + cryptography.hazmat.primitives.hashes """ public_key = getAsymmetricPublicKey(client, key_path) pad = padding.OAEP(mgf=padding.MGF1(algorithm=hashes.SHA256()), @@ -80,6 +89,10 @@ def encryptRSA(plaintext, client, key_path): def signAsymmetric(message, client, key_path): """ Create a signature for a message using a private key stored on Cloud KMS + + Requires: + base64 + hashlib """ # Note: some key algorithms will require a different hash function # For example, EC_SIGN_P384_SHA384 requires SHA384 @@ -104,6 +117,13 @@ def verifySignatureRSA(signature, message, client, key_path): """ Verify the validity of an 'RSA_SIGN_PSS_2048_SHA256' signature for the specified message + + Requires: + cryptography.exceptions.InvalidSignature + cryptography.hazmat.primitives.asymmetric.padding + cryptography.hazmat.primitives.asymmetric.utils + cryptography.hazmat.primitives.hashes + hashlib """ public_key = getAsymmetricPublicKey(client, key_path) digest_bytes = hashlib.sha256(message).digest() @@ -127,6 +147,13 @@ def verifySignatureEC(signature, message, client, key_path): """ Verify the validity of an 'EC_SIGN_P256_SHA256' signature for the specified message + + Requires: + cryptography.exceptions.InvalidSignature + cryptography.hazmat.primitives.asymmetric.ec + cryptography.hazmat.primitives.asymmetric.utils + cryptography.hazmat.primitives.hashes + hashlib """ public_key = getAsymmetricPublicKey(client, key_path) digest_bytes = hashlib.sha256(message).digest() From d889421eb78daf01b383d81f969cea18b3a2880e Mon Sep 17 00:00:00 2001 From: DPE bot Date: Tue, 20 Nov 2018 15:40:29 -0800 Subject: [PATCH 030/136] Auto-update dependencies. [(#1846)](https://github.com/GoogleCloudPlatform/python-docs-samples/issues/1846) ACK, merging. --- kms/snippets/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/kms/snippets/requirements.txt b/kms/snippets/requirements.txt index e18999655f7f..36c6e96568cb 100644 --- a/kms/snippets/requirements.txt +++ b/kms/snippets/requirements.txt @@ -1,4 +1,4 @@ -google-api-python-client==1.6.6 -google-auth==1.4.1 +google-api-python-client==1.7.4 +google-auth==1.6.1 google-auth-httplib2==0.0.3 -cryptography==2.3.1 +cryptography==2.4.1 From 4f159ea04bb7a10714853b813a2f80509eb8e652 Mon Sep 17 00:00:00 2001 From: DPE bot Date: Wed, 21 Nov 2018 10:25:04 -0800 Subject: [PATCH 031/136] Auto-update dependencies. [(#1862)](https://github.com/GoogleCloudPlatform/python-docs-samples/issues/1862) --- kms/snippets/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kms/snippets/requirements.txt b/kms/snippets/requirements.txt index 36c6e96568cb..e75d6b4d639a 100644 --- a/kms/snippets/requirements.txt +++ b/kms/snippets/requirements.txt @@ -1,4 +1,4 @@ google-api-python-client==1.7.4 google-auth==1.6.1 google-auth-httplib2==0.0.3 -cryptography==2.4.1 +cryptography==2.4.2 From df03dc0efcc913f948148c42b70bc3c9ba1f2a78 Mon Sep 17 00:00:00 2001 From: Daniel Sanche Date: Mon, 7 Jan 2019 13:08:18 -0800 Subject: [PATCH 032/136] KMS: Updated for new client library [(#1903)](https://github.com/GoogleCloudPlatform/python-docs-samples/issues/1903) * updated kms samples to use new gapic client library --- kms/snippets/README.rst | 15 +- kms/snippets/README.rst.in | 4 +- kms/snippets/asymmetric.py | 137 ++++++--- kms/snippets/asymmetric_test.py | 133 ++++----- kms/snippets/quickstart.py | 21 +- kms/snippets/requirements.txt | 4 +- kms/snippets/snippets.py | 510 +++++++++++++------------------- kms/snippets/snippets_test.py | 361 ++++++++++++---------- 8 files changed, 573 insertions(+), 612 deletions(-) diff --git a/kms/snippets/README.rst b/kms/snippets/README.rst index 28777c841d84..17e34befaf0c 100644 --- a/kms/snippets/README.rst +++ b/kms/snippets/README.rst @@ -92,18 +92,5 @@ To run this sample: $ python snippets.py - usage: snippets.py [-h] - {create_key_ring,create_crypto_key,encrypt,decrypt,disable_crypto_key_version,enable_crypto_key_version,destroy_crypto_key_version,restore_crypto_key_version,add_member_to_crypto_key_policy,get_key_ring_policy} - ... - positional arguments: - {create_key_ring,create_crypto_key,encrypt,decrypt,disable_crypto_key_version,enable_crypto_key_version,destroy_crypto_key_version,restore_crypto_key_version,add_member_to_crypto_key_policy,get_key_ring_policy} - - optional arguments: - -h, --help show this help message and exit - - - - - -.. _Google Cloud SDK: https://cloud.google.com/sdk/ \ No newline at end of file +.. _Google Cloud SDK: https://cloud.google.com/sdk/ diff --git a/kms/snippets/README.rst.in b/kms/snippets/README.rst.in index 6299b5a0a535..f8aef3a243f7 100644 --- a/kms/snippets/README.rst.in +++ b/kms/snippets/README.rst.in @@ -18,5 +18,7 @@ samples: - name: Snippets file: snippets.py show_help: True +- name: Asymmetric + file: asymmetric.py -folder: kms/api-client \ No newline at end of file +folder: kms/api-client diff --git a/kms/snippets/asymmetric.py b/kms/snippets/asymmetric.py index 7f0d11aa608f..9c8abd15cc9b 100644 --- a/kms/snippets/asymmetric.py +++ b/kms/snippets/asymmetric.py @@ -13,7 +13,6 @@ # See the License for the specific language governing permissions and # limitations under the License.rom googleapiclient import discovery -import base64 import hashlib from cryptography.exceptions import InvalidSignature @@ -21,63 +20,96 @@ from cryptography.hazmat.primitives import hashes, serialization from cryptography.hazmat.primitives.asymmetric import ec, padding, utils +from google.cloud import kms_v1 +from google.cloud.kms_v1 import enums + + +# [START kms_create_asymmetric_key] +def create_asymmetric_key(project_id, location_id, key_ring_id, crypto_key_id): + """Creates an RSA encrypt/decrypt key pair within a specified KeyRing.""" + + # Creates an API client for the KMS API. + client = kms_v1.KeyManagementServiceClient() + + # The resource name of the KeyRing associated with the CryptoKey. + parent = client.key_ring_path(project_id, location_id, key_ring_id) + + # Create the CryptoKey object template + purpose = enums.CryptoKey.CryptoKeyPurpose.ASYMMETRIC_DECRYPT + algorithm = enums.CryptoKeyVersion.CryptoKeyVersionAlgorithm.\ + RSA_DECRYPT_OAEP_2048_SHA256 + crypto_key = {'purpose': purpose, + 'version_template': {'algorithm': algorithm}} + + # Create a CryptoKey for the given KeyRing. + response = client.create_crypto_key(parent, crypto_key_id, crypto_key) + + print('Created CryptoKey {}.'.format(response.name)) + return response +# [END kms_create_asymmetric_key] + # [START kms_get_asymmetric_public] -def getAsymmetricPublicKey(client, key_path): +def get_asymmetric_public_key(key_name): """ Retrieves the public key from a saved asymmetric key pair on Cloud KMS + Example key_name: + "projects/PROJECT_ID/locations/global/keyRings/RING_ID/cryptoKeys\ + /KEY_ID/cryptoKeyVersions/1" + Requires: cryptography.hazmat.backends.default_backend cryptography.hazmat.primitives.serialization """ - request = client.projects() \ - .locations() \ - .keyRings() \ - .cryptoKeys() \ - .cryptoKeyVersions() \ - .getPublicKey(name=key_path) - response = request.execute() - key_txt = response['pem'].encode('ascii') + + client = kms_v1.KeyManagementServiceClient() + response = client.get_public_key(key_name) + + key_txt = response.pem.encode('ascii') key = serialization.load_pem_public_key(key_txt, default_backend()) return key # [END kms_get_asymmetric_public] # [START kms_decrypt_rsa] -def decryptRSA(ciphertext, client, key_path): +def decrypt_rsa(ciphertext, key_name): """ Decrypt the input ciphertext (bytes) using an 'RSA_DECRYPT_OAEP_2048_SHA256' private key stored on Cloud KMS - Requires: - base64 + Example key_name: + "projects/PROJECT_ID/locations/global/keyRings/RING_ID/cryptoKeys\ + /KEY_ID/cryptoKeyVersions/1" """ - request_body = {'ciphertext': base64.b64encode(ciphertext).decode('utf-8')} - request = client.projects() \ - .locations() \ - .keyRings() \ - .cryptoKeys() \ - .cryptoKeyVersions() \ - .asymmetricDecrypt(name=key_path, - body=request_body) - response = request.execute() - plaintext = base64.b64decode(response['plaintext']) - return plaintext + + client = kms_v1.KeyManagementServiceClient() + response = client.asymmetric_decrypt(key_name, ciphertext) + return response.plaintext # [END kms_decrypt_rsa] # [START kms_encrypt_rsa] -def encryptRSA(plaintext, client, key_path): +def encrypt_rsa(plaintext, key_name): """ Encrypt the input plaintext (bytes) locally using an 'RSA_DECRYPT_OAEP_2048_SHA256' public key retrieved from Cloud KMS + Example key_name: + "projects/PROJECT_ID/locations/global/keyRings/RING_ID/cryptoKeys\ + /KEY_ID/cryptoKeyVersions/1" + Requires: cryptography.hazmat.primitives.asymmetric.padding cryptography.hazmat.primitives.hashes """ - public_key = getAsymmetricPublicKey(client, key_path) + # get the public key + client = kms_v1.KeyManagementServiceClient() + response = client.get_public_key(key_name) + key_txt = response.pem.encode('ascii') + public_key = serialization.load_pem_public_key(key_txt, default_backend()) + + # encrypt plaintext pad = padding.OAEP(mgf=padding.MGF1(algorithm=hashes.SHA256()), algorithm=hashes.SHA256(), label=None) @@ -86,38 +118,39 @@ def encryptRSA(plaintext, client, key_path): # [START kms_sign_asymmetric] -def signAsymmetric(message, client, key_path): +def sign_asymmetric(message, key_name): """ Create a signature for a message using a private key stored on Cloud KMS + Example key_name: + "projects/PROJECT_ID/locations/global/keyRings/RING_ID/cryptoKeys\ + /KEY_ID/cryptoKeyVersions/1" + Requires: - base64 hashlib """ # Note: some key algorithms will require a different hash function # For example, EC_SIGN_P384_SHA384 requires SHA384 + client = kms_v1.KeyManagementServiceClient() digest_bytes = hashlib.sha256(message).digest() - digest64 = base64.b64encode(digest_bytes) - - digest_JSON = {'sha256': digest64.decode('utf-8')} - request = client.projects() \ - .locations() \ - .keyRings() \ - .cryptoKeys() \ - .cryptoKeyVersions() \ - .asymmetricSign(name=key_path, - body={'digest': digest_JSON}) - response = request.execute() - return base64.b64decode(response.get('signature', None)) + + digest_json = {'sha256': digest_bytes} + + response = client.asymmetric_sign(key_name, digest_json) + return response.signature # [END kms_sign_asymmetric] # [START kms_verify_signature_rsa] -def verifySignatureRSA(signature, message, client, key_path): +def verify_signature_rsa(signature, message, key_name): """ Verify the validity of an 'RSA_SIGN_PSS_2048_SHA256' signature for the specified message + Example key_name: + "projects/PROJECT_ID/locations/global/keyRings/RING_ID/cryptoKeys\ + /KEY_ID/cryptoKeyVersions/1" + Requires: cryptography.exceptions.InvalidSignature cryptography.hazmat.primitives.asymmetric.padding @@ -125,7 +158,13 @@ def verifySignatureRSA(signature, message, client, key_path): cryptography.hazmat.primitives.hashes hashlib """ - public_key = getAsymmetricPublicKey(client, key_path) + # get the public key + client = kms_v1.KeyManagementServiceClient() + response = client.get_public_key(key_name) + key_txt = response.pem.encode('ascii') + public_key = serialization.load_pem_public_key(key_txt, default_backend()) + + # get the digest of the message digest_bytes = hashlib.sha256(message).digest() try: @@ -143,11 +182,15 @@ def verifySignatureRSA(signature, message, client, key_path): # [START kms_verify_signature_ec] -def verifySignatureEC(signature, message, client, key_path): +def verify_signature_ec(signature, message, key_name): """ Verify the validity of an 'EC_SIGN_P256_SHA256' signature for the specified message + Example key_name: + "projects/PROJECT_ID/locations/global/keyRings/RING_ID/cryptoKeys\ + /KEY_ID/cryptoKeyVersions/1" + Requires: cryptography.exceptions.InvalidSignature cryptography.hazmat.primitives.asymmetric.ec @@ -155,7 +198,13 @@ def verifySignatureEC(signature, message, client, key_path): cryptography.hazmat.primitives.hashes hashlib """ - public_key = getAsymmetricPublicKey(client, key_path) + # get the public key + client = kms_v1.KeyManagementServiceClient() + response = client.get_public_key(key_name) + key_txt = response.pem.encode('ascii') + public_key = serialization.load_pem_public_key(key_txt, default_backend()) + + # get the digest of the message digest_bytes = hashlib.sha256(message).digest() try: diff --git a/kms/snippets/asymmetric_test.py b/kms/snippets/asymmetric_test.py index 4ce9b32aed5b..cc621003c475 100644 --- a/kms/snippets/asymmetric_test.py +++ b/kms/snippets/asymmetric_test.py @@ -16,135 +16,118 @@ from os import environ from time import sleep +import asymmetric + from cryptography.hazmat.backends.openssl.ec import _EllipticCurvePublicKey from cryptography.hazmat.backends.openssl.rsa import _RSAPublicKey -from googleapiclient import discovery -from googleapiclient.errors import HttpError -import asymmetric as sample +from google.api_core.exceptions import GoogleAPICallError +from google.cloud.kms_v1 import enums +from snippets import create_key_ring -def create_key_helper(key_id, key_path, purpose, algorithm, t): - try: - t.client.projects() \ - .locations() \ - .keyRings() \ - .cryptoKeys() \ - .create(parent='{}/keyRings/{}'.format(t.parent, t.keyring), - body={'purpose': purpose, - 'versionTemplate': { - 'algorithm': algorithm - } - }, - cryptoKeyId=key_id) \ - .execute() - return True - except HttpError: - # key already exists - return False +from snippets_test import create_key_helper def setup_module(module): """ Set up keys in project if needed """ - t = TestKMSSamples() + t = TestKMSAsymmetric() try: # create keyring - t.client.projects() \ - .locations() \ - .keyRings() \ - .create(parent=t.parent, body={}, keyRingId=t.keyring) \ - .execute() - except HttpError: + create_key_ring(t.project_id, t.location, t.keyring_id) + except GoogleAPICallError: # keyring already exists pass - s1 = create_key_helper(t.rsaDecryptId, t.rsaDecrypt, 'ASYMMETRIC_DECRYPT', - 'RSA_DECRYPT_OAEP_2048_SHA256', t) - s2 = create_key_helper(t.rsaSignId, t.rsaSign, 'ASYMMETRIC_SIGN', - 'RSA_SIGN_PSS_2048_SHA256', t) - s3 = create_key_helper(t.ecSignId, t.ecSign, 'ASYMMETRIC_SIGN', - 'EC_SIGN_P256_SHA256', t) + s1 = create_key_helper(t.rsaDecryptId, + enums.CryptoKey.CryptoKeyPurpose.ASYMMETRIC_DECRYPT, + enums.CryptoKeyVersion.CryptoKeyVersionAlgorithm. + RSA_DECRYPT_OAEP_2048_SHA256, + t) + s2 = create_key_helper(t.rsaSignId, + enums.CryptoKey.CryptoKeyPurpose.ASYMMETRIC_SIGN, + enums.CryptoKeyVersion.CryptoKeyVersionAlgorithm. + RSA_SIGN_PSS_2048_SHA256, + t) + s3 = create_key_helper(t.ecSignId, + enums.CryptoKey.CryptoKeyPurpose.ASYMMETRIC_SIGN, + enums.CryptoKeyVersion.CryptoKeyVersionAlgorithm. + EC_SIGN_P256_SHA256, + t) + if s1 or s2 or s3: # leave time for keys to initialize sleep(20) -class TestKMSSamples: - +class TestKMSAsymmetric: project_id = environ['GCLOUD_PROJECT'] - keyring = 'kms-asymmetric-samples4' - parent = 'projects/{}/locations/global'.format(project_id) + keyring_id = 'kms-samples' + location = 'global' + parent = 'projects/{}/locations/{}'.format(project_id, location) rsaSignId = 'rsa-sign' rsaDecryptId = 'rsa-decrypt' ecSignId = 'ec-sign' rsaSign = '{}/keyRings/{}/cryptoKeys/{}/cryptoKeyVersions/1' \ - .format(parent, keyring, rsaSignId) + .format(parent, keyring_id, rsaSignId) rsaDecrypt = '{}/keyRings/{}/cryptoKeys/{}/cryptoKeyVersions/1' \ - .format(parent, keyring, rsaDecryptId) + .format(parent, keyring_id, rsaDecryptId) ecSign = '{}/keyRings/{}/cryptoKeys/{}/cryptoKeyVersions/1' \ - .format(parent, keyring, ecSignId) + .format(parent, keyring_id, ecSignId) message = 'test message 123' message_bytes = message.encode('utf-8') - client = discovery.build('cloudkms', 'v1') - def test_get_public_key(self): - rsa_key = sample.getAsymmetricPublicKey(self.client, self.rsaDecrypt) + rsa_key = asymmetric.get_asymmetric_public_key(self.rsaDecrypt) + assert isinstance(rsa_key, _RSAPublicKey), 'expected RSA key' + rsa_key = asymmetric.get_asymmetric_public_key(self.rsaSign) assert isinstance(rsa_key, _RSAPublicKey), 'expected RSA key' - ec_key = sample.getAsymmetricPublicKey(self.client, self.ecSign) + ec_key = asymmetric.get_asymmetric_public_key(self.ecSign) assert isinstance(ec_key, _EllipticCurvePublicKey), 'expected EC key' def test_rsa_encrypt_decrypt(self): - ciphertext = sample.encryptRSA(self.message_bytes, - self.client, - self.rsaDecrypt) - # ciphertext should be 256 characters with base64 and RSA 2048 + ciphertext = asymmetric.encrypt_rsa(self.message_bytes, + self.rsaDecrypt) + # signature should be 256 bytes for RSA 2048 assert len(ciphertext) == 256, \ 'ciphertext should be 256 chars; got {}'.format(len(ciphertext)) - plaintext_bytes = sample.decryptRSA(ciphertext, - self.client, - self.rsaDecrypt) + plaintext_bytes = asymmetric.decrypt_rsa(ciphertext, + self.rsaDecrypt) assert plaintext_bytes == self.message_bytes plaintext = plaintext_bytes.decode('utf-8') assert plaintext == self.message def test_rsa_sign_verify(self): - sig = sample.signAsymmetric(self.message_bytes, - self.client, - self.rsaSign) - # ciphertext should be 344 characters with base64 and RSA 2048 + sig = asymmetric.sign_asymmetric(self.message_bytes, + self.rsaSign) + # signature should be 256 bytes for RSA 2048 assert len(sig) == 256, \ 'sig should be 256 chars; got {}'.format(len(sig)) - success = sample.verifySignatureRSA(sig, - self.message_bytes, - self.client, - self.rsaSign) + success = asymmetric.verify_signature_rsa(sig, + self.message_bytes, + self.rsaSign) assert success is True, 'RSA verification failed' changed_bytes = self.message_bytes + b'.' - success = sample.verifySignatureRSA(sig, - changed_bytes, - self.client, - self.rsaSign) + success = asymmetric.verify_signature_rsa(sig, + changed_bytes, + self.rsaSign) assert success is False, 'verify should fail with modified message' def test_ec_sign_verify(self): - sig = sample.signAsymmetric(self.message_bytes, - self.client, - self.ecSign) + sig = asymmetric.sign_asymmetric(self.message_bytes, + self.ecSign) assert len(sig) > 50 and len(sig) < 300, \ 'sig outside expected length range' - success = sample.verifySignatureEC(sig, - self.message_bytes, - self.client, - self.ecSign) + success = asymmetric.verify_signature_ec(sig, + self.message_bytes, + self.ecSign) assert success is True, 'EC verification failed' changed_bytes = self.message_bytes + b'.' - success = sample.verifySignatureEC(sig, - changed_bytes, - self.client, - self.ecSign) + success = asymmetric.verify_signature_ec(sig, + changed_bytes, + self.ecSign) assert success is False, 'verify should fail with modified message' diff --git a/kms/snippets/quickstart.py b/kms/snippets/quickstart.py index 042bcae9ecb8..2f97f38f70de 100644 --- a/kms/snippets/quickstart.py +++ b/kms/snippets/quickstart.py @@ -13,32 +13,37 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and +import os + def run_quickstart(): # [START kms_quickstart] # Imports the Google APIs client library - import googleapiclient.discovery + from google.cloud import kms_v1 # Your Google Cloud Platform project ID project_id = 'YOUR_PROJECT_ID' + # [END kms_quickstart] + project_id = os.environ['GCLOUD_PROJECT'] + # [START kms_quickstart] # Lists keys in the "global" location. location = 'global' # Creates an API client for the KMS API. - kms_client = googleapiclient.discovery.build('cloudkms', 'v1') + client = kms_v1.KeyManagementServiceClient() # The resource name of the location associated with the key rings. - parent = 'projects/{}/locations/{}'.format(project_id, location) + parent = client.location_path(project_id, location) # Lists key rings - request = kms_client.projects().locations().keyRings().list(parent=parent) - response = request.execute() + response = client.list_key_rings(parent) + response_list = list(response) - if 'keyRings' in response and response['keyRings']: + if len(response_list) > 0: print('Key rings:') - for key_ring in response['keyRings']: - print(key_ring['name']) + for key_ring in response_list: + print(key_ring.name) else: print('No key rings found.') # [END kms_quickstart] diff --git a/kms/snippets/requirements.txt b/kms/snippets/requirements.txt index e75d6b4d639a..74f7afd79000 100644 --- a/kms/snippets/requirements.txt +++ b/kms/snippets/requirements.txt @@ -1,4 +1,2 @@ -google-api-python-client==1.7.4 -google-auth==1.6.1 -google-auth-httplib2==0.0.3 +google-cloud-kms==0.2 cryptography==2.4.2 diff --git a/kms/snippets/snippets.py b/kms/snippets/snippets.py index 73e4a65d812b..07b027051913 100644 --- a/kms/snippets/snippets.py +++ b/kms/snippets/snippets.py @@ -13,11 +13,9 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and -import argparse -import base64 -import io -import googleapiclient.discovery +from google.cloud import kms_v1 +from google.cloud.kms_v1 import enums # [START kms_create_keyring] @@ -25,17 +23,20 @@ def create_key_ring(project_id, location_id, key_ring_id): """Creates a KeyRing in the given location (e.g. global).""" # Creates an API client for the KMS API. - kms_client = googleapiclient.discovery.build('cloudkms', 'v1') + client = kms_v1.KeyManagementServiceClient() # The resource name of the location associated with the KeyRing. - parent = 'projects/{}/locations/{}'.format(project_id, location_id) + parent = client.location_path(project_id, location_id) - # Create KeyRing - request = kms_client.projects().locations().keyRings().create( - parent=parent, body={}, keyRingId=key_ring_id) - response = request.execute() + # The keyring object template + keyring_name = client.key_ring_path(project_id, location_id, key_ring_id) + keyring = {'name': keyring_name} - print('Created KeyRing {}.'.format(response['name'])) + # Create a KeyRing + response = client.create_key_ring(parent, key_ring_id, keyring) + + print('Created KeyRing {}.'.format(response.name)) + return response # [END kms_create_keyring] @@ -44,87 +45,55 @@ def create_crypto_key(project_id, location_id, key_ring_id, crypto_key_id): """Creates a CryptoKey within a KeyRing in the given location.""" # Creates an API client for the KMS API. - kms_client = googleapiclient.discovery.build('cloudkms', 'v1') + client = kms_v1.KeyManagementServiceClient() # The resource name of the KeyRing associated with the CryptoKey. - parent = 'projects/{}/locations/{}/keyRings/{}'.format( - project_id, location_id, key_ring_id) + parent = client.key_ring_path(project_id, location_id, key_ring_id) + + # Create the CryptoKey object template + purpose = enums.CryptoKey.CryptoKeyPurpose.ENCRYPT_DECRYPT + crypto_key = {'purpose': purpose} # Create a CryptoKey for the given KeyRing. - request = kms_client.projects().locations().keyRings().cryptoKeys().create( - parent=parent, body={'purpose': 'ENCRYPT_DECRYPT'}, - cryptoKeyId=crypto_key_id) - response = request.execute() + response = client.create_crypto_key(parent, crypto_key_id, crypto_key) - print('Created CryptoKey {}.'.format(response['name'])) + print('Created CryptoKey {}.'.format(response.name)) + return response # [END kms_create_cryptokey] # [START kms_encrypt] -def encrypt(project_id, location_id, key_ring_id, crypto_key_id, - plaintext_file_name, ciphertext_file_name): - """Encrypts data from plaintext_file_name using the provided CryptoKey and - saves it to ciphertext_file_name so it can only be recovered with a call to - decrypt. - """ +def encrypt_symmetric(project_id, location_id, key_ring_id, crypto_key_id, + plaintext): + """Encrypts input plaintext data using the provided symmetric CryptoKey.""" # Creates an API client for the KMS API. - kms_client = googleapiclient.discovery.build('cloudkms', 'v1') + client = kms_v1.KeyManagementServiceClient() # The resource name of the CryptoKey. - name = 'projects/{}/locations/{}/keyRings/{}/cryptoKeys/{}'.format( - project_id, location_id, key_ring_id, crypto_key_id) - - # Read data from the input file. - with io.open(plaintext_file_name, 'rb') as plaintext_file: - plaintext = plaintext_file.read() + name = client.crypto_key_path_path(project_id, location_id, key_ring_id, + crypto_key_id) # Use the KMS API to encrypt the data. - crypto_keys = kms_client.projects().locations().keyRings().cryptoKeys() - request = crypto_keys.encrypt( - name=name, - body={'plaintext': base64.b64encode(plaintext).decode('ascii')}) - response = request.execute() - ciphertext = base64.b64decode(response['ciphertext'].encode('ascii')) - - # Write the encrypted data to a file. - with io.open(ciphertext_file_name, 'wb') as ciphertext_file: - ciphertext_file.write(ciphertext) - - print('Saved ciphertext to {}.'.format(ciphertext_file_name)) + response = client.encrypt(name, plaintext) + return response.ciphertext # [END kms_encrypt] # [START kms_decrypt] -def decrypt(project_id, location_id, key_ring_id, crypto_key_id, - ciphertext_file_name, plaintext_file_name): - """Decrypts data from ciphertext_file_name that was previously encrypted - using the provided CryptoKey and saves it to plaintext_file_name.""" +def decrypt_symmetric(project_id, location_id, key_ring_id, crypto_key_id, + ciphertext): + """Decrypts input ciphertext using the provided symmetric CryptoKey.""" # Creates an API client for the KMS API. - kms_client = googleapiclient.discovery.build('cloudkms', 'v1') + client = kms_v1.KeyManagementServiceClient() # The resource name of the CryptoKey. - name = 'projects/{}/locations/{}/keyRings/{}/cryptoKeys/{}'.format( - project_id, location_id, key_ring_id, crypto_key_id) - - # Read encrypted data from the input file. - with io.open(ciphertext_file_name, 'rb') as ciphertext_file: - ciphertext = ciphertext_file.read() - + name = client.crypto_key_path_path(project_id, location_id, key_ring_id, + crypto_key_id) # Use the KMS API to decrypt the data. - crypto_keys = kms_client.projects().locations().keyRings().cryptoKeys() - request = crypto_keys.decrypt( - name=name, - body={'ciphertext': base64.b64encode(ciphertext).decode('ascii')}) - response = request.execute() - plaintext = base64.b64decode(response['plaintext'].encode('ascii')) - - # Write the decrypted data to a file. - with io.open(plaintext_file_name, 'wb') as plaintext_file: - plaintext_file.write(plaintext) - - print('Saved plaintext to {}.'.format(plaintext_file_name)) + response = client.decrypt(name, ciphertext) + return response.plaintext # [END kms_decrypt] @@ -135,23 +104,21 @@ def disable_crypto_key_version(project_id, location_id, key_ring_id, KeyRing.""" # Creates an API client for the KMS API. - kms_client = googleapiclient.discovery.build('cloudkms', 'v1') + client = kms_v1.KeyManagementServiceClient() # Construct the resource name of the CryptoKeyVersion. - name = ( - 'projects/{}/locations/{}/keyRings/{}/cryptoKeys/{}/' - 'cryptoKeyVersions/{}' - .format( - project_id, location_id, key_ring_id, crypto_key_id, version_id)) + name = client.crypto_key_version_path(project_id, location_id, key_ring_id, + crypto_key_id, version_id) # Use the KMS API to disable the CryptoKeyVersion. - crypto_keys = kms_client.projects().locations().keyRings().cryptoKeys() - request = crypto_keys.cryptoKeyVersions().patch( - name=name, body={'state': 'DISABLED'}, updateMask='state') - response = request.execute() + new_state = enums.CryptoKeyVersion.CryptoKeyVersionState.DISABLED + version = {'name': name, 'state': new_state} + update_mask = {'paths': ["state"]} + # Print results + response = client.update_crypto_key_version(version, update_mask) print('CryptoKeyVersion {}\'s state has been set to {}.'.format( - name, response['state'])) + name, response.state)) # [END kms_disable_cryptokey_version] @@ -162,23 +129,21 @@ def enable_crypto_key_version(project_id, location_id, key_ring_id, KeyRing.""" # Creates an API client for the KMS API. - kms_client = googleapiclient.discovery.build('cloudkms', 'v1') + client = kms_v1.KeyManagementServiceClient() # Construct the resource name of the CryptoKeyVersion. - name = ( - 'projects/{}/locations/{}/keyRings/{}/cryptoKeys/{}/' - 'cryptoKeyVersions/{}' - .format( - project_id, location_id, key_ring_id, crypto_key_id, version_id)) + name = client.crypto_key_version_path(project_id, location_id, key_ring_id, + crypto_key_id, version_id) # Use the KMS API to enable the CryptoKeyVersion. - crypto_keys = kms_client.projects().locations().keyRings().cryptoKeys() - request = crypto_keys.cryptoKeyVersions().patch( - name=name, body={'state': 'ENABLED'}, updateMask='state') - response = request.execute() + new_state = enums.CryptoKeyVersion.CryptoKeyVersionState.ENABLED + version = {'name': name, 'state': new_state} + update_mask = {'paths': ["state"]} + # Print results + response = client.update_crypto_key_version(version, update_mask) print('CryptoKeyVersion {}\'s state has been set to {}.'.format( - name, response['state'])) + name, response.state)) # [END kms_enable_cryptokey_version] @@ -189,22 +154,18 @@ def destroy_crypto_key_version( KeyRing for destruction 24 hours in the future.""" # Creates an API client for the KMS API. - kms_client = googleapiclient.discovery.build('cloudkms', 'v1') + client = kms_v1.KeyManagementServiceClient() # Construct the resource name of the CryptoKeyVersion. - name = ( - 'projects/{}/locations/{}/keyRings/{}/cryptoKeys/{}/' - 'cryptoKeyVersions/{}' - .format( - project_id, location_id, key_ring_id, crypto_key_id, version_id)) + name = client.crypto_key_version_path(project_id, location_id, key_ring_id, + crypto_key_id, version_id) - # Use the KMS API to schedule the CryptoKeyVersion for destruction. - crypto_keys = kms_client.projects().locations().keyRings().cryptoKeys() - request = crypto_keys.cryptoKeyVersions().destroy(name=name, body={}) - response = request.execute() + # Use the KMS API to mark the CryptoKeyVersion for destruction. + response = client.destroy_crypto_key_version(name) + # Print results print('CryptoKeyVersion {}\'s state has been set to {}.'.format( - name, response['state'])) + name, response.state)) # [END kms_destroy_cryptokey_version] @@ -214,22 +175,20 @@ def restore_crypto_key_version( """Restores a CryptoKeyVersion that is scheduled for destruction.""" # Creates an API client for the KMS API. - kms_client = googleapiclient.discovery.build('cloudkms', 'v1') + client = kms_v1.KeyManagementServiceClient() # Construct the resource name of the CryptoKeyVersion. - name = ( - 'projects/{}/locations/{}/keyRings/{}/cryptoKeys/{}/' - 'cryptoKeyVersions/{}' - .format( - project_id, location_id, key_ring_id, crypto_key_id, version_id)) + name = client.crypto_key_version_path(project_id, location_id, key_ring_id, + crypto_key_id, version_id) # Use the KMS API to restore the CryptoKeyVersion. - crypto_keys = kms_client.projects().locations().keyRings().cryptoKeys() - request = crypto_keys.cryptoKeyVersions().restore(name=name, body={}) - response = request.execute() + response = client.restore_crypto_key_version(name) + # Print results print('CryptoKeyVersion {}\'s state has been set to {}.'.format( - name, response['state'])) + name, response.state)) + + # [END kms_restore_cryptokey_version] @@ -240,217 +199,154 @@ def add_member_to_crypto_key_policy( (IAM) policy for a given CryptoKey associated with a KeyRing.""" # Creates an API client for the KMS API. - kms_client = googleapiclient.discovery.build('cloudkms', 'v1') + client = kms_v1.KeyManagementServiceClient() # The resource name of the CryptoKey. - parent = 'projects/{}/locations/{}/keyRings/{}/cryptoKeys/{}'.format( - project_id, location_id, key_ring_id, crypto_key_id) - - # Get the current IAM policy and add the new member to it. - crypto_keys = kms_client.projects().locations().keyRings().cryptoKeys() - policy_request = crypto_keys.getIamPolicy(resource=parent) - policy_response = policy_request.execute() - bindings = [] - if 'bindings' in policy_response.keys(): - bindings = policy_response['bindings'] - members = [] - members.append(member) - new_binding = dict() - new_binding['role'] = role - new_binding['members'] = members - bindings.append(new_binding) - policy_response['bindings'] = bindings - - # Set the new IAM Policy. - crypto_keys = kms_client.projects().locations().keyRings().cryptoKeys() - request = crypto_keys.setIamPolicy( - resource=parent, body={'policy': policy_response}) - request.execute() - - print_msg = ( - 'Member {} added with role {} to policy for CryptoKey {} in KeyRing {}' - .format(member, role, crypto_key_id, key_ring_id)) - print(print_msg) + resource = client.crypto_key_path_path(project_id, location_id, + key_ring_id, crypto_key_id) + # Get the current IAM policy. + policy = client.get_iam_policy(resource) + + # Add member + policy.bindings.add( + role=role, + members=[member]) + + # Update the IAM Policy. + client.set_iam_policy(resource, policy) + + # Print results + print('Member {} added with role {} to policy for CryptoKey {} \ + in KeyRing {}'.format(member, role, crypto_key_id, key_ring_id)) # [END kms_add_member_to_cryptokey_policy] +# [START kms_add_member_to_keyring_policy] +def add_member_to_key_ring_policy( + project_id, location_id, key_ring_id, member, role): + """Adds a member with a given role to the Identity and Access Management + (IAM) policy for a given KeyRing.""" + + # Creates an API client for the KMS API. + client = kms_v1.KeyManagementServiceClient() + + # The resource name of the KeyRing. + resource = client.key_ring_path(project_id, location_id, key_ring_id) + + # Get the current IAM policy. + policy = client.get_iam_policy(resource) + + # Add member + policy.bindings.add( + role=role, + members=[member]) + + # Update the IAM Policy. + client.set_iam_policy(resource, policy) + + # Print results + print('Member {} added with role {} to policy in KeyRing {}' + .format(member, role, key_ring_id)) + +# [END kms_add_member_to_keyring_policy] + + +# [START kms_remove_member_from_cryptokey_policy] +def remove_member_from_crypto_key_policy( + project_id, location_id, key_ring_id, crypto_key_id, member, role): + """Removes a member with a given role from the Identity and Access + Management (IAM) policy for a given CryptoKey associated with a KeyRing.""" + + # Creates an API client for the KMS API. + client = kms_v1.KeyManagementServiceClient() + + # The resource name of the CryptoKey. + resource = client.crypto_key_path_path(project_id, location_id, + key_ring_id, crypto_key_id) + # Get the current IAM policy. + policy = client.get_iam_policy(resource) + + # Remove member + for b in list(policy.bindings): + if b.role == role and member in b.members: + b.members.remove(member) + + # Update the IAM Policy. + client.set_iam_policy(resource, policy) + + # Print results + print('Member {} removed from role {} for CryptoKey in KeyRing {}' + .format(member, role, crypto_key_id, key_ring_id)) +# [END kms_remove_member_from_cryptokey_policy] + + +def remove_member_from_key_ring_policy(project_id, location_id, key_ring_id, + member, role): + """Removes a member with a given role from the Identity and Access + Management (IAM) policy for a given KeyRing.""" + + # Creates an API client for the KMS API. + client = kms_v1.KeyManagementServiceClient() + + # The resource name of the KeyRing. + resource = client.key_ring_path(project_id, location_id, key_ring_id) + + # Get the current IAM policy. + policy = client.get_iam_policy(resource) + + # Remove member + for b in list(policy.bindings): + if b.role == role and member in b.members: + b.members.remove(member) + + # Update the IAM Policy. + client.set_iam_policy(resource, policy) + + # Print results + print('Member {} removed from role {} for KeyRing {}' + .format(member, role, key_ring_id)) + + # [START kms_get_keyring_policy] def get_key_ring_policy(project_id, location_id, key_ring_id): """Gets the Identity and Access Management (IAM) policy for a given KeyRing and prints out roles and the members assigned to those roles.""" # Creates an API client for the KMS API. - kms_client = googleapiclient.discovery.build('cloudkms', 'v1') + client = kms_v1.KeyManagementServiceClient() # The resource name of the KeyRing. - parent = 'projects/{}/locations/{}/keyRings/{}'.format( - project_id, location_id, key_ring_id) + resource = client.key_ring_path(project_id, location_id, key_ring_id) # Get the current IAM policy. - request = kms_client.projects().locations().keyRings().getIamPolicy( - resource=parent) - response = request.execute() - - if 'bindings' in response.keys(): - print('Printing IAM policy for resource {}:'.format(parent)) - for binding in response['bindings']: - print('') - print('Role: {}'.format(binding['role'])) - print('Members:') - for member in binding['members']: - print(member) - print('') - else: - print('No roles found for resource {}.'.format(parent)) + policy = client.get_iam_policy(resource) + + # Print results + print('Printing IAM policy for resource {}:'.format(resource)) + for b in policy.bindings: + for m in b.members: + print('Role: {} Member: {}'.format(b.role, m)) + return policy # [END kms_get_keyring_policy] -if __name__ == '__main__': - parser = argparse.ArgumentParser( - description=__doc__, - formatter_class=argparse.RawDescriptionHelpFormatter) - subparsers = parser.add_subparsers(dest='command') - - create_key_ring_parser = subparsers.add_parser('create_key_ring') - create_key_ring_parser.add_argument('project') - create_key_ring_parser.add_argument('location') - create_key_ring_parser.add_argument('key_ring') - - create_crypto_key_parser = subparsers.add_parser('create_crypto_key') - create_crypto_key_parser.add_argument('project') - create_crypto_key_parser.add_argument('location') - create_crypto_key_parser.add_argument('key_ring') - create_crypto_key_parser.add_argument('crypto_key') - - encrypt_parser = subparsers.add_parser('encrypt') - encrypt_parser.add_argument('project') - encrypt_parser.add_argument('location') - encrypt_parser.add_argument('key_ring') - encrypt_parser.add_argument('crypto_key') - encrypt_parser.add_argument('infile') - encrypt_parser.add_argument('outfile') - - decrypt_parser = subparsers.add_parser('decrypt') - decrypt_parser.add_argument('project') - decrypt_parser.add_argument('location') - decrypt_parser.add_argument('key_ring') - decrypt_parser.add_argument('crypto_key') - decrypt_parser.add_argument('infile') - decrypt_parser.add_argument('outfile') - - disable_crypto_key_version_parser = subparsers.add_parser( - 'disable_crypto_key_version') - disable_crypto_key_version_parser.add_argument('project') - disable_crypto_key_version_parser.add_argument('location') - disable_crypto_key_version_parser.add_argument('key_ring') - disable_crypto_key_version_parser.add_argument('crypto_key') - disable_crypto_key_version_parser.add_argument('version') - - enable_crypto_key_version_parser = subparsers.add_parser( - 'enable_crypto_key_version') - enable_crypto_key_version_parser.add_argument('project') - enable_crypto_key_version_parser.add_argument('location') - enable_crypto_key_version_parser.add_argument('key_ring') - enable_crypto_key_version_parser.add_argument('crypto_key') - enable_crypto_key_version_parser.add_argument('version') - - destroy_crypto_key_version_parser = subparsers.add_parser( - 'destroy_crypto_key_version') - destroy_crypto_key_version_parser.add_argument('project') - destroy_crypto_key_version_parser.add_argument('location') - destroy_crypto_key_version_parser.add_argument('key_ring') - destroy_crypto_key_version_parser.add_argument('crypto_key') - destroy_crypto_key_version_parser.add_argument('version') - - restore_crypto_key_version_parser = subparsers.add_parser( - 'restore_crypto_key_version') - restore_crypto_key_version_parser.add_argument('project') - restore_crypto_key_version_parser.add_argument('location') - restore_crypto_key_version_parser.add_argument('key_ring') - restore_crypto_key_version_parser.add_argument('crypto_key') - restore_crypto_key_version_parser.add_argument('version') - - add_member_to_crypto_key_policy_parser = subparsers.add_parser( - 'add_member_to_crypto_key_policy') - add_member_to_crypto_key_policy_parser.add_argument('project') - add_member_to_crypto_key_policy_parser.add_argument('location') - add_member_to_crypto_key_policy_parser.add_argument('key_ring') - add_member_to_crypto_key_policy_parser.add_argument('crypto_key') - add_member_to_crypto_key_policy_parser.add_argument('member') - add_member_to_crypto_key_policy_parser.add_argument('role') - - get_key_ring_policy_parser = subparsers.add_parser('get_key_ring_policy') - get_key_ring_policy_parser.add_argument('project') - get_key_ring_policy_parser.add_argument('location') - get_key_ring_policy_parser.add_argument('key_ring') - - args = parser.parse_args() - - if args.command == 'create_key_ring': - create_key_ring( - args.project, - args.location, - args.key_ring) - elif args.command == 'create_crypto_key': - create_crypto_key( - args.project, - args.location, - args.key_ring, - args.crypto_key) - elif args.command == 'encrypt': - encrypt( - args.project, - args.location, - args.key_ring, - args.crypto_key, - args.infile, - args.outfile) - elif args.command == 'decrypt': - decrypt( - args.project, - args.location, - args.key_ring, - args.crypto_key, - args.infile, - args.outfile) - elif args.command == 'disable_crypto_key_version': - disable_crypto_key_version( - args.project, - args.location, - args.key_ring, - args.crypto_key, - args.version) - elif args.command == 'enable_crypto_key_version': - enable_crypto_key_version( - args.project, - args.location, - args.key_ring, - args.crypto_key, - args.version) - elif args.command == 'destroy_crypto_key_version': - destroy_crypto_key_version( - args.project, - args.location, - args.key_ring, - args.crypto_key, - args.version) - elif args.command == 'restore_crypto_key_version': - restore_crypto_key_version( - args.project, - args.location, - args.key_ring, - args.crypto_key, - args.version) - elif args.command == 'add_member_to_crypto_key_policy': - add_member_to_crypto_key_policy( - args.project, - args.location, - args.key_ring, - args.crypto_key, - args.member, - args.role) - elif args.command == 'get_key_ring_policy': - get_key_ring_policy( - args.project, - args.location, - args.key_ring) +def get_crypto_key_policy(project_id, location_id, key_ring_id, crypto_key_id): + """Gets the Identity and Access Management (IAM) policy for a given KeyRing + and prints out roles and the members assigned to those roles.""" + + # Creates an API client for the KMS API. + client = kms_v1.KeyManagementServiceClient() + + # The resource name of the CryptoKey. + resource = client.crypto_key_path_path(project_id, location_id, + key_ring_id, crypto_key_id) + + # Get the current IAM policy. + policy = client.get_iam_policy(resource) + + # Print results + print('Printing IAM policy for resource {}:'.format(resource)) + for b in policy.bindings: + for m in b.members: + print('Role: {} Member: {}'.format(b.role, m)) + return policy diff --git a/kms/snippets/snippets_test.py b/kms/snippets/snippets_test.py index b36d9644b9ef..9da03d9c5f2b 100644 --- a/kms/snippets/snippets_test.py +++ b/kms/snippets/snippets_test.py @@ -13,167 +13,208 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and -import os -import random -import string +import time +from os import environ -import googleapiclient.discovery +from google.api_core.exceptions import GoogleAPICallError +from google.cloud import kms_v1 +from google.cloud.kms_v1 import enums +from google.iam.v1.policy_pb2 import Policy + +import pytest import snippets -PROJECT = os.environ['GCLOUD_PROJECT'] - -# Your Google Cloud Platform Key Location -LOCATION = 'global' - -# Your Google Cloud Platform KeyRing name -KEY_RING = ''.join( - random.choice(string.ascii_lowercase + string.digits) for _ in range(12)) - -# Your Google Cloud Platform CryptoKey name -CRYPTO_KEY = ''.join( - random.choice(string.ascii_lowercase + string.digits) for _ in range(12)) - -# Your Google Cloud Platform CryptoKeyVersion name -VERSION = 1 - -# A member to add to our IAM policy -MEMBER = 'user:ryanmats@google.com' - -# The role we want our new member to have for our IAM policy -ROLE = 'roles/owner' - - -def test_create_key_ring(capsys): - snippets.create_key_ring(PROJECT, LOCATION, KEY_RING) - out, _ = capsys.readouterr() - expected = 'Created KeyRing projects/{}/locations/{}/keyRings/{}.'.format( - PROJECT, LOCATION, KEY_RING) - assert expected in out - - -def test_create_crypto_key(capsys): - snippets.create_crypto_key( - PROJECT, LOCATION, KEY_RING, CRYPTO_KEY) - out, _ = capsys.readouterr() - expected = ( - 'Created CryptoKey projects/{}/locations/{}/keyRings/{}/cryptoKeys/{}.' - .format(PROJECT, LOCATION, KEY_RING, CRYPTO_KEY)) - assert expected in out - - -def test_encrypt_decrypt(capsys, tmpdir): - # Write to a plaintext file. - tmpdir.join('in.txt').write('SampleText') - - # Construct temporary files. - plaintext_file = tmpdir.join('in.txt') - encrypted_file = tmpdir.join('out.txt') - decrypted_file = tmpdir.join('out2.txt') - - # Encrypt text and then decrypt it. - snippets.encrypt( - PROJECT, LOCATION, KEY_RING, CRYPTO_KEY, - str(plaintext_file), str(encrypted_file)) - snippets.decrypt( - PROJECT, LOCATION, KEY_RING, CRYPTO_KEY, - str(encrypted_file), str(decrypted_file)) - - # Make sure the decrypted text matches the original text. - decrypted_text = decrypted_file.read() - assert decrypted_text == 'SampleText' - - # Make sure other output is as expected. - out, _ = capsys.readouterr() - assert 'Saved ciphertext to {}.'.format(str(encrypted_file)) in out - assert 'Saved plaintext to {}.'.format(str(decrypted_file)) in out - - -def test_disable_crypto_key_version(capsys): - snippets.disable_crypto_key_version( - PROJECT, LOCATION, KEY_RING, CRYPTO_KEY, VERSION) - out, _ = capsys.readouterr() - expected = ( - 'CryptoKeyVersion projects/{}/locations/{}/keyRings/{}/cryptoKeys/{}/' - 'cryptoKeyVersions/{}\'s state has been set to {}.' - .format( - PROJECT, LOCATION, KEY_RING, CRYPTO_KEY, VERSION, - 'DISABLED')) - assert expected in out - - -def test_enable_crypto_key_version(capsys): - snippets.enable_crypto_key_version( - PROJECT, LOCATION, KEY_RING, CRYPTO_KEY, VERSION) - out, _ = capsys.readouterr() - expected = ( - 'CryptoKeyVersion projects/{}/locations/{}/keyRings/{}/cryptoKeys/{}/' - 'cryptoKeyVersions/{}\'s state has been set to {}.' - .format( - PROJECT, LOCATION, KEY_RING, CRYPTO_KEY, VERSION, - 'ENABLED')) - assert expected in out - - -def test_destroy_crypto_key_version(capsys): - snippets.destroy_crypto_key_version( - PROJECT, LOCATION, KEY_RING, CRYPTO_KEY, VERSION) - out, _ = capsys.readouterr() - expected = ( - 'CryptoKeyVersion projects/{}/locations/{}/keyRings/{}/cryptoKeys/{}/' - 'cryptoKeyVersions/{}\'s state has been set to {}.' - .format( - PROJECT, LOCATION, KEY_RING, CRYPTO_KEY, VERSION, - 'DESTROY_SCHEDULED')) - assert expected in out - - -def test_restore_crypto_key_version(capsys): - snippets.restore_crypto_key_version( - PROJECT, LOCATION, KEY_RING, CRYPTO_KEY, VERSION) - out, _ = capsys.readouterr() - expected = ( - 'CryptoKeyVersion projects/{}/locations/{}/keyRings/{}/cryptoKeys/{}/' - 'cryptoKeyVersions/{}\'s state has been set to {}.' - .format( - PROJECT, LOCATION, KEY_RING, CRYPTO_KEY, VERSION, - 'DISABLED')) - assert expected in out - - -def test_add_member_to_crypto_key_policy(capsys): - snippets.add_member_to_crypto_key_policy( - PROJECT, LOCATION, KEY_RING, CRYPTO_KEY, MEMBER, ROLE) - out, _ = capsys.readouterr() - expected = ( - 'Member {} added with role {} to policy for CryptoKey {} in KeyRing {}' - .format(MEMBER, ROLE, CRYPTO_KEY, KEY_RING)) - assert expected in out - - kms_client = googleapiclient.discovery.build('cloudkms', 'v1') - parent = 'projects/{}/locations/{}/keyRings/{}/cryptoKeys/{}'.format( - PROJECT, LOCATION, KEY_RING, CRYPTO_KEY) - crypto_keys = kms_client.projects().locations().keyRings().cryptoKeys() - policy_request = crypto_keys.getIamPolicy(resource=parent) - policy_response = policy_request.execute() - assert 'bindings' in policy_response.keys() - bindings = policy_response['bindings'] - found_member_role_pair = False - for binding in bindings: - if binding['role'] == ROLE: - for user in binding['members']: - if user == MEMBER: - found_member_role_pair = True - assert found_member_role_pair - - -def test_get_key_ring_policy(capsys): - snippets.get_key_ring_policy(PROJECT, LOCATION, KEY_RING) - out, _ = capsys.readouterr() - expected_roles_exist = ( - 'Printing IAM policy for resource projects/{}/locations/{}/keyRings/{}' - ':'.format(PROJECT, LOCATION, KEY_RING)) - expected_no_roles = ( - 'No roles found for resource projects/{}/locations/{}/keyRings/{}.' - .format(PROJECT, LOCATION, KEY_RING)) - assert (expected_roles_exist in out) or (expected_no_roles in out) + +def create_key_helper(key_id, purpose, algorithm, t): + try: + client = kms_v1.KeyManagementServiceClient() + parent = client.key_ring_path(t.project_id, t.location, t.keyring_id) + + crypto_key = {'purpose': purpose, + 'version_template': {'algorithm': algorithm}} + client.create_crypto_key(parent, key_id, crypto_key) + return True + except GoogleAPICallError: + # key already exists + return False + + +def setup_module(module): + """ + Set up keys in project if needed + """ + t = TestKMSSnippets() + try: + # create keyring + snippets.create_key_ring(t.project_id, t.location, t.keyring_id) + except GoogleAPICallError: + # keyring already exists + pass + s = create_key_helper(t.symId, + enums.CryptoKey.CryptoKeyPurpose.ENCRYPT_DECRYPT, + enums.CryptoKeyVersion.CryptoKeyVersionAlgorithm. + GOOGLE_SYMMETRIC_ENCRYPTION, + t) + if s: + # leave time for key to initialize + time.sleep(20) + + +class TestKMSSnippets: + project_id = environ['GCLOUD_PROJECT'] + keyring_id = 'kms-samples' + location = 'global' + parent = 'projects/{}/locations/{}'.format(project_id, location) + keyring_path = '{}/keyRings/{}'.format(parent, keyring_id) + version = '1' + + symId = 'symmetric' + + sym = '{}/cryptoKeys/{}'.format(keyring_path, symId) + sym_version = '{}/cryptoKeyVersions/{}'.format(sym, version) + + message = 'test message 123' + message_bytes = message.encode('utf-8') + + member = 'group:test@google.com' + role = 'roles/viewer' + + @pytest.mark.skip(reason="There's currently no method to delete keyrings, \ + so we should avoid creating resources") + def test_create_key_ring(self): + ring_id = self.keyring_id + '-testcreate' + str(int(time.time())) + snippets.create_key_ring(self.project_id, self.location, ring_id) + client = kms_v1.KeyManagementServiceClient() + result = client.get_key_ring(client.key_ring_path(self.project_id, + self.location, + ring_id)) + assert ring_id in result.name + + @pytest.mark.skip(reason="Deleting keys isn't instant, so we should avoid \ + creating a large number of them in our tests") + def test_create_crypto_key(self): + key_id = self.symId + '-test' + str(int(time.time())) + snippets.create_crypto_key(self.project_id, self.location, + self.keyring_id, key_id) + c = kms_v1.KeyManagementServiceClient() + result = c.get_crypto_key(c.crypto_key_path(self.project_id, + self.location, + self.keyring_id, + key_id)) + assert key_id in result.name + + # tests disable/enable/destroy/restore + def test_key_change_version_state(self): + client = kms_v1.KeyManagementServiceClient() + name = client.crypto_key_version_path(self.project_id, self.location, + self.keyring_id, self.symId, + self.version) + state_enum = enums.CryptoKeyVersion.CryptoKeyVersionState + # test disable + snippets.disable_crypto_key_version(self.project_id, self.location, + self.keyring_id, self.symId, + self.version) + response = client.get_crypto_key_version(name) + assert response.state == state_enum.DISABLED + # test destroy + snippets.destroy_crypto_key_version(self.project_id, self.location, + self.keyring_id, self.symId, + self.version) + response = client.get_crypto_key_version(name) + assert response.state == state_enum.DESTROY_SCHEDULED + # test restore + snippets.restore_crypto_key_version(self.project_id, self.location, + self.keyring_id, self.symId, + self.version) + response = client.get_crypto_key_version(name) + assert response.state == state_enum.DISABLED + # test re-enable + snippets.enable_crypto_key_version(self.project_id, self.location, + self.keyring_id, self.symId, + self.version) + response = client.get_crypto_key_version(name) + assert response.state == state_enum.ENABLED + + def test_get_ring_policy(self): + policy = snippets.get_key_ring_policy(self.project_id, + self.location, self.keyring_id) + assert type(policy) is Policy + + # tests get/add/remove policy members + def test_ring_policy(self): + # add member + snippets.add_member_to_key_ring_policy(self.project_id, self.location, + self.keyring_id, self.member, + self.role) + policy = snippets.get_key_ring_policy(self.project_id, + self.location, self.keyring_id) + found = False + for b in list(policy.bindings): + if b.role == self.role and self.member in b.members: + found = True + assert found + # remove member + snippets.remove_member_from_key_ring_policy(self.project_id, + self.location, + self.keyring_id, + self.member, + self.role) + policy = snippets.get_key_ring_policy(self.project_id, + self.location, self.keyring_id) + found = False + for b in list(policy.bindings): + if b.role == self.role and self.member in b.members: + found = True + assert not found + + # tests get/add/remove policy members + def test_key_policy(self): + # add member + snippets.add_member_to_crypto_key_policy(self.project_id, + self.location, + self.keyring_id, + self.symId, + self.member, + self.role) + policy = snippets.get_crypto_key_policy(self.project_id, + self.location, + self.keyring_id, + self.symId) + found = False + for b in list(policy.bindings): + if b.role == self.role and self.member in b.members: + found = True + assert found + # remove member + snippets.remove_member_from_crypto_key_policy(self.project_id, + self.location, + self.keyring_id, + self.symId, + self.member, + self.role) + policy = snippets.get_crypto_key_policy(self.project_id, + self.location, + self.keyring_id, + self.symId) + found = False + for b in list(policy.bindings): + if b.role == self.role and self.member in b.members: + found = True + assert not found + + def test_symmetric_encrypt_decrypt(self): + cipher_bytes = snippets.encrypt_symmetric(self.project_id, + self.location, + self.keyring_id, + self.symId, + self.message_bytes) + plain_bytes = snippets.decrypt_symmetric(self.project_id, + self.location, + self.keyring_id, + self.symId, + cipher_bytes) + assert plain_bytes == self.message_bytes + assert cipher_bytes != self.message_bytes + plaintext = plain_bytes.decode("utf-8") + assert plaintext == self.message From 6f2c0dcf85f27755c644513de53b7a76bb910250 Mon Sep 17 00:00:00 2001 From: DPEBot Date: Wed, 6 Feb 2019 12:06:35 -0800 Subject: [PATCH 033/136] Auto-update dependencies. [(#1980)](https://github.com/GoogleCloudPlatform/python-docs-samples/issues/1980) * Auto-update dependencies. * Update requirements.txt * Update requirements.txt --- kms/snippets/requirements.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kms/snippets/requirements.txt b/kms/snippets/requirements.txt index 74f7afd79000..3c8d13c9ce02 100644 --- a/kms/snippets/requirements.txt +++ b/kms/snippets/requirements.txt @@ -1,2 +1,2 @@ -google-cloud-kms==0.2 -cryptography==2.4.2 +google-cloud-kms==0.2.1 +cryptography==2.5 From ac7a0aa67b8d044d0c98edd599bc4899b8cc79fa Mon Sep 17 00:00:00 2001 From: Charles Engelke Date: Thu, 13 Jun 2019 14:20:59 -0700 Subject: [PATCH 034/136] Move import statements into tagged regions [(#2219)](https://github.com/GoogleCloudPlatform/python-docs-samples/issues/2219) * Move import statements into tagged regions So they will show up in context on web pages. * Flake8 didn't like needless enums imports I have to admit, it's right. It's clearer now. --- kms/snippets/snippets.py | 35 +++++++++++++++++++++++++++++++---- 1 file changed, 31 insertions(+), 4 deletions(-) diff --git a/kms/snippets/snippets.py b/kms/snippets/snippets.py index 07b027051913..d4209e6b18fb 100644 --- a/kms/snippets/snippets.py +++ b/kms/snippets/snippets.py @@ -14,14 +14,12 @@ # See the License for the specific language governing permissions and -from google.cloud import kms_v1 -from google.cloud.kms_v1 import enums - - # [START kms_create_keyring] def create_key_ring(project_id, location_id, key_ring_id): """Creates a KeyRing in the given location (e.g. global).""" + from google.cloud import kms_v1 + # Creates an API client for the KMS API. client = kms_v1.KeyManagementServiceClient() @@ -44,6 +42,9 @@ def create_key_ring(project_id, location_id, key_ring_id): def create_crypto_key(project_id, location_id, key_ring_id, crypto_key_id): """Creates a CryptoKey within a KeyRing in the given location.""" + from google.cloud import kms_v1 + from google.cloud.kms_v1 import enums + # Creates an API client for the KMS API. client = kms_v1.KeyManagementServiceClient() @@ -67,6 +68,8 @@ def encrypt_symmetric(project_id, location_id, key_ring_id, crypto_key_id, plaintext): """Encrypts input plaintext data using the provided symmetric CryptoKey.""" + from google.cloud import kms_v1 + # Creates an API client for the KMS API. client = kms_v1.KeyManagementServiceClient() @@ -85,6 +88,8 @@ def decrypt_symmetric(project_id, location_id, key_ring_id, crypto_key_id, ciphertext): """Decrypts input ciphertext using the provided symmetric CryptoKey.""" + from google.cloud import kms_v1 + # Creates an API client for the KMS API. client = kms_v1.KeyManagementServiceClient() @@ -103,6 +108,9 @@ def disable_crypto_key_version(project_id, location_id, key_ring_id, """Disables a CryptoKeyVersion associated with a given CryptoKey and KeyRing.""" + from google.cloud import kms_v1 + from google.cloud.kms_v1 import enums + # Creates an API client for the KMS API. client = kms_v1.KeyManagementServiceClient() @@ -128,6 +136,9 @@ def enable_crypto_key_version(project_id, location_id, key_ring_id, """Enables a CryptoKeyVersion associated with a given CryptoKey and KeyRing.""" + from google.cloud import kms_v1 + from google.cloud.kms_v1 import enums + # Creates an API client for the KMS API. client = kms_v1.KeyManagementServiceClient() @@ -153,6 +164,8 @@ def destroy_crypto_key_version( """Schedules a CryptoKeyVersion associated with a given CryptoKey and KeyRing for destruction 24 hours in the future.""" + from google.cloud import kms_v1 + # Creates an API client for the KMS API. client = kms_v1.KeyManagementServiceClient() @@ -174,6 +187,8 @@ def restore_crypto_key_version( project_id, location_id, key_ring_id, crypto_key_id, version_id): """Restores a CryptoKeyVersion that is scheduled for destruction.""" + from google.cloud import kms_v1 + # Creates an API client for the KMS API. client = kms_v1.KeyManagementServiceClient() @@ -198,6 +213,8 @@ def add_member_to_crypto_key_policy( """Adds a member with a given role to the Identity and Access Management (IAM) policy for a given CryptoKey associated with a KeyRing.""" + from google.cloud import kms_v1 + # Creates an API client for the KMS API. client = kms_v1.KeyManagementServiceClient() @@ -227,6 +244,8 @@ def add_member_to_key_ring_policy( """Adds a member with a given role to the Identity and Access Management (IAM) policy for a given KeyRing.""" + from google.cloud import kms_v1 + # Creates an API client for the KMS API. client = kms_v1.KeyManagementServiceClient() @@ -257,6 +276,8 @@ def remove_member_from_crypto_key_policy( """Removes a member with a given role from the Identity and Access Management (IAM) policy for a given CryptoKey associated with a KeyRing.""" + from google.cloud import kms_v1 + # Creates an API client for the KMS API. client = kms_v1.KeyManagementServiceClient() @@ -285,6 +306,8 @@ def remove_member_from_key_ring_policy(project_id, location_id, key_ring_id, """Removes a member with a given role from the Identity and Access Management (IAM) policy for a given KeyRing.""" + from google.cloud import kms_v1 + # Creates an API client for the KMS API. client = kms_v1.KeyManagementServiceClient() @@ -312,6 +335,8 @@ def get_key_ring_policy(project_id, location_id, key_ring_id): """Gets the Identity and Access Management (IAM) policy for a given KeyRing and prints out roles and the members assigned to those roles.""" + from google.cloud import kms_v1 + # Creates an API client for the KMS API. client = kms_v1.KeyManagementServiceClient() @@ -334,6 +359,8 @@ def get_crypto_key_policy(project_id, location_id, key_ring_id, crypto_key_id): """Gets the Identity and Access Management (IAM) policy for a given KeyRing and prints out roles and the members assigned to those roles.""" + from google.cloud import kms_v1 + # Creates an API client for the KMS API. client = kms_v1.KeyManagementServiceClient() From 821e6aa6790c4aac53239fc13f0bc8d8d0c7f12a Mon Sep 17 00:00:00 2001 From: Gus Class Date: Tue, 8 Oct 2019 09:53:32 -0700 Subject: [PATCH 035/136] Adds split updates for Firebase ... opencensus [(#2438)](https://github.com/GoogleCloudPlatform/python-docs-samples/issues/2438) --- kms/snippets/requirements.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kms/snippets/requirements.txt b/kms/snippets/requirements.txt index 3c8d13c9ce02..efc7be5ee0d2 100644 --- a/kms/snippets/requirements.txt +++ b/kms/snippets/requirements.txt @@ -1,2 +1,2 @@ -google-cloud-kms==0.2.1 -cryptography==2.5 +google-cloud-kms==1.2.1 +cryptography==2.7 From ef44d0942a3b112aef2ca2397742e3c04348a915 Mon Sep 17 00:00:00 2001 From: DPEBot Date: Fri, 20 Dec 2019 17:41:38 -0800 Subject: [PATCH 036/136] Auto-update dependencies. [(#2005)](https://github.com/GoogleCloudPlatform/python-docs-samples/issues/2005) * Auto-update dependencies. * Revert update of appengine/flexible/datastore. * revert update of appengine/flexible/scipy * revert update of bigquery/bqml * revert update of bigquery/cloud-client * revert update of bigquery/datalab-migration * revert update of bigtable/quickstart * revert update of compute/api * revert update of container_registry/container_analysis * revert update of dataflow/run_template * revert update of datastore/cloud-ndb * revert update of dialogflow/cloud-client * revert update of dlp * revert update of functions/imagemagick * revert update of functions/ocr/app * revert update of healthcare/api-client/fhir * revert update of iam/api-client * revert update of iot/api-client/gcs_file_to_device * revert update of iot/api-client/mqtt_example * revert update of language/automl * revert update of run/image-processing * revert update of vision/automl * revert update testing/requirements.txt * revert update of vision/cloud-client/detect * revert update of vision/cloud-client/product_search * revert update of jobs/v2/api_client * revert update of jobs/v3/api_client * revert update of opencensus * revert update of translate/cloud-client * revert update to speech/cloud-client Co-authored-by: Kurtis Van Gent <31518063+kurtisvg@users.noreply.github.com> Co-authored-by: Doug Mahugh --- kms/snippets/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kms/snippets/requirements.txt b/kms/snippets/requirements.txt index efc7be5ee0d2..a9b47ef6ccae 100644 --- a/kms/snippets/requirements.txt +++ b/kms/snippets/requirements.txt @@ -1,2 +1,2 @@ google-cloud-kms==1.2.1 -cryptography==2.7 +cryptography==2.8 From eecdc663879ca8aa5e66cac7b058cdef0b876eb5 Mon Sep 17 00:00:00 2001 From: WhiteSource Renovate Date: Mon, 30 Mar 2020 20:48:20 +0200 Subject: [PATCH 037/136] chore(deps): update dependency google-cloud-kms to v1.3.0 [(#3160)](https://github.com/GoogleCloudPlatform/python-docs-samples/issues/3160) --- kms/snippets/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kms/snippets/requirements.txt b/kms/snippets/requirements.txt index a9b47ef6ccae..81377367ece9 100644 --- a/kms/snippets/requirements.txt +++ b/kms/snippets/requirements.txt @@ -1,2 +1,2 @@ -google-cloud-kms==1.2.1 +google-cloud-kms==1.3.0 cryptography==2.8 From 2dd03082df1052805caee32a31ee934a9e097366 Mon Sep 17 00:00:00 2001 From: Kurtis Van Gent <31518063+kurtisvg@users.noreply.github.com> Date: Wed, 1 Apr 2020 19:11:50 -0700 Subject: [PATCH 038/136] Simplify noxfile setup. [(#2806)](https://github.com/GoogleCloudPlatform/python-docs-samples/issues/2806) * chore(deps): update dependency requests to v2.23.0 * Simplify noxfile and add version control. * Configure appengine/standard to only test Python 2.7. * Update Kokokro configs to match noxfile. * Add requirements-test to each folder. * Remove Py2 versions from everything execept appengine/standard. * Remove conftest.py. * Remove appengine/standard/conftest.py * Remove 'no-sucess-flaky-report' from pytest.ini. * Add GAE SDK back to appengine/standard tests. * Fix typo. * Roll pytest to python 2 version. * Add a bunch of testing requirements. * Remove typo. * Add appengine lib directory back in. * Add some additional requirements. * Fix issue with flake8 args. * Even more requirements. * Readd appengine conftest.py. * Add a few more requirements. * Even more Appengine requirements. * Add webtest for appengine/standard/mailgun. * Add some additional requirements. * Add workaround for issue with mailjet-rest. * Add responses for appengine/standard/mailjet. Co-authored-by: Renovate Bot --- kms/snippets/quickstart_test.py | 2 +- kms/snippets/requirements-test.txt | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) create mode 100644 kms/snippets/requirements-test.txt diff --git a/kms/snippets/quickstart_test.py b/kms/snippets/quickstart_test.py index 0db901e6bf3e..5a457518c8fb 100644 --- a/kms/snippets/quickstart_test.py +++ b/kms/snippets/quickstart_test.py @@ -13,7 +13,7 @@ # limitations under the License. -def test_quickstart(api_client_inject_project_id): +def test_quickstart(): import quickstart quickstart.run_quickstart() diff --git a/kms/snippets/requirements-test.txt b/kms/snippets/requirements-test.txt new file mode 100644 index 000000000000..781d4326c947 --- /dev/null +++ b/kms/snippets/requirements-test.txt @@ -0,0 +1 @@ +pytest==5.3.2 From 6f8f31de2c61ba9ae3eec745a1074b947b9c55d1 Mon Sep 17 00:00:00 2001 From: Daniel Sanche Date: Tue, 7 Apr 2020 11:43:56 -0700 Subject: [PATCH 039/136] [kms] fix flaky test [(#3268)](https://github.com/GoogleCloudPlatform/python-docs-samples/issues/3268) --- kms/snippets/requirements-test.txt | 2 + kms/snippets/snippets_test.py | 99 +++++++++++++++++------------- 2 files changed, 59 insertions(+), 42 deletions(-) diff --git a/kms/snippets/requirements-test.txt b/kms/snippets/requirements-test.txt index 781d4326c947..758bc040f3a8 100644 --- a/kms/snippets/requirements-test.txt +++ b/kms/snippets/requirements-test.txt @@ -1 +1,3 @@ pytest==5.3.2 +gcp-devrel-py-tools==0.0.15 +google-cloud-core diff --git a/kms/snippets/snippets_test.py b/kms/snippets/snippets_test.py index 9da03d9c5f2b..9b2c7ad462a8 100644 --- a/kms/snippets/snippets_test.py +++ b/kms/snippets/snippets_test.py @@ -16,7 +16,7 @@ import time from os import environ -from google.api_core.exceptions import GoogleAPICallError +from google.api_core.exceptions import Aborted, GoogleAPICallError from google.cloud import kms_v1 from google.cloud.kms_v1 import enums from google.iam.v1.policy_pb2 import Policy @@ -25,6 +25,8 @@ import snippets +from gcp_devrel.testing import eventually_consistent + def create_key_helper(key_id, purpose, algorithm, t): try: @@ -51,7 +53,7 @@ def setup_module(module): except GoogleAPICallError: # keyring already exists pass - s = create_key_helper(t.symId, + s = create_key_helper(t.sym_id, enums.CryptoKey.CryptoKeyPurpose.ENCRYPT_DECRYPT, enums.CryptoKeyVersion.CryptoKeyVersionAlgorithm. GOOGLE_SYMMETRIC_ENCRYPTION, @@ -69,9 +71,9 @@ class TestKMSSnippets: keyring_path = '{}/keyRings/{}'.format(parent, keyring_id) version = '1' - symId = 'symmetric' + sym_id = 'symmetric' - sym = '{}/cryptoKeys/{}'.format(keyring_path, symId) + sym = '{}/cryptoKeys/{}'.format(keyring_path, sym_id) sym_version = '{}/cryptoKeyVersions/{}'.format(sym, version) message = 'test message 123' @@ -94,7 +96,7 @@ def test_create_key_ring(self): @pytest.mark.skip(reason="Deleting keys isn't instant, so we should avoid \ creating a large number of them in our tests") def test_create_crypto_key(self): - key_id = self.symId + '-test' + str(int(time.time())) + key_id = self.sym_id + '-test' + str(int(time.time())) snippets.create_crypto_key(self.project_id, self.location, self.keyring_id, key_id) c = kms_v1.KeyManagementServiceClient() @@ -108,30 +110,30 @@ def test_create_crypto_key(self): def test_key_change_version_state(self): client = kms_v1.KeyManagementServiceClient() name = client.crypto_key_version_path(self.project_id, self.location, - self.keyring_id, self.symId, + self.keyring_id, self.sym_id, self.version) state_enum = enums.CryptoKeyVersion.CryptoKeyVersionState # test disable snippets.disable_crypto_key_version(self.project_id, self.location, - self.keyring_id, self.symId, + self.keyring_id, self.sym_id, self.version) response = client.get_crypto_key_version(name) assert response.state == state_enum.DISABLED # test destroy snippets.destroy_crypto_key_version(self.project_id, self.location, - self.keyring_id, self.symId, + self.keyring_id, self.sym_id, self.version) response = client.get_crypto_key_version(name) assert response.state == state_enum.DESTROY_SCHEDULED # test restore snippets.restore_crypto_key_version(self.project_id, self.location, - self.keyring_id, self.symId, + self.keyring_id, self.sym_id, self.version) response = client.get_crypto_key_version(name) assert response.state == state_enum.DISABLED # test re-enable snippets.enable_crypto_key_version(self.project_id, self.location, - self.keyring_id, self.symId, + self.keyring_id, self.sym_id, self.version) response = client.get_crypto_key_version(name) assert response.state == state_enum.ENABLED @@ -171,48 +173,61 @@ def test_ring_policy(self): # tests get/add/remove policy members def test_key_policy(self): # add member - snippets.add_member_to_crypto_key_policy(self.project_id, - self.location, - self.keyring_id, - self.symId, - self.member, - self.role) - policy = snippets.get_crypto_key_policy(self.project_id, - self.location, - self.keyring_id, - self.symId) - found = False - for b in list(policy.bindings): - if b.role == self.role and self.member in b.members: - found = True - assert found + snippets.add_member_to_crypto_key_policy( + self.project_id, + self.location, + self.keyring_id, + self.sym_id, + self.member, + self.role) + + def check_policy(): + policy = snippets.get_crypto_key_policy( + self.project_id, + self.location, + self.keyring_id, + self.sym_id) + found = False + for b in list(policy.bindings): + if b.role == self.role and self.member in b.members: + found = True + assert found + eventually_consistent.call(check_policy, + exceptions=(Aborted, AssertionError)) # remove member - snippets.remove_member_from_crypto_key_policy(self.project_id, - self.location, - self.keyring_id, - self.symId, - self.member, - self.role) - policy = snippets.get_crypto_key_policy(self.project_id, - self.location, - self.keyring_id, - self.symId) - found = False - for b in list(policy.bindings): - if b.role == self.role and self.member in b.members: - found = True - assert not found + snippets.remove_member_from_crypto_key_policy( + self.project_id, + self.location, + self.keyring_id, + self.sym_id, + self.member, + self.role) + + def check_policy(): + policy = snippets.get_crypto_key_policy( + self.project_id, + self.location, + self.keyring_id, + self.sym_id) + found = False + for b in list(policy.bindings): + if b.role == self.role and self.member in b.members: + found = True + assert not found + eventually_consistent.call( + check_policy, + exceptions=(Aborted, AssertionError)) def test_symmetric_encrypt_decrypt(self): cipher_bytes = snippets.encrypt_symmetric(self.project_id, self.location, self.keyring_id, - self.symId, + self.sym_id, self.message_bytes) plain_bytes = snippets.decrypt_symmetric(self.project_id, self.location, self.keyring_id, - self.symId, + self.sym_id, cipher_bytes) assert plain_bytes == self.message_bytes assert cipher_bytes != self.message_bytes From 966796aeebdc9fb16d6df3e75899426ad5ed2aa2 Mon Sep 17 00:00:00 2001 From: WhiteSource Renovate Date: Tue, 21 Apr 2020 03:44:04 +0200 Subject: [PATCH 040/136] Update dependency google-cloud-kms to v1.4.0 [(#3410)](https://github.com/GoogleCloudPlatform/python-docs-samples/issues/3410) This PR contains the following updates: | Package | Update | Change | |---|---|---| | [google-cloud-kms](https://togithub.com/googleapis/python-kms) | minor | `==1.3.0` -> `==1.4.0` | --- ### Release Notes
googleapis/python-kms ### [`v1.4.0`](https://togithub.com/googleapis/python-kms/blob/master/CHANGELOG.md#​140-httpswwwgithubcomgoogleapispython-kmscomparev130v140-2020-04-14) [Compare Source](https://togithub.com/googleapis/python-kms/compare/v1.3.0...v1.4.0) ##### Features - add support for external key manager (via synth) ([#​8](https://www.github.com/googleapis/python-kms/issues/8)) ([4077fc8](https://www.github.com/googleapis/python-kms/commit/4077fc89943cc09d489d44c05efcf9cab61cdbaf))
--- ### Renovate configuration :date: **Schedule**: At any time (no schedule defined). :vertical_traffic_light: **Automerge**: Disabled by config. Please merge this manually once you are satisfied. :recycle: **Rebasing**: Never, or you tick the rebase/retry checkbox. :no_bell: **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] If you want to rebase/retry this PR, check this box --- This PR has been generated by [WhiteSource Renovate](https://renovate.whitesourcesoftware.com). View repository job log [here](https://app.renovatebot.com/dashboard#GoogleCloudPlatform/python-docs-samples). --- kms/snippets/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kms/snippets/requirements.txt b/kms/snippets/requirements.txt index 81377367ece9..c10519b98572 100644 --- a/kms/snippets/requirements.txt +++ b/kms/snippets/requirements.txt @@ -1,2 +1,2 @@ -google-cloud-kms==1.3.0 +google-cloud-kms==1.4.0 cryptography==2.8 From 5fb1511e5b57486d66fa694101e450448f31cc75 Mon Sep 17 00:00:00 2001 From: WhiteSource Renovate Date: Wed, 22 Apr 2020 06:14:10 +0200 Subject: [PATCH 041/136] chore(deps): update dependency cryptography to v2.9 [(#3266)](https://github.com/GoogleCloudPlatform/python-docs-samples/issues/3266) Co-authored-by: Leah E. Cole <6719667+leahecole@users.noreply.github.com> --- kms/snippets/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kms/snippets/requirements.txt b/kms/snippets/requirements.txt index c10519b98572..aaf2ea5f26ef 100644 --- a/kms/snippets/requirements.txt +++ b/kms/snippets/requirements.txt @@ -1,2 +1,2 @@ google-cloud-kms==1.4.0 -cryptography==2.8 +cryptography==2.9 From 48170cb9bcea0cea860d2c4dbbc30ecdce3f9828 Mon Sep 17 00:00:00 2001 From: Bu Sun Kim <8822365+busunkim96@users.noreply.github.com> Date: Wed, 22 Apr 2020 09:16:04 -0700 Subject: [PATCH 042/136] fix: use `crypto_key_path` instead of `crypto_key_path_path` [(#3319)](https://github.com/GoogleCloudPlatform/python-docs-samples/issues/3319) `crypto_key_path_path` was added to the library in error and will be removed in a future version of the library --- kms/snippets/snippets.py | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/kms/snippets/snippets.py b/kms/snippets/snippets.py index d4209e6b18fb..e09a3a799ace 100644 --- a/kms/snippets/snippets.py +++ b/kms/snippets/snippets.py @@ -74,8 +74,7 @@ def encrypt_symmetric(project_id, location_id, key_ring_id, crypto_key_id, client = kms_v1.KeyManagementServiceClient() # The resource name of the CryptoKey. - name = client.crypto_key_path_path(project_id, location_id, key_ring_id, - crypto_key_id) + name = client.crypto_key_path(project_id, location_id, key_ring_id, crypto_key_id) # Use the KMS API to encrypt the data. response = client.encrypt(name, plaintext) @@ -94,8 +93,7 @@ def decrypt_symmetric(project_id, location_id, key_ring_id, crypto_key_id, client = kms_v1.KeyManagementServiceClient() # The resource name of the CryptoKey. - name = client.crypto_key_path_path(project_id, location_id, key_ring_id, - crypto_key_id) + name = client.crypto_key_path(project_id, location_id, key_ring_id, crypto_key_id) # Use the KMS API to decrypt the data. response = client.decrypt(name, ciphertext) return response.plaintext @@ -219,8 +217,7 @@ def add_member_to_crypto_key_policy( client = kms_v1.KeyManagementServiceClient() # The resource name of the CryptoKey. - resource = client.crypto_key_path_path(project_id, location_id, - key_ring_id, crypto_key_id) + resource = client.crypto_key_path(project_id, location_id, key_ring_id, crypto_key_id) # Get the current IAM policy. policy = client.get_iam_policy(resource) @@ -282,8 +279,8 @@ def remove_member_from_crypto_key_policy( client = kms_v1.KeyManagementServiceClient() # The resource name of the CryptoKey. - resource = client.crypto_key_path_path(project_id, location_id, - key_ring_id, crypto_key_id) + resource = client.crypto_key_path(project_id, location_id, key_ring_id, crypto_key_id) + # Get the current IAM policy. policy = client.get_iam_policy(resource) @@ -365,8 +362,7 @@ def get_crypto_key_policy(project_id, location_id, key_ring_id, crypto_key_id): client = kms_v1.KeyManagementServiceClient() # The resource name of the CryptoKey. - resource = client.crypto_key_path_path(project_id, location_id, - key_ring_id, crypto_key_id) + resource = client.crypto_key_path(project_id, location_id, key_ring_id, crypto_key_id) # Get the current IAM policy. policy = client.get_iam_policy(resource) From 5c1926a930abd9672a8c4123ca8fcf31bc504cfc Mon Sep 17 00:00:00 2001 From: WhiteSource Renovate Date: Wed, 22 Apr 2020 21:07:11 +0200 Subject: [PATCH 043/136] chore(deps): update dependency cryptography to v2.9.1 [(#3463)](https://github.com/GoogleCloudPlatform/python-docs-samples/issues/3463) --- kms/snippets/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kms/snippets/requirements.txt b/kms/snippets/requirements.txt index aaf2ea5f26ef..19a906ab2712 100644 --- a/kms/snippets/requirements.txt +++ b/kms/snippets/requirements.txt @@ -1,2 +1,2 @@ google-cloud-kms==1.4.0 -cryptography==2.9 +cryptography==2.9.1 From e6944effdea853aeb64ef2d5f8898e319ac67f1c Mon Sep 17 00:00:00 2001 From: Takashi Matsuo Date: Thu, 23 Apr 2020 10:36:06 -0700 Subject: [PATCH 044/136] [kms] chore: remove gcp-devrel-py-tools [(#3479)](https://github.com/GoogleCloudPlatform/python-docs-samples/issues/3479) --- kms/snippets/requirements-test.txt | 3 +-- kms/snippets/snippets_test.py | 20 +++++++++++--------- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/kms/snippets/requirements-test.txt b/kms/snippets/requirements-test.txt index 758bc040f3a8..8855f3cf1f88 100644 --- a/kms/snippets/requirements-test.txt +++ b/kms/snippets/requirements-test.txt @@ -1,3 +1,2 @@ +backoff==1.10.0 pytest==5.3.2 -gcp-devrel-py-tools==0.0.15 -google-cloud-core diff --git a/kms/snippets/snippets_test.py b/kms/snippets/snippets_test.py index 9b2c7ad462a8..c5c34a281793 100644 --- a/kms/snippets/snippets_test.py +++ b/kms/snippets/snippets_test.py @@ -20,13 +20,11 @@ from google.cloud import kms_v1 from google.cloud.kms_v1 import enums from google.iam.v1.policy_pb2 import Policy - +import backoff import pytest import snippets -from gcp_devrel.testing import eventually_consistent - def create_key_helper(key_id, purpose, algorithm, t): try: @@ -181,6 +179,8 @@ def test_key_policy(self): self.member, self.role) + @backoff.on_exception( + backoff.expo, (Aborted, AssertionError), max_time=60) def check_policy(): policy = snippets.get_crypto_key_policy( self.project_id, @@ -192,8 +192,9 @@ def check_policy(): if b.role == self.role and self.member in b.members: found = True assert found - eventually_consistent.call(check_policy, - exceptions=(Aborted, AssertionError)) + + check_policy() + # remove member snippets.remove_member_from_crypto_key_policy( self.project_id, @@ -203,7 +204,9 @@ def check_policy(): self.member, self.role) - def check_policy(): + @backoff.on_exception( + backoff.expo, (Aborted, AssertionError), max_time=60) + def check_policy_again(): policy = snippets.get_crypto_key_policy( self.project_id, self.location, @@ -214,9 +217,8 @@ def check_policy(): if b.role == self.role and self.member in b.members: found = True assert not found - eventually_consistent.call( - check_policy, - exceptions=(Aborted, AssertionError)) + + check_policy_again() def test_symmetric_encrypt_decrypt(self): cipher_bytes = snippets.encrypt_symmetric(self.project_id, From c6a8bfa93fd09250b8642f6709022c656853c6e1 Mon Sep 17 00:00:00 2001 From: WhiteSource Renovate Date: Thu, 23 Apr 2020 22:47:42 +0200 Subject: [PATCH 045/136] Update dependency cryptography to v2.9.2 [(#3473)](https://github.com/GoogleCloudPlatform/python-docs-samples/issues/3473) --- kms/snippets/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kms/snippets/requirements.txt b/kms/snippets/requirements.txt index 19a906ab2712..6e2cc2a4558b 100644 --- a/kms/snippets/requirements.txt +++ b/kms/snippets/requirements.txt @@ -1,2 +1,2 @@ google-cloud-kms==1.4.0 -cryptography==2.9.1 +cryptography==2.9.2 From 9992fabe9916ab271613cfece3c2f0f3af130f4e Mon Sep 17 00:00:00 2001 From: Takashi Matsuo Date: Mon, 27 Apr 2020 17:31:46 -0700 Subject: [PATCH 046/136] [kms] fix: use unique ids for test [(#3563)](https://github.com/GoogleCloudPlatform/python-docs-samples/issues/3563) fixes #3554 fixes #3555 --- kms/snippets/snippets_test.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/kms/snippets/snippets_test.py b/kms/snippets/snippets_test.py index c5c34a281793..0b03bcda2193 100644 --- a/kms/snippets/snippets_test.py +++ b/kms/snippets/snippets_test.py @@ -15,6 +15,7 @@ import time from os import environ +import uuid from google.api_core.exceptions import Aborted, GoogleAPICallError from google.cloud import kms_v1 @@ -63,7 +64,7 @@ def setup_module(module): class TestKMSSnippets: project_id = environ['GCLOUD_PROJECT'] - keyring_id = 'kms-samples' + keyring_id = 'kms-samples-{}'.format(uuid.uuid4().hex) location = 'global' parent = 'projects/{}/locations/{}'.format(project_id, location) keyring_path = '{}/keyRings/{}'.format(parent, keyring_id) @@ -83,7 +84,7 @@ class TestKMSSnippets: @pytest.mark.skip(reason="There's currently no method to delete keyrings, \ so we should avoid creating resources") def test_create_key_ring(self): - ring_id = self.keyring_id + '-testcreate' + str(int(time.time())) + ring_id = self.keyring_id + '-test-create-{}'.format(uuid.uuid4().hex) snippets.create_key_ring(self.project_id, self.location, ring_id) client = kms_v1.KeyManagementServiceClient() result = client.get_key_ring(client.key_ring_path(self.project_id, @@ -94,7 +95,7 @@ def test_create_key_ring(self): @pytest.mark.skip(reason="Deleting keys isn't instant, so we should avoid \ creating a large number of them in our tests") def test_create_crypto_key(self): - key_id = self.sym_id + '-test' + str(int(time.time())) + key_id = self.sym_id + '-test-{}'.format(uuid.uuid4().hex) snippets.create_crypto_key(self.project_id, self.location, self.keyring_id, key_id) c = kms_v1.KeyManagementServiceClient() From c24b425ce74d700d5f30ee0f3c9e8dd6d4d530e2 Mon Sep 17 00:00:00 2001 From: Seth Vargo Date: Tue, 5 May 2020 18:46:19 -0400 Subject: [PATCH 047/136] Update and add Cloud KMS samples [(#3690)](https://github.com/GoogleCloudPlatform/python-docs-samples/issues/3690) This updates the Cloud KMS samples to match the format from the other 6 languages. It also updates the samples to note the workaround for https://github.com/googleapis/gapic-generator-python/issues/364. --- kms/snippets/README.rst | 16 +- kms/snippets/README.rst.in | 5 - kms/snippets/asymmetric.py | 219 ------- kms/snippets/asymmetric_test.py | 133 ---- kms/snippets/create_key_asymmetric_decrypt.py | 54 ++ kms/snippets/create_key_asymmetric_sign.py | 54 ++ kms/snippets/create_key_hsm.py | 56 ++ kms/snippets/create_key_labels.py | 58 ++ kms/snippets/create_key_ring.py | 46 ++ kms/snippets/create_key_rotation_schedule.py | 67 ++ .../create_key_symmetric_encrypt_decrypt.py | 54 ++ kms/snippets/create_key_version.py | 47 ++ kms/snippets/decrypt_asymmetric.py | 46 ++ kms/snippets/decrypt_symmetric.py | 45 ++ kms/snippets/destroy_key_version.py | 45 ++ kms/snippets/disable_key_version.py | 55 ++ kms/snippets/enable_key_version.py | 55 ++ kms/snippets/encrypt_asymmetric.py | 69 ++ kms/snippets/encrypt_symmetric.py | 51 ++ kms/snippets/get_key_labels.py | 48 ++ kms/snippets/get_key_version_attestation.py | 56 ++ kms/snippets/get_public_key.py | 45 ++ kms/snippets/iam_add_member.py | 56 ++ kms/snippets/iam_get_policy.py | 54 ++ kms/snippets/iam_remove_member.py | 57 ++ kms/snippets/quickstart.py | 52 +- kms/snippets/quickstart_test.py | 19 - kms/snippets/requirements-test.txt | 3 +- kms/snippets/restore_key_version.py | 45 ++ kms/snippets/sign_asymmetric.py | 64 ++ kms/snippets/snippets.py | 375 ----------- kms/snippets/snippets_test.py | 619 ++++++++++++------ kms/snippets/update_key_add_rotation.py | 62 ++ kms/snippets/update_key_remove_labels.py | 54 ++ kms/snippets/update_key_remove_rotation.py | 53 ++ kms/snippets/update_key_set_primary.py | 45 ++ kms/snippets/update_key_update_labels.py | 54 ++ kms/snippets/verify_asymmetric_ec.py | 72 ++ kms/snippets/verify_asymmetric_rsa.py | 73 +++ 39 files changed, 2069 insertions(+), 1012 deletions(-) delete mode 100644 kms/snippets/asymmetric.py delete mode 100644 kms/snippets/asymmetric_test.py create mode 100644 kms/snippets/create_key_asymmetric_decrypt.py create mode 100644 kms/snippets/create_key_asymmetric_sign.py create mode 100644 kms/snippets/create_key_hsm.py create mode 100644 kms/snippets/create_key_labels.py create mode 100644 kms/snippets/create_key_ring.py create mode 100644 kms/snippets/create_key_rotation_schedule.py create mode 100644 kms/snippets/create_key_symmetric_encrypt_decrypt.py create mode 100644 kms/snippets/create_key_version.py create mode 100644 kms/snippets/decrypt_asymmetric.py create mode 100644 kms/snippets/decrypt_symmetric.py create mode 100644 kms/snippets/destroy_key_version.py create mode 100644 kms/snippets/disable_key_version.py create mode 100644 kms/snippets/enable_key_version.py create mode 100644 kms/snippets/encrypt_asymmetric.py create mode 100644 kms/snippets/encrypt_symmetric.py create mode 100644 kms/snippets/get_key_labels.py create mode 100644 kms/snippets/get_key_version_attestation.py create mode 100644 kms/snippets/get_public_key.py create mode 100644 kms/snippets/iam_add_member.py create mode 100644 kms/snippets/iam_get_policy.py create mode 100644 kms/snippets/iam_remove_member.py delete mode 100644 kms/snippets/quickstart_test.py create mode 100644 kms/snippets/restore_key_version.py create mode 100644 kms/snippets/sign_asymmetric.py delete mode 100644 kms/snippets/snippets.py create mode 100644 kms/snippets/update_key_add_rotation.py create mode 100644 kms/snippets/update_key_remove_labels.py create mode 100644 kms/snippets/update_key_remove_rotation.py create mode 100644 kms/snippets/update_key_set_primary.py create mode 100644 kms/snippets/update_key_update_labels.py create mode 100644 kms/snippets/verify_asymmetric_ec.py create mode 100644 kms/snippets/verify_asymmetric_rsa.py diff --git a/kms/snippets/README.rst b/kms/snippets/README.rst index 17e34befaf0c..3acb00f5d913 100644 --- a/kms/snippets/README.rst +++ b/kms/snippets/README.rst @@ -77,20 +77,6 @@ To run this sample: $ python quickstart.py -Snippets -+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - -.. image:: https://gstatic.com/cloudssh/images/open-btn.png - :target: https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/GoogleCloudPlatform/python-docs-samples&page=editor&open_in_editor=kms/api-client/snippets.py,kms/api-client/README.rst - - - - -To run this sample: - -.. code-block:: bash - - $ python snippets.py -.. _Google Cloud SDK: https://cloud.google.com/sdk/ +.. _Google Cloud SDK: https://cloud.google.com/sdk/ \ No newline at end of file diff --git a/kms/snippets/README.rst.in b/kms/snippets/README.rst.in index f8aef3a243f7..cfd81fc800bd 100644 --- a/kms/snippets/README.rst.in +++ b/kms/snippets/README.rst.in @@ -15,10 +15,5 @@ setup: samples: - name: Quickstart file: quickstart.py -- name: Snippets - file: snippets.py - show_help: True -- name: Asymmetric - file: asymmetric.py folder: kms/api-client diff --git a/kms/snippets/asymmetric.py b/kms/snippets/asymmetric.py deleted file mode 100644 index 9c8abd15cc9b..000000000000 --- a/kms/snippets/asymmetric.py +++ /dev/null @@ -1,219 +0,0 @@ -#!/bin/python -# Copyright 2018 Google Inc. -# -# 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.rom googleapiclient import discovery - -import hashlib - -from cryptography.exceptions import InvalidSignature -from cryptography.hazmat.backends import default_backend -from cryptography.hazmat.primitives import hashes, serialization -from cryptography.hazmat.primitives.asymmetric import ec, padding, utils - -from google.cloud import kms_v1 -from google.cloud.kms_v1 import enums - - -# [START kms_create_asymmetric_key] -def create_asymmetric_key(project_id, location_id, key_ring_id, crypto_key_id): - """Creates an RSA encrypt/decrypt key pair within a specified KeyRing.""" - - # Creates an API client for the KMS API. - client = kms_v1.KeyManagementServiceClient() - - # The resource name of the KeyRing associated with the CryptoKey. - parent = client.key_ring_path(project_id, location_id, key_ring_id) - - # Create the CryptoKey object template - purpose = enums.CryptoKey.CryptoKeyPurpose.ASYMMETRIC_DECRYPT - algorithm = enums.CryptoKeyVersion.CryptoKeyVersionAlgorithm.\ - RSA_DECRYPT_OAEP_2048_SHA256 - crypto_key = {'purpose': purpose, - 'version_template': {'algorithm': algorithm}} - - # Create a CryptoKey for the given KeyRing. - response = client.create_crypto_key(parent, crypto_key_id, crypto_key) - - print('Created CryptoKey {}.'.format(response.name)) - return response -# [END kms_create_asymmetric_key] - - -# [START kms_get_asymmetric_public] -def get_asymmetric_public_key(key_name): - """ - Retrieves the public key from a saved asymmetric key pair on Cloud KMS - - Example key_name: - "projects/PROJECT_ID/locations/global/keyRings/RING_ID/cryptoKeys\ - /KEY_ID/cryptoKeyVersions/1" - - Requires: - cryptography.hazmat.backends.default_backend - cryptography.hazmat.primitives.serialization - """ - - client = kms_v1.KeyManagementServiceClient() - response = client.get_public_key(key_name) - - key_txt = response.pem.encode('ascii') - key = serialization.load_pem_public_key(key_txt, default_backend()) - return key -# [END kms_get_asymmetric_public] - - -# [START kms_decrypt_rsa] -def decrypt_rsa(ciphertext, key_name): - """ - Decrypt the input ciphertext (bytes) using an - 'RSA_DECRYPT_OAEP_2048_SHA256' private key stored on Cloud KMS - - Example key_name: - "projects/PROJECT_ID/locations/global/keyRings/RING_ID/cryptoKeys\ - /KEY_ID/cryptoKeyVersions/1" - """ - - client = kms_v1.KeyManagementServiceClient() - response = client.asymmetric_decrypt(key_name, ciphertext) - return response.plaintext -# [END kms_decrypt_rsa] - - -# [START kms_encrypt_rsa] -def encrypt_rsa(plaintext, key_name): - """ - Encrypt the input plaintext (bytes) locally using an - 'RSA_DECRYPT_OAEP_2048_SHA256' public key retrieved from Cloud KMS - - Example key_name: - "projects/PROJECT_ID/locations/global/keyRings/RING_ID/cryptoKeys\ - /KEY_ID/cryptoKeyVersions/1" - - Requires: - cryptography.hazmat.primitives.asymmetric.padding - cryptography.hazmat.primitives.hashes - """ - # get the public key - client = kms_v1.KeyManagementServiceClient() - response = client.get_public_key(key_name) - key_txt = response.pem.encode('ascii') - public_key = serialization.load_pem_public_key(key_txt, default_backend()) - - # encrypt plaintext - pad = padding.OAEP(mgf=padding.MGF1(algorithm=hashes.SHA256()), - algorithm=hashes.SHA256(), - label=None) - return public_key.encrypt(plaintext, pad) -# [END kms_encrypt_rsa] - - -# [START kms_sign_asymmetric] -def sign_asymmetric(message, key_name): - """ - Create a signature for a message using a private key stored on Cloud KMS - - Example key_name: - "projects/PROJECT_ID/locations/global/keyRings/RING_ID/cryptoKeys\ - /KEY_ID/cryptoKeyVersions/1" - - Requires: - hashlib - """ - # Note: some key algorithms will require a different hash function - # For example, EC_SIGN_P384_SHA384 requires SHA384 - client = kms_v1.KeyManagementServiceClient() - digest_bytes = hashlib.sha256(message).digest() - - digest_json = {'sha256': digest_bytes} - - response = client.asymmetric_sign(key_name, digest_json) - return response.signature -# [END kms_sign_asymmetric] - - -# [START kms_verify_signature_rsa] -def verify_signature_rsa(signature, message, key_name): - """ - Verify the validity of an 'RSA_SIGN_PSS_2048_SHA256' signature for the - specified message - - Example key_name: - "projects/PROJECT_ID/locations/global/keyRings/RING_ID/cryptoKeys\ - /KEY_ID/cryptoKeyVersions/1" - - Requires: - cryptography.exceptions.InvalidSignature - cryptography.hazmat.primitives.asymmetric.padding - cryptography.hazmat.primitives.asymmetric.utils - cryptography.hazmat.primitives.hashes - hashlib - """ - # get the public key - client = kms_v1.KeyManagementServiceClient() - response = client.get_public_key(key_name) - key_txt = response.pem.encode('ascii') - public_key = serialization.load_pem_public_key(key_txt, default_backend()) - - # get the digest of the message - digest_bytes = hashlib.sha256(message).digest() - - try: - # Attempt verification - public_key.verify(signature, - digest_bytes, - padding.PSS(mgf=padding.MGF1(hashes.SHA256()), - salt_length=32), - utils.Prehashed(hashes.SHA256())) - # No errors were thrown. Verification was successful - return True - except InvalidSignature: - return False -# [END kms_verify_signature_rsa] - - -# [START kms_verify_signature_ec] -def verify_signature_ec(signature, message, key_name): - """ - Verify the validity of an 'EC_SIGN_P256_SHA256' signature - for the specified message - - Example key_name: - "projects/PROJECT_ID/locations/global/keyRings/RING_ID/cryptoKeys\ - /KEY_ID/cryptoKeyVersions/1" - - Requires: - cryptography.exceptions.InvalidSignature - cryptography.hazmat.primitives.asymmetric.ec - cryptography.hazmat.primitives.asymmetric.utils - cryptography.hazmat.primitives.hashes - hashlib - """ - # get the public key - client = kms_v1.KeyManagementServiceClient() - response = client.get_public_key(key_name) - key_txt = response.pem.encode('ascii') - public_key = serialization.load_pem_public_key(key_txt, default_backend()) - - # get the digest of the message - digest_bytes = hashlib.sha256(message).digest() - - try: - # Attempt verification - public_key.verify(signature, - digest_bytes, - ec.ECDSA(utils.Prehashed(hashes.SHA256()))) - # No errors were thrown. Verification was successful - return True - except InvalidSignature: - return False -# [END kms_verify_signature_ec] diff --git a/kms/snippets/asymmetric_test.py b/kms/snippets/asymmetric_test.py deleted file mode 100644 index cc621003c475..000000000000 --- a/kms/snippets/asymmetric_test.py +++ /dev/null @@ -1,133 +0,0 @@ -#!/bin/python -# Copyright 2018 Google Inc. -# -# 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. - -from os import environ -from time import sleep - -import asymmetric - -from cryptography.hazmat.backends.openssl.ec import _EllipticCurvePublicKey -from cryptography.hazmat.backends.openssl.rsa import _RSAPublicKey - -from google.api_core.exceptions import GoogleAPICallError -from google.cloud.kms_v1 import enums - -from snippets import create_key_ring - -from snippets_test import create_key_helper - - -def setup_module(module): - """ - Set up keys in project if needed - """ - t = TestKMSAsymmetric() - try: - # create keyring - create_key_ring(t.project_id, t.location, t.keyring_id) - except GoogleAPICallError: - # keyring already exists - pass - s1 = create_key_helper(t.rsaDecryptId, - enums.CryptoKey.CryptoKeyPurpose.ASYMMETRIC_DECRYPT, - enums.CryptoKeyVersion.CryptoKeyVersionAlgorithm. - RSA_DECRYPT_OAEP_2048_SHA256, - t) - s2 = create_key_helper(t.rsaSignId, - enums.CryptoKey.CryptoKeyPurpose.ASYMMETRIC_SIGN, - enums.CryptoKeyVersion.CryptoKeyVersionAlgorithm. - RSA_SIGN_PSS_2048_SHA256, - t) - s3 = create_key_helper(t.ecSignId, - enums.CryptoKey.CryptoKeyPurpose.ASYMMETRIC_SIGN, - enums.CryptoKeyVersion.CryptoKeyVersionAlgorithm. - EC_SIGN_P256_SHA256, - t) - - if s1 or s2 or s3: - # leave time for keys to initialize - sleep(20) - - -class TestKMSAsymmetric: - project_id = environ['GCLOUD_PROJECT'] - keyring_id = 'kms-samples' - location = 'global' - parent = 'projects/{}/locations/{}'.format(project_id, location) - - rsaSignId = 'rsa-sign' - rsaDecryptId = 'rsa-decrypt' - ecSignId = 'ec-sign' - - rsaSign = '{}/keyRings/{}/cryptoKeys/{}/cryptoKeyVersions/1' \ - .format(parent, keyring_id, rsaSignId) - rsaDecrypt = '{}/keyRings/{}/cryptoKeys/{}/cryptoKeyVersions/1' \ - .format(parent, keyring_id, rsaDecryptId) - ecSign = '{}/keyRings/{}/cryptoKeys/{}/cryptoKeyVersions/1' \ - .format(parent, keyring_id, ecSignId) - - message = 'test message 123' - message_bytes = message.encode('utf-8') - - def test_get_public_key(self): - rsa_key = asymmetric.get_asymmetric_public_key(self.rsaDecrypt) - assert isinstance(rsa_key, _RSAPublicKey), 'expected RSA key' - rsa_key = asymmetric.get_asymmetric_public_key(self.rsaSign) - assert isinstance(rsa_key, _RSAPublicKey), 'expected RSA key' - ec_key = asymmetric.get_asymmetric_public_key(self.ecSign) - assert isinstance(ec_key, _EllipticCurvePublicKey), 'expected EC key' - - def test_rsa_encrypt_decrypt(self): - ciphertext = asymmetric.encrypt_rsa(self.message_bytes, - self.rsaDecrypt) - # signature should be 256 bytes for RSA 2048 - assert len(ciphertext) == 256, \ - 'ciphertext should be 256 chars; got {}'.format(len(ciphertext)) - plaintext_bytes = asymmetric.decrypt_rsa(ciphertext, - self.rsaDecrypt) - assert plaintext_bytes == self.message_bytes - plaintext = plaintext_bytes.decode('utf-8') - assert plaintext == self.message - - def test_rsa_sign_verify(self): - sig = asymmetric.sign_asymmetric(self.message_bytes, - self.rsaSign) - # signature should be 256 bytes for RSA 2048 - assert len(sig) == 256, \ - 'sig should be 256 chars; got {}'.format(len(sig)) - success = asymmetric.verify_signature_rsa(sig, - self.message_bytes, - self.rsaSign) - assert success is True, 'RSA verification failed' - changed_bytes = self.message_bytes + b'.' - success = asymmetric.verify_signature_rsa(sig, - changed_bytes, - self.rsaSign) - assert success is False, 'verify should fail with modified message' - - def test_ec_sign_verify(self): - sig = asymmetric.sign_asymmetric(self.message_bytes, - self.ecSign) - assert len(sig) > 50 and len(sig) < 300, \ - 'sig outside expected length range' - success = asymmetric.verify_signature_ec(sig, - self.message_bytes, - self.ecSign) - assert success is True, 'EC verification failed' - changed_bytes = self.message_bytes + b'.' - success = asymmetric.verify_signature_ec(sig, - changed_bytes, - self.ecSign) - assert success is False, 'verify should fail with modified message' diff --git a/kms/snippets/create_key_asymmetric_decrypt.py b/kms/snippets/create_key_asymmetric_decrypt.py new file mode 100644 index 000000000000..cac157958ebd --- /dev/null +++ b/kms/snippets/create_key_asymmetric_decrypt.py @@ -0,0 +1,54 @@ +# Copyright 2020 Google LLC +# +# 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 + + +# [START kms_create_key_asymmetric_decrypt] +def create_key_asymmetric_decrypt(project_id, location_id, key_ring_id, id): + """ + Creates a new asymmetric decryption key in Cloud KMS. + + Args: + project_id (string): Google Cloud project ID (e.g. 'my-project'). + location_id (string): Cloud KMS location (e.g. 'us-east1'). + key_ring_id (string): ID of the Cloud KMS key ring (e.g. 'my-key-ring'). + id (string): ID of the key to create (e.g. 'my-asymmetric-decrypt-key'). + + Returns: + CryptoKey: Cloud KMS key. + + """ + + # Import the client library. + from google.cloud import kms + + # Create the client. + client = kms.KeyManagementServiceClient() + + # Build the parent key ring name. + key_ring_name = client.key_ring_path(project_id, location_id, key_ring_id) + + # Build the key. + purpose = kms.enums.CryptoKey.CryptoKeyPurpose.ASYMMETRIC_DECRYPT + algorithm = kms.enums.CryptoKeyVersion.CryptoKeyVersionAlgorithm.RSA_DECRYPT_OAEP_2048_SHA256 + key = { + 'purpose': purpose, + 'version_template': { + 'algorithm': algorithm, + } + } + + # Call the API. + created_key = client.create_crypto_key(key_ring_name, id, key) + print('Created asymmetric decrypt key: {}'.format(created_key.name)) + return created_key +# [END kms_create_key_asymmetric_decrypt] diff --git a/kms/snippets/create_key_asymmetric_sign.py b/kms/snippets/create_key_asymmetric_sign.py new file mode 100644 index 000000000000..9bf18a7a996d --- /dev/null +++ b/kms/snippets/create_key_asymmetric_sign.py @@ -0,0 +1,54 @@ +# Copyright 2020 Google LLC +# +# 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 + + +# [START kms_create_key_asymmetric_sign] +def create_key_asymmetric_sign(project_id, location_id, key_ring_id, id): + """ + Creates a new asymmetric signing key in Cloud KMS. + + Args: + project_id (string): Google Cloud project ID (e.g. 'my-project'). + location_id (string): Cloud KMS location (e.g. 'us-east1'). + key_ring_id (string): ID of the Cloud KMS key ring (e.g. 'my-key-ring'). + id (string): ID of the key to create (e.g. 'my-asymmetric-signing-key'). + + Returns: + CryptoKey: Cloud KMS key. + + """ + + # Import the client library. + from google.cloud import kms + + # Create the client. + client = kms.KeyManagementServiceClient() + + # Build the parent key ring name. + key_ring_name = client.key_ring_path(project_id, location_id, key_ring_id) + + # Build the key. + purpose = kms.enums.CryptoKey.CryptoKeyPurpose.ASYMMETRIC_SIGN + algorithm = kms.enums.CryptoKeyVersion.CryptoKeyVersionAlgorithm.RSA_SIGN_PKCS1_2048_SHA256 + key = { + 'purpose': purpose, + 'version_template': { + 'algorithm': algorithm, + } + } + + # Call the API. + created_key = client.create_crypto_key(key_ring_name, id, key) + print('Created asymmetric signing key: {}'.format(created_key.name)) + return created_key +# [END kms_create_key_asymmetric_sign] diff --git a/kms/snippets/create_key_hsm.py b/kms/snippets/create_key_hsm.py new file mode 100644 index 000000000000..84ba37e5d00e --- /dev/null +++ b/kms/snippets/create_key_hsm.py @@ -0,0 +1,56 @@ +# Copyright 2020 Google LLC +# +# 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 + + +# [START kms_create_key_hsm] +def create_key_hsm(project_id, location_id, key_ring_id, id): + """ + Creates a new key in Cloud KMS backed by Cloud HSM. + + Args: + project_id (string): Google Cloud project ID (e.g. 'my-project'). + location_id (string): Cloud KMS location (e.g. 'us-east1'). + key_ring_id (string): ID of the Cloud KMS key ring (e.g. 'my-key-ring'). + id (string): ID of the key to create (e.g. 'my-hsm-key'). + + Returns: + CryptoKey: Cloud KMS key. + + """ + + # Import the client library. + from google.cloud import kms + + # Create the client. + client = kms.KeyManagementServiceClient() + + # Build the parent key ring name. + key_ring_name = client.key_ring_path(project_id, location_id, key_ring_id) + + # Build the key. + purpose = kms.enums.CryptoKey.CryptoKeyPurpose.ENCRYPT_DECRYPT + algorithm = kms.enums.CryptoKeyVersion.CryptoKeyVersionAlgorithm.GOOGLE_SYMMETRIC_ENCRYPTION + protection_level = kms.enums.ProtectionLevel.HSM + key = { + 'purpose': purpose, + 'version_template': { + 'algorithm': algorithm, + 'protection_level': protection_level + } + } + + # Call the API. + created_key = client.create_crypto_key(key_ring_name, id, key) + print('Created hsm key: {}'.format(created_key.name)) + return created_key +# [END kms_create_key_hsm] diff --git a/kms/snippets/create_key_labels.py b/kms/snippets/create_key_labels.py new file mode 100644 index 000000000000..e64a10cb955f --- /dev/null +++ b/kms/snippets/create_key_labels.py @@ -0,0 +1,58 @@ +# Copyright 2020 Google LLC +# +# 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 + + +# [START kms_create_key_labels] +def create_key_labels(project_id, location_id, key_ring_id, id): + """ + Creates a new key in Cloud KMS with labels. + + Args: + project_id (string): Google Cloud project ID (e.g. 'my-project'). + location_id (string): Cloud KMS location (e.g. 'us-east1'). + key_ring_id (string): ID of the Cloud KMS key ring (e.g. 'my-key-ring'). + id (string): ID of the key to create (e.g. 'my-labeled-key'). + + Returns: + CryptoKey: Cloud KMS key. + + """ + + # Import the client library. + from google.cloud import kms + + # Create the client. + client = kms.KeyManagementServiceClient() + + # Build the parent key ring name. + key_ring_name = client.key_ring_path(project_id, location_id, key_ring_id) + + # Build the key. + purpose = kms.enums.CryptoKey.CryptoKeyPurpose.ENCRYPT_DECRYPT + algorithm = kms.enums.CryptoKeyVersion.CryptoKeyVersionAlgorithm.GOOGLE_SYMMETRIC_ENCRYPTION + key = { + 'purpose': purpose, + 'version_template': { + 'algorithm': algorithm, + }, + 'labels': { + 'team': 'alpha', + 'cost_center': 'cc1234' + } + } + + # Call the API. + created_key = client.create_crypto_key(key_ring_name, id, key) + print('Created labeled key: {}'.format(created_key.name)) + return created_key +# [END kms_create_key_labels] diff --git a/kms/snippets/create_key_ring.py b/kms/snippets/create_key_ring.py new file mode 100644 index 000000000000..c01e8490516b --- /dev/null +++ b/kms/snippets/create_key_ring.py @@ -0,0 +1,46 @@ +# Copyright 2020 Google LLC +# +# 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 + + +# [START kms_create_key_ring] +def create_key_ring(project_id, location_id, id): + """ + Creates a new key ring in Cloud KMS + + Args: + project_id (string): Google Cloud project ID (e.g. 'my-project'). + location_id (string): Cloud KMS location (e.g. 'us-east1'). + id (string): ID of the key ring to create (e.g. 'my-key-ring'). + + Returns: + KeyRing: Cloud KMS key ring. + + """ + + # Import the client library. + from google.cloud import kms + + # Create the client. + client = kms.KeyManagementServiceClient() + + # Build the parent location name. + location_name = client.location_path(project_id, location_id) + + # Build the key ring. + key_ring = {} + + # Call the API. + created_key_ring = client.create_key_ring(location_name, id, key_ring) + print('Created key ring: {}'.format(created_key_ring.name)) + return created_key_ring +# [END kms_create_key_ring] diff --git a/kms/snippets/create_key_rotation_schedule.py b/kms/snippets/create_key_rotation_schedule.py new file mode 100644 index 000000000000..e6bbdb62d361 --- /dev/null +++ b/kms/snippets/create_key_rotation_schedule.py @@ -0,0 +1,67 @@ +# Copyright 2020 Google LLC +# +# 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 + + +# [START kms_create_key_rotation_schedule] +def create_key_rotation_schedule(project_id, location_id, key_ring_id, id): + """ + Creates a new key in Cloud KMS that automatically rotates. + + Args: + project_id (string): Google Cloud project ID (e.g. 'my-project'). + location_id (string): Cloud KMS location (e.g. 'us-east1'). + key_ring_id (string): ID of the Cloud KMS key ring (e.g. 'my-key-ring'). + id (string): ID of the key to create (e.g. 'my-rotating-key'). + + Returns: + CryptoKey: Cloud KMS key. + + """ + + # Import the client library. + from google.cloud import kms + + # Import time for getting the current time. + import time + + # Create the client. + client = kms.KeyManagementServiceClient() + + # Build the parent key ring name. + key_ring_name = client.key_ring_path(project_id, location_id, key_ring_id) + + # Build the key. + purpose = kms.enums.CryptoKey.CryptoKeyPurpose.ENCRYPT_DECRYPT + algorithm = kms.enums.CryptoKeyVersion.CryptoKeyVersionAlgorithm.GOOGLE_SYMMETRIC_ENCRYPTION + key = { + 'purpose': purpose, + 'version_template': { + 'algorithm': algorithm, + }, + + # Rotate the key every 30 days. + 'rotation_period': { + 'seconds': 60*60*24*30 + }, + + # Start the first rotation in 24 hours. + 'next_rotation_time': { + 'seconds': int(time.time()) + 60*60*24 + } + } + + # Call the API. + created_key = client.create_crypto_key(key_ring_name, id, key) + print('Created labeled key: {}'.format(created_key.name)) + return created_key +# [END kms_create_key_rotation_schedule] diff --git a/kms/snippets/create_key_symmetric_encrypt_decrypt.py b/kms/snippets/create_key_symmetric_encrypt_decrypt.py new file mode 100644 index 000000000000..54b9c5f40981 --- /dev/null +++ b/kms/snippets/create_key_symmetric_encrypt_decrypt.py @@ -0,0 +1,54 @@ +# Copyright 2020 Google LLC +# +# 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 + + +# [START kms_create_key_symmetric_encrypt_decrypt] +def create_key_symmetric_encrypt_decrypt(project_id, location_id, key_ring_id, id): + """ + Creates a new symmetric encryption/decryption key in Cloud KMS. + + Args: + project_id (string): Google Cloud project ID (e.g. 'my-project'). + location_id (string): Cloud KMS location (e.g. 'us-east1'). + key_ring_id (string): ID of the Cloud KMS key ring (e.g. 'my-key-ring'). + id (string): ID of the key to create (e.g. 'my-symmetric-key'). + + Returns: + CryptoKey: Cloud KMS key. + + """ + + # Import the client library. + from google.cloud import kms + + # Create the client. + client = kms.KeyManagementServiceClient() + + # Build the parent key ring name. + key_ring_name = client.key_ring_path(project_id, location_id, key_ring_id) + + # Build the key. + purpose = kms.enums.CryptoKey.CryptoKeyPurpose.ENCRYPT_DECRYPT + algorithm = kms.enums.CryptoKeyVersion.CryptoKeyVersionAlgorithm.GOOGLE_SYMMETRIC_ENCRYPTION + key = { + 'purpose': purpose, + 'version_template': { + 'algorithm': algorithm, + } + } + + # Call the API. + created_key = client.create_crypto_key(key_ring_name, id, key) + print('Created symmetric key: {}'.format(created_key.name)) + return created_key +# [END kms_create_key_symmetric_encrypt_decrypt] diff --git a/kms/snippets/create_key_version.py b/kms/snippets/create_key_version.py new file mode 100644 index 000000000000..9c84f808a943 --- /dev/null +++ b/kms/snippets/create_key_version.py @@ -0,0 +1,47 @@ +# Copyright 2020 Google LLC +# +# 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 + + +# [START kms_create_key_version] +def create_key_version(project_id, location_id, key_ring_id, key_id): + """ + Creates a new version of the given key. + + Args: + project_id (string): Google Cloud project ID (e.g. 'my-project'). + location_id (string): Cloud KMS location (e.g. 'us-east1'). + key_ring_id (string): ID of the Cloud KMS key ring (e.g. 'my-key-ring'). + key_id (string): ID of the key for which to create a new version (e.g. 'my-key'). + + Returns: + CryptoKeyVersion: Cloud KMS key version. + + """ + + # Import the client library. + from google.cloud import kms + + # Create the client. + client = kms.KeyManagementServiceClient() + + # Build the parent key name. + key_name = client.crypto_key_path(project_id, location_id, key_ring_id, key_id) + + # Build the key version. + version = {} + + # Call the API. + created_version = client.create_crypto_key_version(key_name, version) + print('Created key version: {}'.format(created_version.name)) + return created_version +# [END kms_create_key_version] diff --git a/kms/snippets/decrypt_asymmetric.py b/kms/snippets/decrypt_asymmetric.py new file mode 100644 index 000000000000..7b040cdd4203 --- /dev/null +++ b/kms/snippets/decrypt_asymmetric.py @@ -0,0 +1,46 @@ +# Copyright 2020 Google LLC +# +# 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 + + +# [START kms_decrypt_asymmetric] +def decrypt_asymmetric(project_id, location_id, key_ring_id, key_id, version_id, ciphertext): + """ + Decrypt the ciphertext using an asymmetric key. + + Args: + project_id (string): Google Cloud project ID (e.g. 'my-project'). + location_id (string): Cloud KMS location (e.g. 'us-east1'). + key_ring_id (string): ID of the Cloud KMS key ring (e.g. 'my-key-ring'). + key_id (string): ID of the key to use (e.g. 'my-key'). + version_id (string): ID of the key version to use (e.g. '1'). + ciphertext (bytes): Encrypted bytes to decrypt. + + Returns: + DecryptResponse: Response including plaintext. + + """ + + # Import the client library. + from google.cloud import kms + + # Create the client. + client = kms.KeyManagementServiceClient() + + # Build the key version name. + key_version_name = client.crypto_key_version_path(project_id, location_id, key_ring_id, key_id, version_id) + + # Call the API. + decrypt_response = client.asymmetric_decrypt(key_version_name, ciphertext) + print('Plaintext: {}'.format(decrypt_response.plaintext)) + return decrypt_response +# [END kms_decrypt_asymmetric] diff --git a/kms/snippets/decrypt_symmetric.py b/kms/snippets/decrypt_symmetric.py new file mode 100644 index 000000000000..a5cbe714279b --- /dev/null +++ b/kms/snippets/decrypt_symmetric.py @@ -0,0 +1,45 @@ +# Copyright 2020 Google LLC +# +# 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 + + +# [START kms_decrypt_symmetric] +def decrypt_symmetric(project_id, location_id, key_ring_id, key_id, ciphertext): + """ + Decrypt the ciphertext using the symmetric key + + Args: + project_id (string): Google Cloud project ID (e.g. 'my-project'). + location_id (string): Cloud KMS location (e.g. 'us-east1'). + key_ring_id (string): ID of the Cloud KMS key ring (e.g. 'my-key-ring'). + key_id (string): ID of the key to use (e.g. 'my-key'). + ciphertext (bytes): Encrypted bytes to decrypt. + + Returns: + DecryptResponse: Response including plaintext. + + """ + + # Import the client library. + from google.cloud import kms + + # Create the client. + client = kms.KeyManagementServiceClient() + + # Build the key name. + key_name = client.crypto_key_path(project_id, location_id, key_ring_id, key_id) + + # Call the API. + decrypt_response = client.decrypt(key_name, ciphertext) + print('Plaintext: {}'.format(decrypt_response.plaintext)) + return decrypt_response +# [END kms_decrypt_symmetric] diff --git a/kms/snippets/destroy_key_version.py b/kms/snippets/destroy_key_version.py new file mode 100644 index 000000000000..7423ca7e099e --- /dev/null +++ b/kms/snippets/destroy_key_version.py @@ -0,0 +1,45 @@ +# Copyright 2020 Google LLC +# +# 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 + + +# [START kms_destroy_key_version] +def destroy_key_version(project_id, location_id, key_ring_id, key_id, version_id): + """ + Schedule destruction of the given key version. + + Args: + project_id (string): Google Cloud project ID (e.g. 'my-project'). + location_id (string): Cloud KMS location (e.g. 'us-east1'). + key_ring_id (string): ID of the Cloud KMS key ring (e.g. 'my-key-ring'). + key_id (string): ID of the key to use (e.g. 'my-key'). + version_id (string): ID of the key version to destroy (e.g. '1'). + + Returns: + CryptoKeyVersion: The version. + + """ + + # Import the client library. + from google.cloud import kms + + # Create the client. + client = kms.KeyManagementServiceClient() + + # Build the key version name. + key_version_name = client.crypto_key_version_path(project_id, location_id, key_ring_id, key_id, version_id) + + # Call the API. + destroyed_version = client.destroy_crypto_key_version(key_version_name) + print('Destroyed key version: {}'.format(destroyed_version.name)) + return destroyed_version +# [END kms_destroy_key_version] diff --git a/kms/snippets/disable_key_version.py b/kms/snippets/disable_key_version.py new file mode 100644 index 000000000000..a4a16dd57a65 --- /dev/null +++ b/kms/snippets/disable_key_version.py @@ -0,0 +1,55 @@ +# Copyright 2020 Google LLC +# +# 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 + + +# [START kms_disable_key_version] +def disable_key_version(project_id, location_id, key_ring_id, key_id, version_id): + """ + Disable a key. + + Args: + project_id (string): Google Cloud project ID (e.g. 'my-project'). + location_id (string): Cloud KMS location (e.g. 'us-east1'). + key_ring_id (string): ID of the Cloud KMS key ring (e.g. 'my-key-ring'). + key_id (string): ID of the key to use (e.g. 'my-key'). + version_id (string): ID of the key version to disable (e.g. '1'). + + Returns: + CryptoKeyVersion: The version. + + """ + + # Import the client library. + from google.cloud import kms + + # Create the client. + client = kms.KeyManagementServiceClient() + + # Build the key version name. + key_version_name = client.crypto_key_version_path(project_id, location_id, key_ring_id, key_id, version_id) + + # Build the key version. We need to build a full proto instead of a dict due + # to https://github.com/googleapis/gapic-generator-python/issues/364. + from google.cloud.kms_v1.proto import resources_pb2 + key_version = resources_pb2.CryptoKeyVersion() + key_version.name = key_version_name + key_version.state = kms.enums.CryptoKeyVersion.CryptoKeyVersionState.DISABLED + + # Build the update mask. + update_mask = {'paths': ['state']} + + # Call the API. + disabled_version = client.update_crypto_key_version(key_version, update_mask) + print('Disabled key version: {}'.format(disabled_version.name)) + return disabled_version +# [END kms_disable_key_version] diff --git a/kms/snippets/enable_key_version.py b/kms/snippets/enable_key_version.py new file mode 100644 index 000000000000..9cb8daadd66f --- /dev/null +++ b/kms/snippets/enable_key_version.py @@ -0,0 +1,55 @@ +# Copyright 2020 Google LLC +# +# 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 + + +# [START kms_enable_key_version] +def enable_key_version(project_id, location_id, key_ring_id, key_id, version_id): + """ + Enable a key. + + Args: + project_id (string): Google Cloud project ID (e.g. 'my-project'). + location_id (string): Cloud KMS location (e.g. 'us-east1'). + key_ring_id (string): ID of the Cloud KMS key ring (e.g. 'my-key-ring'). + key_id (string): ID of the key to use (e.g. 'my-key'). + version_id (string): ID of the key version to enable (e.g. '1'). + + Returns: + CryptoKeyVersion: The version. + + """ + + # Import the client library. + from google.cloud import kms + + # Create the client. + client = kms.KeyManagementServiceClient() + + # Build the key version name. + key_version_name = client.crypto_key_version_path(project_id, location_id, key_ring_id, key_id, version_id) + + # Build the key version. We need to build a full proto instead of a dict due + # to https://github.com/googleapis/gapic-generator-python/issues/364. + from google.cloud.kms_v1.proto import resources_pb2 + key_version = resources_pb2.CryptoKeyVersion() + key_version.name = key_version_name + key_version.state = kms.enums.CryptoKeyVersion.CryptoKeyVersionState.ENABLED + + # Build the update mask. + update_mask = {'paths': ['state']} + + # Call the API. + enabled_version = client.update_crypto_key_version(key_version, update_mask) + print('Enabled key version: {}'.format(enabled_version.name)) + return enabled_version +# [END kms_enable_key_version] diff --git a/kms/snippets/encrypt_asymmetric.py b/kms/snippets/encrypt_asymmetric.py new file mode 100644 index 000000000000..efe40322c425 --- /dev/null +++ b/kms/snippets/encrypt_asymmetric.py @@ -0,0 +1,69 @@ +# Copyright 2020 Google LLC +# +# 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 + + +# [START kms_encrypt_asymmetric] +def encrypt_asymmetric(project_id, location_id, key_ring_id, key_id, version_id, plaintext): + """ + Encrypt plaintext using the public key portion of an asymmetric key. + + Args: + project_id (string): Google Cloud project ID (e.g. 'my-project'). + location_id (string): Cloud KMS location (e.g. 'us-east1'). + key_ring_id (string): ID of the Cloud KMS key ring (e.g. 'my-key-ring'). + key_id (string): ID of the key to use (e.g. 'my-key'). + version_id (string): ID of the key version to use (e.g. '1'). + plaintext (string): message to encrypt + + Returns: + bytes: Encrypted ciphertext. + + """ + + # Import the client library. + from google.cloud import kms + + # Import base64 for printing the ciphertext. + import base64 + + # Import cryptographic helpers from the cryptography package. + from cryptography.hazmat.backends import default_backend + from cryptography.hazmat.primitives import hashes, serialization + from cryptography.hazmat.primitives.asymmetric import padding + + # Convert the plaintext to bytes. + plaintext_bytes = plaintext.encode('utf-8') + + # Create the client. + client = kms.KeyManagementServiceClient() + + # Build the key version name. + key_version_name = client.crypto_key_version_path(project_id, location_id, key_ring_id, key_id, version_id) + + # Get the public key. + public_key = client.get_public_key(key_version_name) + + # Extract and parse the public key as a PEM-encoded RSA key. + pem = public_key.pem.encode('utf-8') + rsa_key = serialization.load_pem_public_key(pem, default_backend()) + + # Construct the padding. Note that the padding differs based on key choice. + sha256 = hashes.SHA256() + mgf = padding.MGF1(algorithm=sha256) + pad = padding.OAEP(mgf=mgf, algorithm=sha256, label=None) + + # Encrypt the data using the public key. + ciphertext = rsa_key.encrypt(plaintext_bytes, pad) + print('Ciphertext: {}'.format(base64.b64encode(ciphertext))) + return ciphertext +# [END kms_encrypt_asymmetric] diff --git a/kms/snippets/encrypt_symmetric.py b/kms/snippets/encrypt_symmetric.py new file mode 100644 index 000000000000..b90da358f676 --- /dev/null +++ b/kms/snippets/encrypt_symmetric.py @@ -0,0 +1,51 @@ +# Copyright 2020 Google LLC +# +# 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 + + +# [START kms_encrypt_symmetric] +def encrypt_symmetric(project_id, location_id, key_ring_id, key_id, plaintext): + """ + Encrypt plaintext using a symmetric key. + + Args: + project_id (string): Google Cloud project ID (e.g. 'my-project'). + location_id (string): Cloud KMS location (e.g. 'us-east1'). + key_ring_id (string): ID of the Cloud KMS key ring (e.g. 'my-key-ring'). + key_id (string): ID of the key to use (e.g. 'my-key'). + plaintext (string): message to encrypt + + Returns: + bytes: Encrypted ciphertext. + + """ + + # Import the client library. + from google.cloud import kms + + # Import base64 for printing the ciphertext. + import base64 + + # Convert the plaintext to bytes. + plaintext_bytes = plaintext.encode('utf-8') + + # Create the client. + client = kms.KeyManagementServiceClient() + + # Build the key name. + key_name = client.crypto_key_path(project_id, location_id, key_ring_id, key_id) + + # Call the API. + encrypt_response = client.encrypt(key_name, plaintext_bytes) + print('Ciphertext: {}'.format(base64.b64encode(encrypt_response.ciphertext))) + return encrypt_response +# [END kms_encrypt_symmetric] diff --git a/kms/snippets/get_key_labels.py b/kms/snippets/get_key_labels.py new file mode 100644 index 000000000000..363bcfbaf03b --- /dev/null +++ b/kms/snippets/get_key_labels.py @@ -0,0 +1,48 @@ +# Copyright 2020 Google LLC +# +# 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 + + +# [START kms_get_key_labels] +def get_key_labels(project_id, location_id, key_ring_id, key_id): + """ + Get a key and its labels. + + Args: + project_id (string): Google Cloud project ID (e.g. 'my-project'). + location_id (string): Cloud KMS location (e.g. 'us-east1'). + key_ring_id (string): ID of the Cloud KMS key ring (e.g. 'my-key-ring'). + key_id (string): ID of the key to use (e.g. 'my-key'). + + Returns: + CryptoKey: Cloud KMS key. + + """ + + # Import the client library. + from google.cloud import kms + + # Create the client. + client = kms.KeyManagementServiceClient() + + # Build the key name. + key_name = client.crypto_key_path(project_id, location_id, key_ring_id, key_id) + + # Call the API. + key = client.get_crypto_key(key_name) + + # Example of iterating over labels. + for k, v in key.labels.items(): + print('{} = {}'.format(k, v)) + + return key +# [END kms_get_key_labels] diff --git a/kms/snippets/get_key_version_attestation.py b/kms/snippets/get_key_version_attestation.py new file mode 100644 index 000000000000..615d4653d8ef --- /dev/null +++ b/kms/snippets/get_key_version_attestation.py @@ -0,0 +1,56 @@ +# Copyright 2020 Google LLC +# +# 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 + + +# [START kms_get_key_version_attestation] +def get_key_version_attestation(project_id, location_id, key_ring_id, key_id, version_id): + """ + Get an HSM-backend key's attestation. + + Args: + project_id (string): Google Cloud project ID (e.g. 'my-project'). + location_id (string): Cloud KMS location (e.g. 'us-east1'). + key_ring_id (string): ID of the Cloud KMS key ring (e.g. 'my-key-ring'). + key_id (string): ID of the key to use (e.g. 'my-key'). + version_id (string): ID of the version to use (e.g. '1'). + + Returns: + Attestation: Cloud KMS key attestation. + + """ + + # Import the client library. + from google.cloud import kms + + # Import base64 for printing the attestation. + import base64 + + # Create the client. + client = kms.KeyManagementServiceClient() + + # Build the key version name. + key_version_name = client.crypto_key_version_path(project_id, location_id, key_ring_id, key_id, version_id) + + # Call the API. + version = client.get_crypto_key_version(key_version_name) + + # Only HSM keys have an attestation. For other key types, the attestion + # will be None. + attestation = version.attestation + if not attestation: + raise 'no attestation - attestations only exist on HSM keys' + + encoded_attestation = base64.b64encode(attestation.content) + print('Got key attestation: {}'.format(encoded_attestation)) + return attestation +# [END kms_get_key_version_attestation] diff --git a/kms/snippets/get_public_key.py b/kms/snippets/get_public_key.py new file mode 100644 index 000000000000..1b810d15f6ad --- /dev/null +++ b/kms/snippets/get_public_key.py @@ -0,0 +1,45 @@ +# Copyright 2020 Google LLC +# +# 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 + + +# [START kms_get_public_key] +def get_public_key(project_id, location_id, key_ring_id, key_id, version_id): + """ + Get the public key for an asymmetric key. + + Args: + project_id (string): Google Cloud project ID (e.g. 'my-project'). + location_id (string): Cloud KMS location (e.g. 'us-east1'). + key_ring_id (string): ID of the Cloud KMS key ring (e.g. 'my-key-ring'). + key_id (string): ID of the key to use (e.g. 'my-key'). + version_id (string): ID of the key to use (e.g. '1'). + + Returns: + PublicKey: Cloud KMS public key response. + + """ + + # Import the client library. + from google.cloud import kms + + # Create the client. + client = kms.KeyManagementServiceClient() + + # Build the key version name. + key_version_name = client.crypto_key_version_path(project_id, location_id, key_ring_id, key_id, version_id) + + # Call the API. + public_key = client.get_public_key(key_version_name) + print('Public key: {}'.format(public_key.pem)) + return public_key +# [END kms_get_public_key] diff --git a/kms/snippets/iam_add_member.py b/kms/snippets/iam_add_member.py new file mode 100644 index 000000000000..442f248390de --- /dev/null +++ b/kms/snippets/iam_add_member.py @@ -0,0 +1,56 @@ +# Copyright 2020 Google LLC +# +# 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 + + +# [START kms_iam_add_member] +def iam_add_member(project_id, location_id, key_ring_id, key_id, member): + """ + Add an IAM member to a resource. + + Args: + project_id (string): Google Cloud project ID (e.g. 'my-project'). + location_id (string): Cloud KMS location (e.g. 'us-east1'). + key_ring_id (string): ID of the Cloud KMS key ring (e.g. 'my-key-ring'). + key_id (string): ID of the key to use (e.g. 'my-key'). + member (string): Member to add (e.g. 'user:foo@example.com') + + Returns: + Policy: Updated Cloud IAM policy. + + """ + + # Import the client library. + from google.cloud import kms + + # Create the client. + client = kms.KeyManagementServiceClient() + + # Build the resource name. + resource_name = client.crypto_key_path(project_id, location_id, key_ring_id, key_id) + + # The resource name could also be a key ring. + # resource_name = client.key_ring_path(project_id, location_id, key_ring_id); + + # Get the current policy. + policy = client.get_iam_policy(resource_name) + + # Add the member to the policy. + policy.bindings.add( + role='roles/cloudkms.cryptoKeyEncrypterDecrypter', + members=[member]) + + # Save the updated IAM policy. + updated_policy = client.set_iam_policy(resource_name, policy) + print('Added {} to {}'.format(member, resource_name)) + return updated_policy +# [END kms_iam_add_member] diff --git a/kms/snippets/iam_get_policy.py b/kms/snippets/iam_get_policy.py new file mode 100644 index 000000000000..c00172e98a5b --- /dev/null +++ b/kms/snippets/iam_get_policy.py @@ -0,0 +1,54 @@ +# Copyright 2020 Google LLC +# +# 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 + + +# [START kms_iam_get_policy] +def iam_get_policy(project_id, location_id, key_ring_id, key_id): + """ + Get the IAM policy for a resource. + + Args: + project_id (string): Google Cloud project ID (e.g. 'my-project'). + location_id (string): Cloud KMS location (e.g. 'us-east1'). + key_ring_id (string): ID of the Cloud KMS key ring (e.g. 'my-key-ring'). + key_id (string): ID of the key to use (e.g. 'my-key'). + + Returns: + Policy: Cloud IAM policy. + + """ + + # Import the client library. + from google.cloud import kms + + # Create the client. + client = kms.KeyManagementServiceClient() + + # Build the resource name. + resource_name = client.crypto_key_path(project_id, location_id, key_ring_id, key_id) + + # The resource name could also be a key ring. + # resource_name = client.key_ring_path(project_id, location_id, key_ring_id); + + # Get the current policy. + policy = client.get_iam_policy(resource_name) + + # Print the policy + print('IAM policy for {}'.format(resource_name)) + for binding in policy.bindings: + print(binding.role) + for member in binding.members: + print('- {}'.format(member)) + + return policy +# [END kms_iam_get_policy] diff --git a/kms/snippets/iam_remove_member.py b/kms/snippets/iam_remove_member.py new file mode 100644 index 000000000000..ad73fab943c5 --- /dev/null +++ b/kms/snippets/iam_remove_member.py @@ -0,0 +1,57 @@ +# Copyright 2020 Google LLC +# +# 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 + + +# [START kms_iam_remove_member] +def iam_remove_member(project_id, location_id, key_ring_id, key_id, member): + """ + Remove an IAM member from a resource. + + Args: + project_id (string): Google Cloud project ID (e.g. 'my-project'). + location_id (string): Cloud KMS location (e.g. 'us-east1'). + key_ring_id (string): ID of the Cloud KMS key ring (e.g. 'my-key-ring'). + key_id (string): ID of the key to use (e.g. 'my-key'). + member (string): Member to remove (e.g. 'user:foo@example.com') + + Returns: + Policy: Updated Cloud IAM policy. + + """ + + # Import the client library. + from google.cloud import kms + + # Create the client. + client = kms.KeyManagementServiceClient() + + # Build the resource name. + resource_name = client.crypto_key_path(project_id, location_id, key_ring_id, key_id) + + # The resource name could also be a key ring. + # resource_name = client.key_ring_path(project_id, location_id, key_ring_id); + + # Get the current policy. + policy = client.get_iam_policy(resource_name) + + # Remove the member from the policy. + for binding in policy.bindings: + if binding.role == 'roles/cloudkms.cryptoKeyEncrypterDecrypter': + if member in binding.members: + binding.members.remove(member) + + # Save the updated IAM policy. + updated_policy = client.set_iam_policy(resource_name, policy) + print('Removed {} from {}'.format(member, resource_name)) + return updated_policy +# [END kms_iam_remove_member] diff --git a/kms/snippets/quickstart.py b/kms/snippets/quickstart.py index 2f97f38f70de..91b5a49ad41f 100644 --- a/kms/snippets/quickstart.py +++ b/kms/snippets/quickstart.py @@ -13,41 +13,37 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and -import os +import argparse -def run_quickstart(): - # [START kms_quickstart] - # Imports the Google APIs client library - from google.cloud import kms_v1 +# [START kms_quickstart] +def quickstart(project_id, location_id): + # Import the client library. + from google.cloud import kms - # Your Google Cloud Platform project ID - project_id = 'YOUR_PROJECT_ID' - # [END kms_quickstart] - project_id = os.environ['GCLOUD_PROJECT'] - # [START kms_quickstart] + # Create the client. + client = kms.KeyManagementServiceClient() - # Lists keys in the "global" location. - location = 'global' + # Build the parent location name. + location_name = client.location_path(project_id, location_id) - # Creates an API client for the KMS API. - client = kms_v1.KeyManagementServiceClient() + # Call the API. + key_rings = client.list_key_rings(location_name) - # The resource name of the location associated with the key rings. - parent = client.location_path(project_id, location) + # Example of iterating over key rings. + for key_ring in key_rings: + print(key_ring.name) - # Lists key rings - response = client.list_key_rings(parent) - response_list = list(response) - - if len(response_list) > 0: - print('Key rings:') - for key_ring in response_list: - print(key_ring.name) - else: - print('No key rings found.') - # [END kms_quickstart] + return key_rings +# [END kms_quickstart] if __name__ == '__main__': - run_quickstart() + parser = argparse.ArgumentParser( + description=__doc__, + formatter_class=argparse.RawDescriptionHelpFormatter) + parser.add_argument('project_id', help='id of the GCP project') + parser.add_argument('location_id', help='id of the KMS location') + args = parser.parse_args() + + quickstart(args.project_id, args.location_id) diff --git a/kms/snippets/quickstart_test.py b/kms/snippets/quickstart_test.py deleted file mode 100644 index 5a457518c8fb..000000000000 --- a/kms/snippets/quickstart_test.py +++ /dev/null @@ -1,19 +0,0 @@ -# Copyright 2017 Google Inc. 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. - - -def test_quickstart(): - import quickstart - - quickstart.run_quickstart() diff --git a/kms/snippets/requirements-test.txt b/kms/snippets/requirements-test.txt index 8855f3cf1f88..d3e30fa6c737 100644 --- a/kms/snippets/requirements-test.txt +++ b/kms/snippets/requirements-test.txt @@ -1,2 +1 @@ -backoff==1.10.0 -pytest==5.3.2 +pytest==5.4.1 diff --git a/kms/snippets/restore_key_version.py b/kms/snippets/restore_key_version.py new file mode 100644 index 000000000000..3c4668d6bedf --- /dev/null +++ b/kms/snippets/restore_key_version.py @@ -0,0 +1,45 @@ +# Copyright 2020 Google LLC +# +# 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 + + +# [START kms_restore_key_version] +def restore_key_version(project_id, location_id, key_ring_id, key_id, version_id): + """ + Restore a key version scheduled for destruction. + + Args: + project_id (string): Google Cloud project ID (e.g. 'my-project'). + location_id (string): Cloud KMS location (e.g. 'us-east1'). + key_ring_id (string): ID of the Cloud KMS key ring (e.g. 'my-key-ring'). + key_id (string): ID of the key to use (e.g. 'my-key'). + version_id (string): ID of the version to use (e.g. '1'). + + Returns: + CryptoKeyVersion: Restored Cloud KMS key version. + + """ + + # Import the client library. + from google.cloud import kms + + # Create the client. + client = kms.KeyManagementServiceClient() + + # Build the key version name. + key_version_name = client.crypto_key_version_path(project_id, location_id, key_ring_id, key_id, version_id) + + # Call the API. + restored_version = client.restore_crypto_key_version(key_version_name) + print('Restored key version: {}'.format(restored_version.name)) + return restored_version +# [END kms_restore_key_version] diff --git a/kms/snippets/sign_asymmetric.py b/kms/snippets/sign_asymmetric.py new file mode 100644 index 000000000000..a92a13ec20e2 --- /dev/null +++ b/kms/snippets/sign_asymmetric.py @@ -0,0 +1,64 @@ +# Copyright 2020 Google LLC +# +# 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 + + +# [START kms_sign_asymmetric] +def sign_asymmetric(project_id, location_id, key_ring_id, key_id, version_id, message): + """ + Sign a message using the public key part of an asymmetric key. + + Args: + project_id (string): Google Cloud project ID (e.g. 'my-project'). + location_id (string): Cloud KMS location (e.g. 'us-east1'). + key_ring_id (string): ID of the Cloud KMS key ring (e.g. 'my-key-ring'). + key_id (string): ID of the key to use (e.g. 'my-key'). + version_id (string): Version to use (e.g. '1'). + message (string): Message to sign. + + Returns: + AsymmetricSignResponse: Signature. + + """ + + # Import the client library. + from google.cloud import kms + + # Import base64 for printing the ciphertext. + import base64 + + # Import hashlib for calculating hashes. + import hashlib + + # Create the client. + client = kms.KeyManagementServiceClient() + + # Build the key version name. + key_version_name = client.crypto_key_version_path(project_id, location_id, key_ring_id, key_id, version_id) + + # Convert the message to bytes. + message_bytes = message.encode('utf-8') + + # Calculate the hash. + hash_ = hashlib.sha256(message_bytes).digest() + + # Build the digest. + # + # Note: Key algorithms will require a varying hash function. For + # example, EC_SIGN_P384_SHA384 requires SHA-384. + digest = {'sha256': hash_} + + # Call the API + sign_response = client.asymmetric_sign(key_version_name, digest) + print('Signature: {}'.format(base64.b64encode(sign_response.signature))) + return sign_response +# [END kms_sign_asymmetric] diff --git a/kms/snippets/snippets.py b/kms/snippets/snippets.py deleted file mode 100644 index e09a3a799ace..000000000000 --- a/kms/snippets/snippets.py +++ /dev/null @@ -1,375 +0,0 @@ -#!/usr/bin/env python - -# Copyright 2017 Google, Inc -# -# 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 - - -# [START kms_create_keyring] -def create_key_ring(project_id, location_id, key_ring_id): - """Creates a KeyRing in the given location (e.g. global).""" - - from google.cloud import kms_v1 - - # Creates an API client for the KMS API. - client = kms_v1.KeyManagementServiceClient() - - # The resource name of the location associated with the KeyRing. - parent = client.location_path(project_id, location_id) - - # The keyring object template - keyring_name = client.key_ring_path(project_id, location_id, key_ring_id) - keyring = {'name': keyring_name} - - # Create a KeyRing - response = client.create_key_ring(parent, key_ring_id, keyring) - - print('Created KeyRing {}.'.format(response.name)) - return response -# [END kms_create_keyring] - - -# [START kms_create_cryptokey] -def create_crypto_key(project_id, location_id, key_ring_id, crypto_key_id): - """Creates a CryptoKey within a KeyRing in the given location.""" - - from google.cloud import kms_v1 - from google.cloud.kms_v1 import enums - - # Creates an API client for the KMS API. - client = kms_v1.KeyManagementServiceClient() - - # The resource name of the KeyRing associated with the CryptoKey. - parent = client.key_ring_path(project_id, location_id, key_ring_id) - - # Create the CryptoKey object template - purpose = enums.CryptoKey.CryptoKeyPurpose.ENCRYPT_DECRYPT - crypto_key = {'purpose': purpose} - - # Create a CryptoKey for the given KeyRing. - response = client.create_crypto_key(parent, crypto_key_id, crypto_key) - - print('Created CryptoKey {}.'.format(response.name)) - return response -# [END kms_create_cryptokey] - - -# [START kms_encrypt] -def encrypt_symmetric(project_id, location_id, key_ring_id, crypto_key_id, - plaintext): - """Encrypts input plaintext data using the provided symmetric CryptoKey.""" - - from google.cloud import kms_v1 - - # Creates an API client for the KMS API. - client = kms_v1.KeyManagementServiceClient() - - # The resource name of the CryptoKey. - name = client.crypto_key_path(project_id, location_id, key_ring_id, crypto_key_id) - - # Use the KMS API to encrypt the data. - response = client.encrypt(name, plaintext) - return response.ciphertext -# [END kms_encrypt] - - -# [START kms_decrypt] -def decrypt_symmetric(project_id, location_id, key_ring_id, crypto_key_id, - ciphertext): - """Decrypts input ciphertext using the provided symmetric CryptoKey.""" - - from google.cloud import kms_v1 - - # Creates an API client for the KMS API. - client = kms_v1.KeyManagementServiceClient() - - # The resource name of the CryptoKey. - name = client.crypto_key_path(project_id, location_id, key_ring_id, crypto_key_id) - # Use the KMS API to decrypt the data. - response = client.decrypt(name, ciphertext) - return response.plaintext -# [END kms_decrypt] - - -# [START kms_disable_cryptokey_version] -def disable_crypto_key_version(project_id, location_id, key_ring_id, - crypto_key_id, version_id): - """Disables a CryptoKeyVersion associated with a given CryptoKey and - KeyRing.""" - - from google.cloud import kms_v1 - from google.cloud.kms_v1 import enums - - # Creates an API client for the KMS API. - client = kms_v1.KeyManagementServiceClient() - - # Construct the resource name of the CryptoKeyVersion. - name = client.crypto_key_version_path(project_id, location_id, key_ring_id, - crypto_key_id, version_id) - - # Use the KMS API to disable the CryptoKeyVersion. - new_state = enums.CryptoKeyVersion.CryptoKeyVersionState.DISABLED - version = {'name': name, 'state': new_state} - update_mask = {'paths': ["state"]} - - # Print results - response = client.update_crypto_key_version(version, update_mask) - print('CryptoKeyVersion {}\'s state has been set to {}.'.format( - name, response.state)) -# [END kms_disable_cryptokey_version] - - -# [START kms_enable_cryptokey_version] -def enable_crypto_key_version(project_id, location_id, key_ring_id, - crypto_key_id, version_id): - """Enables a CryptoKeyVersion associated with a given CryptoKey and - KeyRing.""" - - from google.cloud import kms_v1 - from google.cloud.kms_v1 import enums - - # Creates an API client for the KMS API. - client = kms_v1.KeyManagementServiceClient() - - # Construct the resource name of the CryptoKeyVersion. - name = client.crypto_key_version_path(project_id, location_id, key_ring_id, - crypto_key_id, version_id) - - # Use the KMS API to enable the CryptoKeyVersion. - new_state = enums.CryptoKeyVersion.CryptoKeyVersionState.ENABLED - version = {'name': name, 'state': new_state} - update_mask = {'paths': ["state"]} - - # Print results - response = client.update_crypto_key_version(version, update_mask) - print('CryptoKeyVersion {}\'s state has been set to {}.'.format( - name, response.state)) -# [END kms_enable_cryptokey_version] - - -# [START kms_destroy_cryptokey_version] -def destroy_crypto_key_version( - project_id, location_id, key_ring_id, crypto_key_id, version_id): - """Schedules a CryptoKeyVersion associated with a given CryptoKey and - KeyRing for destruction 24 hours in the future.""" - - from google.cloud import kms_v1 - - # Creates an API client for the KMS API. - client = kms_v1.KeyManagementServiceClient() - - # Construct the resource name of the CryptoKeyVersion. - name = client.crypto_key_version_path(project_id, location_id, key_ring_id, - crypto_key_id, version_id) - - # Use the KMS API to mark the CryptoKeyVersion for destruction. - response = client.destroy_crypto_key_version(name) - - # Print results - print('CryptoKeyVersion {}\'s state has been set to {}.'.format( - name, response.state)) -# [END kms_destroy_cryptokey_version] - - -# [START kms_restore_cryptokey_version] -def restore_crypto_key_version( - project_id, location_id, key_ring_id, crypto_key_id, version_id): - """Restores a CryptoKeyVersion that is scheduled for destruction.""" - - from google.cloud import kms_v1 - - # Creates an API client for the KMS API. - client = kms_v1.KeyManagementServiceClient() - - # Construct the resource name of the CryptoKeyVersion. - name = client.crypto_key_version_path(project_id, location_id, key_ring_id, - crypto_key_id, version_id) - - # Use the KMS API to restore the CryptoKeyVersion. - response = client.restore_crypto_key_version(name) - - # Print results - print('CryptoKeyVersion {}\'s state has been set to {}.'.format( - name, response.state)) - - -# [END kms_restore_cryptokey_version] - - -# [START kms_add_member_to_cryptokey_policy] -def add_member_to_crypto_key_policy( - project_id, location_id, key_ring_id, crypto_key_id, member, role): - """Adds a member with a given role to the Identity and Access Management - (IAM) policy for a given CryptoKey associated with a KeyRing.""" - - from google.cloud import kms_v1 - - # Creates an API client for the KMS API. - client = kms_v1.KeyManagementServiceClient() - - # The resource name of the CryptoKey. - resource = client.crypto_key_path(project_id, location_id, key_ring_id, crypto_key_id) - # Get the current IAM policy. - policy = client.get_iam_policy(resource) - - # Add member - policy.bindings.add( - role=role, - members=[member]) - - # Update the IAM Policy. - client.set_iam_policy(resource, policy) - - # Print results - print('Member {} added with role {} to policy for CryptoKey {} \ - in KeyRing {}'.format(member, role, crypto_key_id, key_ring_id)) -# [END kms_add_member_to_cryptokey_policy] - - -# [START kms_add_member_to_keyring_policy] -def add_member_to_key_ring_policy( - project_id, location_id, key_ring_id, member, role): - """Adds a member with a given role to the Identity and Access Management - (IAM) policy for a given KeyRing.""" - - from google.cloud import kms_v1 - - # Creates an API client for the KMS API. - client = kms_v1.KeyManagementServiceClient() - - # The resource name of the KeyRing. - resource = client.key_ring_path(project_id, location_id, key_ring_id) - - # Get the current IAM policy. - policy = client.get_iam_policy(resource) - - # Add member - policy.bindings.add( - role=role, - members=[member]) - - # Update the IAM Policy. - client.set_iam_policy(resource, policy) - - # Print results - print('Member {} added with role {} to policy in KeyRing {}' - .format(member, role, key_ring_id)) - -# [END kms_add_member_to_keyring_policy] - - -# [START kms_remove_member_from_cryptokey_policy] -def remove_member_from_crypto_key_policy( - project_id, location_id, key_ring_id, crypto_key_id, member, role): - """Removes a member with a given role from the Identity and Access - Management (IAM) policy for a given CryptoKey associated with a KeyRing.""" - - from google.cloud import kms_v1 - - # Creates an API client for the KMS API. - client = kms_v1.KeyManagementServiceClient() - - # The resource name of the CryptoKey. - resource = client.crypto_key_path(project_id, location_id, key_ring_id, crypto_key_id) - - # Get the current IAM policy. - policy = client.get_iam_policy(resource) - - # Remove member - for b in list(policy.bindings): - if b.role == role and member in b.members: - b.members.remove(member) - - # Update the IAM Policy. - client.set_iam_policy(resource, policy) - - # Print results - print('Member {} removed from role {} for CryptoKey in KeyRing {}' - .format(member, role, crypto_key_id, key_ring_id)) -# [END kms_remove_member_from_cryptokey_policy] - - -def remove_member_from_key_ring_policy(project_id, location_id, key_ring_id, - member, role): - """Removes a member with a given role from the Identity and Access - Management (IAM) policy for a given KeyRing.""" - - from google.cloud import kms_v1 - - # Creates an API client for the KMS API. - client = kms_v1.KeyManagementServiceClient() - - # The resource name of the KeyRing. - resource = client.key_ring_path(project_id, location_id, key_ring_id) - - # Get the current IAM policy. - policy = client.get_iam_policy(resource) - - # Remove member - for b in list(policy.bindings): - if b.role == role and member in b.members: - b.members.remove(member) - - # Update the IAM Policy. - client.set_iam_policy(resource, policy) - - # Print results - print('Member {} removed from role {} for KeyRing {}' - .format(member, role, key_ring_id)) - - -# [START kms_get_keyring_policy] -def get_key_ring_policy(project_id, location_id, key_ring_id): - """Gets the Identity and Access Management (IAM) policy for a given KeyRing - and prints out roles and the members assigned to those roles.""" - - from google.cloud import kms_v1 - - # Creates an API client for the KMS API. - client = kms_v1.KeyManagementServiceClient() - - # The resource name of the KeyRing. - resource = client.key_ring_path(project_id, location_id, key_ring_id) - - # Get the current IAM policy. - policy = client.get_iam_policy(resource) - - # Print results - print('Printing IAM policy for resource {}:'.format(resource)) - for b in policy.bindings: - for m in b.members: - print('Role: {} Member: {}'.format(b.role, m)) - return policy -# [END kms_get_keyring_policy] - - -def get_crypto_key_policy(project_id, location_id, key_ring_id, crypto_key_id): - """Gets the Identity and Access Management (IAM) policy for a given KeyRing - and prints out roles and the members assigned to those roles.""" - - from google.cloud import kms_v1 - - # Creates an API client for the KMS API. - client = kms_v1.KeyManagementServiceClient() - - # The resource name of the CryptoKey. - resource = client.crypto_key_path(project_id, location_id, key_ring_id, crypto_key_id) - - # Get the current IAM policy. - policy = client.get_iam_policy(resource) - - # Print results - print('Printing IAM policy for resource {}:'.format(resource)) - for b in policy.bindings: - for m in b.members: - print('Role: {} Member: {}'.format(b.role, m)) - return policy diff --git a/kms/snippets/snippets_test.py b/kms/snippets/snippets_test.py index 0b03bcda2193..c75b872c4121 100644 --- a/kms/snippets/snippets_test.py +++ b/kms/snippets/snippets_test.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python - # Copyright 2017 Google, Inc # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -13,226 +11,415 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and +import hashlib +import os import time -from os import environ import uuid -from google.api_core.exceptions import Aborted, GoogleAPICallError -from google.cloud import kms_v1 -from google.cloud.kms_v1 import enums -from google.iam.v1.policy_pb2 import Policy -import backoff import pytest -import snippets +from create_key_asymmetric_decrypt import create_key_asymmetric_decrypt +from create_key_asymmetric_sign import create_key_asymmetric_sign +from create_key_hsm import create_key_hsm +from create_key_labels import create_key_labels +from create_key_ring import create_key_ring +from create_key_rotation_schedule import create_key_rotation_schedule +from create_key_symmetric_encrypt_decrypt import create_key_symmetric_encrypt_decrypt +from create_key_version import create_key_version +from decrypt_asymmetric import decrypt_asymmetric +from decrypt_symmetric import decrypt_symmetric +from destroy_key_version import destroy_key_version +from disable_key_version import disable_key_version +from enable_key_version import enable_key_version +from encrypt_asymmetric import encrypt_asymmetric +from encrypt_symmetric import encrypt_symmetric +from get_key_labels import get_key_labels +from get_key_version_attestation import get_key_version_attestation +from get_public_key import get_public_key +from iam_add_member import iam_add_member +from iam_get_policy import iam_get_policy +from iam_remove_member import iam_remove_member +from quickstart import quickstart +from restore_key_version import restore_key_version +from sign_asymmetric import sign_asymmetric +from update_key_add_rotation import update_key_add_rotation +from update_key_remove_labels import update_key_remove_labels +from update_key_remove_rotation import update_key_remove_rotation +from update_key_set_primary import update_key_set_primary +from update_key_update_labels import update_key_update_labels +from verify_asymmetric_ec import verify_asymmetric_ec +from verify_asymmetric_rsa import verify_asymmetric_rsa +from cryptography.exceptions import InvalidSignature +from cryptography.hazmat.backends import default_backend +from cryptography.hazmat.primitives import hashes, serialization +from cryptography.hazmat.primitives.asymmetric import padding, utils -def create_key_helper(key_id, purpose, algorithm, t): - try: - client = kms_v1.KeyManagementServiceClient() - parent = client.key_ring_path(t.project_id, t.location, t.keyring_id) - - crypto_key = {'purpose': purpose, - 'version_template': {'algorithm': algorithm}} - client.create_crypto_key(parent, key_id, crypto_key) - return True - except GoogleAPICallError: - # key already exists - return False - - -def setup_module(module): - """ - Set up keys in project if needed - """ - t = TestKMSSnippets() - try: - # create keyring - snippets.create_key_ring(t.project_id, t.location, t.keyring_id) - except GoogleAPICallError: - # keyring already exists - pass - s = create_key_helper(t.sym_id, - enums.CryptoKey.CryptoKeyPurpose.ENCRYPT_DECRYPT, - enums.CryptoKeyVersion.CryptoKeyVersionAlgorithm. - GOOGLE_SYMMETRIC_ENCRYPTION, - t) - if s: - # leave time for key to initialize - time.sleep(20) - - -class TestKMSSnippets: - project_id = environ['GCLOUD_PROJECT'] - keyring_id = 'kms-samples-{}'.format(uuid.uuid4().hex) - location = 'global' - parent = 'projects/{}/locations/{}'.format(project_id, location) - keyring_path = '{}/keyRings/{}'.format(parent, keyring_id) - version = '1' - - sym_id = 'symmetric' - - sym = '{}/cryptoKeys/{}'.format(keyring_path, sym_id) - sym_version = '{}/cryptoKeyVersions/{}'.format(sym, version) - - message = 'test message 123' - message_bytes = message.encode('utf-8') +from google.cloud import kms +from google.cloud.kms_v1.proto import resources_pb2 + + +@pytest.fixture(scope="module") +def client(): + return kms.KeyManagementServiceClient() + + +@pytest.fixture(scope="module") +def project_id(): + return os.environ['GCLOUD_PROJECT'] + + +@pytest.fixture(scope="module") +def location_id(): + return "us-east1" + + +@pytest.fixture(scope="module") +def key_ring_id(client, project_id, location_id): + location_name = client.location_path(project_id, location_id) + key_ring_id = '{}'.format(uuid.uuid4()) + key_ring = client.create_key_ring(location_name, key_ring_id, {}) + + yield key_ring_id + + for key in client.list_crypto_keys(key_ring.name): + if key.rotation_period.seconds > 0 or key.next_rotation_time.seconds > 0: + # https://github.com/googleapis/gapic-generator-python/issues/364 + updated_key = resources_pb2.CryptoKey() + updated_key.name = key.name + update_mask = {'paths': ['rotation_period', 'next_rotation_time']} + client.update_crypto_key(updated_key, update_mask) + + f = 'state != DESTROYED AND state != DESTROY_SCHEDULED' + for version in client.list_crypto_key_versions(key.name, filter_=f): + client.destroy_crypto_key_version(version.name) + + +@pytest.fixture(scope="module") +def asymmetric_decrypt_key_id(client, project_id, location_id, key_ring_id): + key_ring_name = client.key_ring_path(project_id, location_id, key_ring_id) + key_id = '{}'.format(uuid.uuid4()) + key = client.create_crypto_key(key_ring_name, key_id, { + 'purpose': kms.enums.CryptoKey.CryptoKeyPurpose.ASYMMETRIC_DECRYPT, + 'version_template': { + 'algorithm': kms.enums.CryptoKeyVersion.CryptoKeyVersionAlgorithm.RSA_DECRYPT_OAEP_2048_SHA256 + }, + 'labels': {'foo': 'bar', 'zip': 'zap'} + }) + wait_for_ready(client, '{}/cryptoKeyVersions/1'.format(key.name)) + return key_id + + +@pytest.fixture(scope="module") +def asymmetric_sign_ec_key_id(client, project_id, location_id, key_ring_id): + key_ring_name = client.key_ring_path(project_id, location_id, key_ring_id) + key_id = '{}'.format(uuid.uuid4()) + key = client.create_crypto_key(key_ring_name, key_id, { + 'purpose': kms.enums.CryptoKey.CryptoKeyPurpose.ASYMMETRIC_SIGN, + 'version_template': { + 'algorithm': kms.enums.CryptoKeyVersion.CryptoKeyVersionAlgorithm.EC_SIGN_P256_SHA256 + }, + 'labels': {'foo': 'bar', 'zip': 'zap'} + }) + wait_for_ready(client, '{}/cryptoKeyVersions/1'.format(key.name)) + return key_id + + +@pytest.fixture(scope="module") +def asymmetric_sign_rsa_key_id(client, project_id, location_id, key_ring_id): + key_ring_name = client.key_ring_path(project_id, location_id, key_ring_id) + key_id = '{}'.format(uuid.uuid4()) + key = client.create_crypto_key(key_ring_name, key_id, { + 'purpose': kms.enums.CryptoKey.CryptoKeyPurpose.ASYMMETRIC_SIGN, + 'version_template': { + 'algorithm': kms.enums.CryptoKeyVersion.CryptoKeyVersionAlgorithm.RSA_SIGN_PKCS1_2048_SHA256 + }, + 'labels': {'foo': 'bar', 'zip': 'zap'} + }) + wait_for_ready(client, '{}/cryptoKeyVersions/1'.format(key.name)) + return key_id + + +@pytest.fixture(scope="module") +def hsm_key_id(client, project_id, location_id, key_ring_id): + key_ring_name = client.key_ring_path(project_id, location_id, key_ring_id) + key_id = '{}'.format(uuid.uuid4()) + key = client.create_crypto_key(key_ring_name, key_id, { + 'purpose': kms.enums.CryptoKey.CryptoKeyPurpose.ENCRYPT_DECRYPT, + 'version_template': { + 'algorithm': kms.enums.CryptoKeyVersion.CryptoKeyVersionAlgorithm.GOOGLE_SYMMETRIC_ENCRYPTION, + 'protection_level': kms.enums.ProtectionLevel.HSM + }, + 'labels': {'foo': 'bar', 'zip': 'zap'} + }) + wait_for_ready(client, '{}/cryptoKeyVersions/1'.format(key.name)) + return key_id + + +@pytest.fixture(scope="module") +def symmetric_key_id(client, project_id, location_id, key_ring_id): + key_ring_name = client.key_ring_path(project_id, location_id, key_ring_id) + key_id = '{}'.format(uuid.uuid4()) + key = client.create_crypto_key(key_ring_name, key_id, { + 'purpose': kms.enums.CryptoKey.CryptoKeyPurpose.ENCRYPT_DECRYPT, + 'version_template': { + 'algorithm': kms.enums.CryptoKeyVersion.CryptoKeyVersionAlgorithm.GOOGLE_SYMMETRIC_ENCRYPTION + }, + 'labels': {'foo': 'bar', 'zip': 'zap'} + }) + wait_for_ready(client, '{}/cryptoKeyVersions/1'.format(key.name)) + return key_id + + +def wait_for_ready(client, key_version_name): + for i in range(5): + key_version = client.get_crypto_key_version(key_version_name) + if key_version.state == kms.enums.CryptoKeyVersion.CryptoKeyVersionState.ENABLED: + return + time.sleep(0.1*(i**2)) + pytest.fail('{} not ready'.format(key_version_name)) + + +def test_create_key_asymmetric_decrypt(project_id, location_id, key_ring_id): + key_id = '{}'.format(uuid.uuid4()) + key = create_key_asymmetric_decrypt(project_id, location_id, key_ring_id, key_id) + assert key.purpose == kms.enums.CryptoKey.CryptoKeyPurpose.ASYMMETRIC_DECRYPT + assert key.version_template.algorithm == kms.enums.CryptoKeyVersion.CryptoKeyVersionAlgorithm.RSA_DECRYPT_OAEP_2048_SHA256 + + +def test_create_key_asymmetric_sign(project_id, location_id, key_ring_id): + key_id = '{}'.format(uuid.uuid4()) + key = create_key_asymmetric_sign(project_id, location_id, key_ring_id, key_id) + assert key.purpose == kms.enums.CryptoKey.CryptoKeyPurpose.ASYMMETRIC_SIGN + assert key.version_template.algorithm == kms.enums.CryptoKeyVersion.CryptoKeyVersionAlgorithm.RSA_SIGN_PKCS1_2048_SHA256 + + +def test_create_key_hsm(project_id, location_id, key_ring_id): + key_id = '{}'.format(uuid.uuid4()) + key = create_key_hsm(project_id, location_id, key_ring_id, key_id) + assert key.purpose == kms.enums.CryptoKey.CryptoKeyPurpose.ENCRYPT_DECRYPT + assert key.version_template.algorithm == kms.enums.CryptoKeyVersion.CryptoKeyVersionAlgorithm.GOOGLE_SYMMETRIC_ENCRYPTION + assert key.version_template.protection_level == kms.enums.ProtectionLevel.HSM + + +def test_create_key_labels(project_id, location_id, key_ring_id): + key_id = '{}'.format(uuid.uuid4()) + key = create_key_labels(project_id, location_id, key_ring_id, key_id) + assert key.purpose == kms.enums.CryptoKey.CryptoKeyPurpose.ENCRYPT_DECRYPT + assert key.version_template.algorithm == kms.enums.CryptoKeyVersion.CryptoKeyVersionAlgorithm.GOOGLE_SYMMETRIC_ENCRYPTION + assert key.labels == {'team': 'alpha', 'cost_center': 'cc1234'} + + +def test_create_key_ring(project_id, location_id): + key_ring_id = '{}'.format(uuid.uuid4()) + key_ring = create_key_ring(project_id, location_id, key_ring_id) + assert key_ring + + +def test_create_key_rotation_schedule(project_id, location_id, key_ring_id): + key_id = '{}'.format(uuid.uuid4()) + key = create_key_rotation_schedule(project_id, location_id, key_ring_id, key_id) + assert key.rotation_period.seconds == 60*60*24*30 + assert key.next_rotation_time.seconds > 0 + + +def test_create_key_symmetric_encrypt_decrypt(project_id, location_id, key_ring_id): + key_id = '{}'.format(uuid.uuid4()) + key = create_key_symmetric_encrypt_decrypt(project_id, location_id, key_ring_id, key_id) + assert key.purpose == kms.enums.CryptoKey.CryptoKeyPurpose.ENCRYPT_DECRYPT + assert key.version_template.algorithm == kms.enums.CryptoKeyVersion.CryptoKeyVersionAlgorithm.GOOGLE_SYMMETRIC_ENCRYPTION + + +def test_create_key_version(project_id, location_id, key_ring_id, symmetric_key_id): + version = create_key_version(project_id, location_id, key_ring_id, symmetric_key_id) + assert version + + +def test_decrypt_asymmetric(client, project_id, location_id, key_ring_id, asymmetric_decrypt_key_id): + message = 'my message'.encode('utf-8') + + key_version_name = client.crypto_key_version_path(project_id, location_id, key_ring_id, asymmetric_decrypt_key_id, '1') + public_key = client.get_public_key(key_version_name) + + pem = public_key.pem.encode('utf-8') + rsa_key = serialization.load_pem_public_key(pem, default_backend()) + + pad = padding.OAEP(mgf=padding.MGF1(algorithm=hashes.SHA256()), + algorithm=hashes.SHA256(), + label=None) + ciphertext = rsa_key.encrypt(message, pad) + + response = decrypt_asymmetric(project_id, location_id, key_ring_id, asymmetric_decrypt_key_id, '1', ciphertext) + assert response.plaintext == message + + +def test_decrypt_symmetric(client, project_id, location_id, key_ring_id, symmetric_key_id): + plaintext = 'my message'.encode('utf-8') + + key_version_name = client.crypto_key_path(project_id, location_id, key_ring_id, symmetric_key_id) + encrypt_response = client.encrypt(key_version_name, plaintext) + ciphertext = encrypt_response.ciphertext + + decrypt_response = decrypt_symmetric(project_id, location_id, key_ring_id, symmetric_key_id, ciphertext) + assert decrypt_response.plaintext == plaintext + + +def test_destroy_restore_key_version(client, project_id, location_id, key_ring_id, asymmetric_decrypt_key_id): + key_name = client.crypto_key_path(project_id, location_id, key_ring_id, asymmetric_decrypt_key_id) + version = client.create_crypto_key_version(key_name, {}) + version_id = version.name.split('/')[-1] + wait_for_ready(client, version.name) + + destroyed_version = destroy_key_version(project_id, location_id, key_ring_id, asymmetric_decrypt_key_id, version_id) + assert destroyed_version.state == kms.enums.CryptoKeyVersion.CryptoKeyVersionState.DESTROY_SCHEDULED + + restored_version = restore_key_version(project_id, location_id, key_ring_id, asymmetric_decrypt_key_id, version_id) + assert restored_version.state == kms.enums.CryptoKeyVersion.CryptoKeyVersionState.DISABLED + + +def test_disable_enable_key_version(client, project_id, location_id, key_ring_id, asymmetric_decrypt_key_id): + key_name = client.crypto_key_path(project_id, location_id, key_ring_id, asymmetric_decrypt_key_id) + version = client.create_crypto_key_version(key_name, {}) + version_id = version.name.split('/')[-1] + + wait_for_ready(client, version.name) + + disabled_version = disable_key_version(project_id, location_id, key_ring_id, asymmetric_decrypt_key_id, version_id) + assert disabled_version.state == kms.enums.CryptoKeyVersion.CryptoKeyVersionState.DISABLED + + enabled_version = enable_key_version(project_id, location_id, key_ring_id, asymmetric_decrypt_key_id, version_id) + assert enabled_version.state == kms.enums.CryptoKeyVersion.CryptoKeyVersionState.ENABLED + + +def test_encrypt_asymmetric(client, project_id, location_id, key_ring_id, asymmetric_decrypt_key_id): + plaintext = 'my message' + ciphertext = encrypt_asymmetric(project_id, location_id, key_ring_id, asymmetric_decrypt_key_id, '1', plaintext) + + key_version_name = client.crypto_key_version_path(project_id, location_id, key_ring_id, asymmetric_decrypt_key_id, '1') + response = client.asymmetric_decrypt(key_version_name, ciphertext) + assert response.plaintext == plaintext.encode('utf-8') + + +def test_encrypt_symmetric(client, project_id, location_id, key_ring_id, symmetric_key_id): + plaintext = 'my message' + encrypt_response = encrypt_symmetric(project_id, location_id, key_ring_id, symmetric_key_id, plaintext) + + key_name = client.crypto_key_path(project_id, location_id, key_ring_id, symmetric_key_id) + decrypt_response = client.decrypt(key_name, encrypt_response.ciphertext) + assert decrypt_response.plaintext == plaintext.encode('utf-8') + + +def test_get_key_labels(project_id, location_id, key_ring_id, symmetric_key_id): + key = get_key_labels(project_id, location_id, key_ring_id, symmetric_key_id) + assert key.labels == {'foo': 'bar', 'zip': 'zap'} + + +def test_get_key_version_attestation(project_id, location_id, key_ring_id, hsm_key_id): + attestation = get_key_version_attestation(project_id, location_id, key_ring_id, hsm_key_id, '1') + assert attestation.format + assert attestation.content + + +def test_get_public_key(project_id, location_id, key_ring_id, asymmetric_decrypt_key_id): + public_key = get_public_key(project_id, location_id, key_ring_id, asymmetric_decrypt_key_id, '1') + assert public_key.pem + + +def test_iam_add_member(project_id, location_id, key_ring_id, symmetric_key_id): member = 'group:test@google.com' - role = 'roles/viewer' - - @pytest.mark.skip(reason="There's currently no method to delete keyrings, \ - so we should avoid creating resources") - def test_create_key_ring(self): - ring_id = self.keyring_id + '-test-create-{}'.format(uuid.uuid4().hex) - snippets.create_key_ring(self.project_id, self.location, ring_id) - client = kms_v1.KeyManagementServiceClient() - result = client.get_key_ring(client.key_ring_path(self.project_id, - self.location, - ring_id)) - assert ring_id in result.name - - @pytest.mark.skip(reason="Deleting keys isn't instant, so we should avoid \ - creating a large number of them in our tests") - def test_create_crypto_key(self): - key_id = self.sym_id + '-test-{}'.format(uuid.uuid4().hex) - snippets.create_crypto_key(self.project_id, self.location, - self.keyring_id, key_id) - c = kms_v1.KeyManagementServiceClient() - result = c.get_crypto_key(c.crypto_key_path(self.project_id, - self.location, - self.keyring_id, - key_id)) - assert key_id in result.name - - # tests disable/enable/destroy/restore - def test_key_change_version_state(self): - client = kms_v1.KeyManagementServiceClient() - name = client.crypto_key_version_path(self.project_id, self.location, - self.keyring_id, self.sym_id, - self.version) - state_enum = enums.CryptoKeyVersion.CryptoKeyVersionState - # test disable - snippets.disable_crypto_key_version(self.project_id, self.location, - self.keyring_id, self.sym_id, - self.version) - response = client.get_crypto_key_version(name) - assert response.state == state_enum.DISABLED - # test destroy - snippets.destroy_crypto_key_version(self.project_id, self.location, - self.keyring_id, self.sym_id, - self.version) - response = client.get_crypto_key_version(name) - assert response.state == state_enum.DESTROY_SCHEDULED - # test restore - snippets.restore_crypto_key_version(self.project_id, self.location, - self.keyring_id, self.sym_id, - self.version) - response = client.get_crypto_key_version(name) - assert response.state == state_enum.DISABLED - # test re-enable - snippets.enable_crypto_key_version(self.project_id, self.location, - self.keyring_id, self.sym_id, - self.version) - response = client.get_crypto_key_version(name) - assert response.state == state_enum.ENABLED - - def test_get_ring_policy(self): - policy = snippets.get_key_ring_policy(self.project_id, - self.location, self.keyring_id) - assert type(policy) is Policy - - # tests get/add/remove policy members - def test_ring_policy(self): - # add member - snippets.add_member_to_key_ring_policy(self.project_id, self.location, - self.keyring_id, self.member, - self.role) - policy = snippets.get_key_ring_policy(self.project_id, - self.location, self.keyring_id) - found = False - for b in list(policy.bindings): - if b.role == self.role and self.member in b.members: - found = True - assert found - # remove member - snippets.remove_member_from_key_ring_policy(self.project_id, - self.location, - self.keyring_id, - self.member, - self.role) - policy = snippets.get_key_ring_policy(self.project_id, - self.location, self.keyring_id) - found = False - for b in list(policy.bindings): - if b.role == self.role and self.member in b.members: - found = True - assert not found - - # tests get/add/remove policy members - def test_key_policy(self): - # add member - snippets.add_member_to_crypto_key_policy( - self.project_id, - self.location, - self.keyring_id, - self.sym_id, - self.member, - self.role) - - @backoff.on_exception( - backoff.expo, (Aborted, AssertionError), max_time=60) - def check_policy(): - policy = snippets.get_crypto_key_policy( - self.project_id, - self.location, - self.keyring_id, - self.sym_id) - found = False - for b in list(policy.bindings): - if b.role == self.role and self.member in b.members: - found = True - assert found - - check_policy() - - # remove member - snippets.remove_member_from_crypto_key_policy( - self.project_id, - self.location, - self.keyring_id, - self.sym_id, - self.member, - self.role) - - @backoff.on_exception( - backoff.expo, (Aborted, AssertionError), max_time=60) - def check_policy_again(): - policy = snippets.get_crypto_key_policy( - self.project_id, - self.location, - self.keyring_id, - self.sym_id) - found = False - for b in list(policy.bindings): - if b.role == self.role and self.member in b.members: - found = True - assert not found - - check_policy_again() - - def test_symmetric_encrypt_decrypt(self): - cipher_bytes = snippets.encrypt_symmetric(self.project_id, - self.location, - self.keyring_id, - self.sym_id, - self.message_bytes) - plain_bytes = snippets.decrypt_symmetric(self.project_id, - self.location, - self.keyring_id, - self.sym_id, - cipher_bytes) - assert plain_bytes == self.message_bytes - assert cipher_bytes != self.message_bytes - plaintext = plain_bytes.decode("utf-8") - assert plaintext == self.message + policy = iam_add_member(project_id, location_id, key_ring_id, symmetric_key_id, member) + assert any(member in b.members for b in policy.bindings) + + +def test_iam_get_policy(project_id, location_id, key_ring_id, symmetric_key_id): + policy = iam_get_policy(project_id, location_id, key_ring_id, symmetric_key_id) + assert policy + + +def test_iam_remove_member(client, project_id, location_id, key_ring_id, asymmetric_sign_rsa_key_id): + resource_name = client.crypto_key_path(project_id, location_id, key_ring_id, asymmetric_sign_rsa_key_id) + + policy = client.get_iam_policy(resource_name) + policy.bindings.add( + role='roles/cloudkms.cryptoKeyEncrypterDecrypter', + members=['group:test@google.com', 'group:tester@google.com']) + client.set_iam_policy(resource_name, policy) + + policy = iam_remove_member(project_id, location_id, key_ring_id, asymmetric_sign_rsa_key_id, 'group:test@google.com') + assert not any('group:test@google.com' in b.members for b in policy.bindings) + assert any('group:tester@google.com' in b.members for b in policy.bindings) + + +def test_sign_asymmetric(client, project_id, location_id, key_ring_id, asymmetric_sign_rsa_key_id): + message = 'my message' + + sign_response = sign_asymmetric(project_id, location_id, key_ring_id, asymmetric_sign_rsa_key_id, '1', message) + assert sign_response.signature + + key_version_name = client.crypto_key_version_path(project_id, location_id, key_ring_id, asymmetric_sign_rsa_key_id, '1') + public_key = client.get_public_key(key_version_name) + pem = public_key.pem.encode('utf-8') + rsa_key = serialization.load_pem_public_key(pem, default_backend()) + hash_ = hashlib.sha256(message.encode('utf-8')).digest() + + try: + sha256 = hashes.SHA256() + pad = padding.PKCS1v15() + rsa_key.verify(sign_response.signature, hash_, pad, utils.Prehashed(sha256)) + except InvalidSignature: + pytest.fail('invalid signature') + + +def test_update_key_add_rotation(project_id, location_id, key_ring_id, symmetric_key_id): + key = update_key_add_rotation(project_id, location_id, key_ring_id, symmetric_key_id) + assert key.rotation_period.seconds == 60*60*24*30 + assert key.next_rotation_time.seconds > 0 + + +def test_update_key_remove_labels(project_id, location_id, key_ring_id, symmetric_key_id): + key = update_key_remove_labels(project_id, location_id, key_ring_id, symmetric_key_id) + assert key.labels == {} + + +def test_update_key_remove_rotation(project_id, location_id, key_ring_id, symmetric_key_id): + key = update_key_remove_rotation(project_id, location_id, key_ring_id, symmetric_key_id) + assert key.rotation_period.seconds == 0 + assert key.next_rotation_time.seconds == 0 + + +def test_update_key_set_primary(project_id, location_id, key_ring_id, symmetric_key_id): + key = update_key_set_primary(project_id, location_id, key_ring_id, symmetric_key_id, '1') + assert '1' in key.primary.name + + +def test_update_key_update_labels(project_id, location_id, key_ring_id, symmetric_key_id): + key = update_key_update_labels(project_id, location_id, key_ring_id, symmetric_key_id) + assert key.labels == {'new_label': 'new_value'} + + +def test_verify_asymmetric_ec(client, project_id, location_id, key_ring_id, asymmetric_sign_ec_key_id): + message = 'my message' + + key_version_name = client.crypto_key_version_path(project_id, location_id, key_ring_id, asymmetric_sign_ec_key_id, '1') + hash_ = hashlib.sha256(message.encode('utf-8')).digest() + sign_response = client.asymmetric_sign(key_version_name, {'sha256': hash_}) + + verified = verify_asymmetric_ec(project_id, location_id, key_ring_id, asymmetric_sign_ec_key_id, '1', message, sign_response.signature) + assert verified + + +def test_verify_asymmetric_rsa(client, project_id, location_id, key_ring_id, asymmetric_sign_rsa_key_id): + message = 'my message' + + key_version_name = client.crypto_key_version_path(project_id, location_id, key_ring_id, asymmetric_sign_rsa_key_id, '1') + hash_ = hashlib.sha256(message.encode('utf-8')).digest() + sign_response = client.asymmetric_sign(key_version_name, {'sha256': hash_}) + + verified = verify_asymmetric_rsa(project_id, location_id, key_ring_id, asymmetric_sign_rsa_key_id, '1', message, sign_response.signature) + assert verified + + +def test_quickstart(project_id, location_id): + key_rings = quickstart(project_id, location_id) + assert key_rings diff --git a/kms/snippets/update_key_add_rotation.py b/kms/snippets/update_key_add_rotation.py new file mode 100644 index 000000000000..22dd6b6622fc --- /dev/null +++ b/kms/snippets/update_key_add_rotation.py @@ -0,0 +1,62 @@ +# Copyright 2020 Google LLC +# +# 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 + + +# [START kms_update_key_add_rotation_schedule] +def update_key_add_rotation(project_id, location_id, key_ring_id, key_id): + """ + Add a rotation schedule to an existing key. + + Args: + project_id (string): Google Cloud project ID (e.g. 'my-project'). + location_id (string): Cloud KMS location (e.g. 'us-east1'). + key_ring_id (string): ID of the Cloud KMS key ring (e.g. 'my-key-ring'). + key_id (string): ID of the key to use (e.g. 'my-key'). + + Returns: + CryptoKey: Updated Cloud KMS key. + + """ + + # Import the client library. + from google.cloud import kms + + # Import time for getting the current time. + import time + + # Create the client. + client = kms.KeyManagementServiceClient() + + # Build the key name. + key_name = client.crypto_key_path(project_id, location_id, key_ring_id, key_id) + + # Build the key. We need to build a full proto instead of a dict due to + # https://github.com/googleapis/gapic-generator-python/issues/364. + from google.cloud.kms_v1.proto import resources_pb2 + key = resources_pb2.CryptoKey() + key.name = key_name + + # Rotate the key every 30 days. + key.rotation_period.seconds = 60*60*24*30 + + # Start the first rotation in 24 hours. + key.next_rotation_time.seconds = int(time.time()) + 60*60*24 + + # Build the update mask. + update_mask = {'paths': ['rotation_period', 'next_rotation_time']} + + # Call the API. + updated_key = client.update_crypto_key(key, update_mask) + print('Updated key: {}'.format(updated_key.name)) + return updated_key +# [END kms_update_key_add_rotation_schedule] diff --git a/kms/snippets/update_key_remove_labels.py b/kms/snippets/update_key_remove_labels.py new file mode 100644 index 000000000000..a44ab214b7a8 --- /dev/null +++ b/kms/snippets/update_key_remove_labels.py @@ -0,0 +1,54 @@ +# Copyright 2020 Google LLC +# +# 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 + + +# [START kms_update_key_remove_labels] +def update_key_remove_labels(project_id, location_id, key_ring_id, key_id): + """ + Remove labels from an existing key. + + Args: + project_id (string): Google Cloud project ID (e.g. 'my-project'). + location_id (string): Cloud KMS location (e.g. 'us-east1'). + key_ring_id (string): ID of the Cloud KMS key ring (e.g. 'my-key-ring'). + key_id (string): ID of the key to use (e.g. 'my-key'). + + Returns: + CryptoKey: Updated Cloud KMS key. + + """ + + # Import the client library. + from google.cloud import kms + + # Create the client. + client = kms.KeyManagementServiceClient() + + # Build the key name. + key_name = client.crypto_key_path(project_id, location_id, key_ring_id, key_id) + + # Build the key. We need to build a full proto instead of a dict due to + # https://github.com/googleapis/gapic-generator-python/issues/364. + from google.cloud.kms_v1.proto import resources_pb2 + key = resources_pb2.CryptoKey() + key.name = key_name + key.labels.clear() + + # Build the update mask. + update_mask = {'paths': ['labels']} + + # Call the API. + updated_key = client.update_crypto_key(key, update_mask) + print('Updated key: {}'.format(updated_key.name)) + return updated_key +# [END kms_update_key_remove_labels] diff --git a/kms/snippets/update_key_remove_rotation.py b/kms/snippets/update_key_remove_rotation.py new file mode 100644 index 000000000000..7f8707eb6eb0 --- /dev/null +++ b/kms/snippets/update_key_remove_rotation.py @@ -0,0 +1,53 @@ +# Copyright 2020 Google LLC +# +# 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 + + +# [START kms_update_key_remove_rotation_schedule] +def update_key_remove_rotation(project_id, location_id, key_ring_id, key_id): + """ + Remove a rotation schedule from an existing key. + + Args: + project_id (string): Google Cloud project ID (e.g. 'my-project'). + location_id (string): Cloud KMS location (e.g. 'us-east1'). + key_ring_id (string): ID of the Cloud KMS key ring (e.g. 'my-key-ring'). + key_id (string): ID of the key to use (e.g. 'my-key'). + + Returns: + CryptoKey: Updated Cloud KMS key. + + """ + + # Import the client library. + from google.cloud import kms + + # Create the client. + client = kms.KeyManagementServiceClient() + + # Build the key name. + key_name = client.crypto_key_path(project_id, location_id, key_ring_id, key_id) + + # Build the key. We need to build a full proto instead of a dict due to + # https://github.com/googleapis/gapic-generator-python/issues/364. + from google.cloud.kms_v1.proto import resources_pb2 + key = resources_pb2.CryptoKey() + key.name = key_name + + # Build the update mask. + update_mask = {'paths': ['rotation_period', 'next_rotation_time']} + + # Call the API. + updated_key = client.update_crypto_key(key, update_mask) + print('Updated key: {}'.format(updated_key.name)) + return updated_key +# [END kms_update_key_remove_rotation_schedule] diff --git a/kms/snippets/update_key_set_primary.py b/kms/snippets/update_key_set_primary.py new file mode 100644 index 000000000000..dd889dbd407f --- /dev/null +++ b/kms/snippets/update_key_set_primary.py @@ -0,0 +1,45 @@ +# Copyright 2020 Google LLC +# +# 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 + + +# [START kms_update_key_set_primary] +def update_key_set_primary(project_id, location_id, key_ring_id, key_id, version_id): + """ + Update the primary version of a key. + + Args: + project_id (string): Google Cloud project ID (e.g. 'my-project'). + location_id (string): Cloud KMS location (e.g. 'us-east1'). + key_ring_id (string): ID of the Cloud KMS key ring (e.g. 'my-key-ring'). + key_id (string): ID of the key to use (e.g. 'my-key'). + version_id (string): ID of the key to make primary (e.g. '2'). + + Returns: + CryptoKey: Updated Cloud KMS key. + + """ + + # Import the client library. + from google.cloud import kms + + # Create the client. + client = kms.KeyManagementServiceClient() + + # Build the key name. + key_name = client.crypto_key_path(project_id, location_id, key_ring_id, key_id) + + # Call the API. + updated_key = client.update_crypto_key_primary_version(key_name, version_id) + print('Updated {} primary to {}'.format(updated_key.name, version_id)) + return updated_key +# [END kms_update_key_set_primary] diff --git a/kms/snippets/update_key_update_labels.py b/kms/snippets/update_key_update_labels.py new file mode 100644 index 000000000000..21372472bc2a --- /dev/null +++ b/kms/snippets/update_key_update_labels.py @@ -0,0 +1,54 @@ +# Copyright 2020 Google LLC +# +# 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 + + +# [START kms_update_key_update_labels] +def update_key_update_labels(project_id, location_id, key_ring_id, key_id): + """ + Update labels on an existing key. + + Args: + project_id (string): Google Cloud project ID (e.g. 'my-project'). + location_id (string): Cloud KMS location (e.g. 'us-east1'). + key_ring_id (string): ID of the Cloud KMS key ring (e.g. 'my-key-ring'). + key_id (string): ID of the key to use (e.g. 'my-key'). + + Returns: + CryptoKey: Updated Cloud KMS key. + + """ + + # Import the client library. + from google.cloud import kms + + # Create the client. + client = kms.KeyManagementServiceClient() + + # Build the key name. + key_name = client.crypto_key_path(project_id, location_id, key_ring_id, key_id) + + # Build the key. We need to build a full proto instead of a dict due to + # https://github.com/googleapis/gapic-generator-python/issues/364. + from google.cloud.kms_v1.proto import resources_pb2 + key = resources_pb2.CryptoKey() + key.name = key_name + key.labels.update({'new_label': 'new_value'}) + + # Build the update mask. + update_mask = {'paths': ['labels']} + + # Call the API. + updated_key = client.update_crypto_key(key, update_mask) + print('Updated key: {}'.format(updated_key.name)) + return updated_key +# [END kms_update_key_update_labels] diff --git a/kms/snippets/verify_asymmetric_ec.py b/kms/snippets/verify_asymmetric_ec.py new file mode 100644 index 000000000000..ac77a64b8681 --- /dev/null +++ b/kms/snippets/verify_asymmetric_ec.py @@ -0,0 +1,72 @@ +# Copyright 2020 Google LLC +# +# 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 + + +# [START kms_verify_asymmetric_signature_ec] +def verify_asymmetric_ec(project_id, location_id, key_ring_id, key_id, version_id, message, signature): + """ + Verify the signature of an message signed with an asymmetric EC key. + + Args: + project_id (string): Google Cloud project ID (e.g. 'my-project'). + location_id (string): Cloud KMS location (e.g. 'us-east1'). + key_ring_id (string): ID of the Cloud KMS key ring (e.g. 'my-key-ring'). + key_id (string): ID of the key to use (e.g. 'my-key'). + version_id (string): ID of the version to use (e.g. '1'). + message (string): Original message (e.g. 'my message') + signature (bytes): Signature from a sign request. + + Returns: + bool: True if verified, False otherwise + + """ + + # Import the client library. + from google.cloud import kms + + # Import cryptographic helpers from the cryptography package. + from cryptography.exceptions import InvalidSignature + from cryptography.hazmat.backends import default_backend + from cryptography.hazmat.primitives import hashes, serialization + from cryptography.hazmat.primitives.asymmetric import ec, utils + + # Import hashlib. + import hashlib + + # Convert the message to bytes. + message_bytes = message.encode('utf-8') + + # Create the client. + client = kms.KeyManagementServiceClient() + + # Build the key version name. + key_version_name = client.crypto_key_version_path(project_id, location_id, key_ring_id, key_id, version_id) + + # Get the public key. + public_key = client.get_public_key(key_version_name) + + # Extract and parse the public key as a PEM-encoded RSA key. + pem = public_key.pem.encode('utf-8') + ec_key = serialization.load_pem_public_key(pem, default_backend()) + hash_ = hashlib.sha256(message_bytes).digest() + + # Attempt to verify. + try: + sha256 = hashes.SHA256() + ec_key.verify(signature, hash_, ec.ECDSA(utils.Prehashed(sha256))) + print('Signature verified') + return True + except InvalidSignature: + print('Signature failed to verify') + return False +# [END kms_verify_asymmetric_signature_ec] diff --git a/kms/snippets/verify_asymmetric_rsa.py b/kms/snippets/verify_asymmetric_rsa.py new file mode 100644 index 000000000000..6df3d862f83b --- /dev/null +++ b/kms/snippets/verify_asymmetric_rsa.py @@ -0,0 +1,73 @@ +# Copyright 2020 Google LLC +# +# 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 + + +# [START kms_verify_asymmetric_signature_rsa] +def verify_asymmetric_rsa(project_id, location_id, key_ring_id, key_id, version_id, message, signature): + """ + Verify the signature of an message signed with an asymmetric RSA key. + + Args: + project_id (string): Google Cloud project ID (e.g. 'my-project'). + location_id (string): Cloud KMS location (e.g. 'us-east1'). + key_ring_id (string): ID of the Cloud KMS key ring (e.g. 'my-key-ring'). + key_id (string): ID of the key to use (e.g. 'my-key'). + version_id (string): ID of the version to use (e.g. '1'). + message (string): Original message (e.g. 'my message') + signature (bytes): Signature from a sign request. + + Returns: + bool: True if verified, False otherwise + + """ + + # Import the client library. + from google.cloud import kms + + # Import cryptographic helpers from the cryptography package. + from cryptography.exceptions import InvalidSignature + from cryptography.hazmat.backends import default_backend + from cryptography.hazmat.primitives import hashes, serialization + from cryptography.hazmat.primitives.asymmetric import padding, utils + + # Import hashlib. + import hashlib + + # Convert the message to bytes. + message_bytes = message.encode('utf-8') + + # Create the client. + client = kms.KeyManagementServiceClient() + + # Build the key version name. + key_version_name = client.crypto_key_version_path(project_id, location_id, key_ring_id, key_id, version_id) + + # Get the public key. + public_key = client.get_public_key(key_version_name) + + # Extract and parse the public key as a PEM-encoded RSA key. + pem = public_key.pem.encode('utf-8') + rsa_key = serialization.load_pem_public_key(pem, default_backend()) + hash_ = hashlib.sha256(message_bytes).digest() + + # Attempt to verify. + try: + sha256 = hashes.SHA256() + pad = padding.PKCS1v15() + rsa_key.verify(signature, hash_, pad, utils.Prehashed(sha256)) + print('Signature verified') + return True + except InvalidSignature: + print('Signature failed to verify') + return False +# [END kms_verify_asymmetric_signature_rsa] From 005b35b32d44d5fe1fed1ecaed7918217cdb4e0b Mon Sep 17 00:00:00 2001 From: Takashi Matsuo Date: Tue, 12 May 2020 17:30:32 -0700 Subject: [PATCH 048/136] chore: some lint fixes [(#3748)](https://github.com/GoogleCloudPlatform/python-docs-samples/issues/3748) --- kms/snippets/snippets_test.py | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/kms/snippets/snippets_test.py b/kms/snippets/snippets_test.py index c75b872c4121..795edeb47370 100644 --- a/kms/snippets/snippets_test.py +++ b/kms/snippets/snippets_test.py @@ -16,6 +16,12 @@ import time import uuid +from cryptography.exceptions import InvalidSignature +from cryptography.hazmat.backends import default_backend +from cryptography.hazmat.primitives import hashes, serialization +from cryptography.hazmat.primitives.asymmetric import padding, utils +from google.cloud import kms +from google.cloud.kms_v1.proto import resources_pb2 import pytest from create_key_asymmetric_decrypt import create_key_asymmetric_decrypt @@ -50,14 +56,6 @@ from verify_asymmetric_ec import verify_asymmetric_ec from verify_asymmetric_rsa import verify_asymmetric_rsa -from cryptography.exceptions import InvalidSignature -from cryptography.hazmat.backends import default_backend -from cryptography.hazmat.primitives import hashes, serialization -from cryptography.hazmat.primitives.asymmetric import padding, utils - -from google.cloud import kms -from google.cloud.kms_v1.proto import resources_pb2 - @pytest.fixture(scope="module") def client(): From cd445b9df5f60c51ef1cca39b86eca7c22d20362 Mon Sep 17 00:00:00 2001 From: Bu Sun Kim Date: Thu, 28 May 2020 01:45:21 +0000 Subject: [PATCH 049/136] chore: update templates --- kms/snippets/README.rst | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/kms/snippets/README.rst b/kms/snippets/README.rst index 3acb00f5d913..7a52a0817bf3 100644 --- a/kms/snippets/README.rst +++ b/kms/snippets/README.rst @@ -1,3 +1,4 @@ + .. This file is automatically generated. Do not edit this file directly. Google Cloud KMS API Python Samples @@ -14,10 +15,12 @@ This directory contains samples for Google Cloud KMS API. The `Google Cloud KMS .. _Google Cloud KMS API: https://cloud.google.com/kms/docs/ + Setup ------------------------------------------------------------------------------- + Authentication ++++++++++++++ @@ -28,6 +31,9 @@ credentials for applications. .. _Authentication Getting Started Guide: https://cloud.google.com/docs/authentication/getting-started + + + Install Dependencies ++++++++++++++++++++ @@ -42,7 +48,7 @@ Install Dependencies .. _Python Development Environment Setup Guide: https://cloud.google.com/python/setup -#. Create a virtualenv. Samples are compatible with Python 2.7 and 3.4+. +#. Create a virtualenv. Samples are compatible with Python 3.6+. .. code-block:: bash @@ -58,9 +64,15 @@ Install Dependencies .. _pip: https://pip.pypa.io/ .. _virtualenv: https://virtualenv.pypa.io/ + + + + + Samples ------------------------------------------------------------------------------- + Quickstart +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ @@ -79,4 +91,8 @@ To run this sample: -.. _Google Cloud SDK: https://cloud.google.com/sdk/ \ No newline at end of file + + + + +.. _Google Cloud SDK: https://cloud.google.com/sdk/ From b7f93668585241fcdec2436e95513432208fe0a3 Mon Sep 17 00:00:00 2001 From: Bu Sun Kim Date: Thu, 28 May 2020 01:56:36 +0000 Subject: [PATCH 050/136] chore: update templates --- kms/snippets/noxfile.py | 225 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 225 insertions(+) create mode 100644 kms/snippets/noxfile.py diff --git a/kms/snippets/noxfile.py b/kms/snippets/noxfile.py new file mode 100644 index 000000000000..b23055f14a65 --- /dev/null +++ b/kms/snippets/noxfile.py @@ -0,0 +1,225 @@ +# Copyright 2019 Google LLC +# +# 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. + +from __future__ import print_function + +import os +from pathlib import Path +import sys + +import nox + + +# WARNING - WARNING - WARNING - WARNING - WARNING +# WARNING - WARNING - WARNING - WARNING - WARNING +# DO NOT EDIT THIS FILE EVER! +# WARNING - WARNING - WARNING - WARNING - WARNING +# WARNING - WARNING - WARNING - WARNING - WARNING + +# Copy `noxfile_config.py` to your directory and modify it instead. + + +# `TEST_CONFIG` dict is a configuration hook that allows users to +# modify the test configurations. The values here should be in sync +# with `noxfile_config.py`. Users will copy `noxfile_config.py` into +# their directory and modify it. + +TEST_CONFIG = { + # You can opt out from the test for specific Python versions. + 'ignored_versions': ["2.7"], + + # An envvar key for determining the project id to use. Change it + # to 'BUILD_SPECIFIC_GCLOUD_PROJECT' if you want to opt in using a + # build specific Cloud project. You can also use your own string + # to use your own Cloud project. + 'gcloud_project_env': 'GCLOUD_PROJECT', + # 'gcloud_project_env': 'BUILD_SPECIFIC_GCLOUD_PROJECT', + + # A dictionary you want to inject into your test. Don't put any + # secrets here. These values will override predefined values. + 'envs': {}, +} + + +try: + # Ensure we can import noxfile_config in the project's directory. + sys.path.append('.') + from noxfile_config import TEST_CONFIG_OVERRIDE +except ImportError as e: + print("No user noxfile_config found: detail: {}".format(e)) + TEST_CONFIG_OVERRIDE = {} + +# Update the TEST_CONFIG with the user supplied values. +TEST_CONFIG.update(TEST_CONFIG_OVERRIDE) + + +def get_pytest_env_vars(): + """Returns a dict for pytest invocation.""" + ret = {} + + # Override the GCLOUD_PROJECT and the alias. + env_key = TEST_CONFIG['gcloud_project_env'] + # This should error out if not set. + ret['GOOGLE_CLOUD_PROJECT'] = os.environ[env_key] + ret['GCLOUD_PROJECT'] = os.environ[env_key] + + # Apply user supplied envs. + ret.update(TEST_CONFIG['envs']) + return ret + + +# DO NOT EDIT - automatically generated. +# All versions used to tested samples. +ALL_VERSIONS = ["2.7", "3.6", "3.7", "3.8"] + +# Any default versions that should be ignored. +IGNORED_VERSIONS = TEST_CONFIG['ignored_versions'] + +TESTED_VERSIONS = sorted([v for v in ALL_VERSIONS if v not in IGNORED_VERSIONS]) + +INSTALL_LIBRARY_FROM_SOURCE = bool(os.environ.get("INSTALL_LIBRARY_FROM_SOURCE", False)) +# +# Style Checks +# + + +def _determine_local_import_names(start_dir): + """Determines all import names that should be considered "local". + + This is used when running the linter to insure that import order is + properly checked. + """ + file_ext_pairs = [os.path.splitext(path) for path in os.listdir(start_dir)] + return [ + basename + for basename, extension in file_ext_pairs + if extension == ".py" + or os.path.isdir(os.path.join(start_dir, basename)) + and basename not in ("__pycache__") + ] + + +# Linting with flake8. +# +# We ignore the following rules: +# E203: whitespace before ‘:’ +# E266: too many leading ‘#’ for block comment +# E501: line too long +# I202: Additional newline in a section of imports +# +# We also need to specify the rules which are ignored by default: +# ['E226', 'W504', 'E126', 'E123', 'W503', 'E24', 'E704', 'E121'] +FLAKE8_COMMON_ARGS = [ + "--show-source", + "--builtin=gettext", + "--max-complexity=20", + "--import-order-style=google", + "--exclude=.nox,.cache,env,lib,generated_pb2,*_pb2.py,*_pb2_grpc.py", + "--ignore=E121,E123,E126,E203,E226,E24,E266,E501,E704,W503,W504,I202", + "--max-line-length=88", +] + + +@nox.session +def lint(session): + session.install("flake8", "flake8-import-order") + + local_names = _determine_local_import_names(".") + args = FLAKE8_COMMON_ARGS + [ + "--application-import-names", + ",".join(local_names), + "." + ] + session.run("flake8", *args) + + +# +# Sample Tests +# + + +PYTEST_COMMON_ARGS = ["--junitxml=sponge_log.xml"] + + +def _session_tests(session, post_install=None): + """Runs py.test for a particular project.""" + if os.path.exists("requirements.txt"): + session.install("-r", "requirements.txt") + + if os.path.exists("requirements-test.txt"): + session.install("-r", "requirements-test.txt") + + if INSTALL_LIBRARY_FROM_SOURCE: + session.install("-e", _get_repo_root()) + + if post_install: + post_install(session) + + session.run( + "pytest", + *(PYTEST_COMMON_ARGS + session.posargs), + # Pytest will return 5 when no tests are collected. This can happen + # on travis where slow and flaky tests are excluded. + # See http://doc.pytest.org/en/latest/_modules/_pytest/main.html + success_codes=[0, 5], + env=get_pytest_env_vars() + ) + + +@nox.session(python=ALL_VERSIONS) +def py(session): + """Runs py.test for a sample using the specified version of Python.""" + if session.python in TESTED_VERSIONS: + _session_tests(session) + else: + session.skip("SKIPPED: {} tests are disabled for this sample.".format( + session.python + )) + + +# +# Readmegen +# + + +def _get_repo_root(): + """ Returns the root folder of the project. """ + # Get root of this repository. Assume we don't have directories nested deeper than 10 items. + p = Path(os.getcwd()) + for i in range(10): + if p is None: + break + if Path(p / ".git").exists(): + return str(p) + p = p.parent + raise Exception("Unable to detect repository root.") + + +GENERATED_READMES = sorted([x for x in Path(".").rglob("*.rst.in")]) + + +@nox.session +@nox.parametrize("path", GENERATED_READMES) +def readmegen(session, path): + """(Re-)generates the readme for a sample.""" + session.install("jinja2", "pyyaml") + dir_ = os.path.dirname(path) + + if os.path.exists(os.path.join(dir_, "requirements.txt")): + session.install("-r", os.path.join(dir_, "requirements.txt")) + + in_file = os.path.join(dir_, "README.rst.in") + session.run( + "python", _get_repo_root() + "/scripts/readme-gen/readme_gen.py", in_file + ) From aecda49f74409b96b370fcc606995d4487f8d6ca Mon Sep 17 00:00:00 2001 From: Benson Kuang <3453547+bkuang@users.noreply.github.com> Date: Fri, 1 May 2020 13:30:27 -0400 Subject: [PATCH 051/136] Add kms/attestations/ directory with sample script to verify attestations [(#3262)](https://github.com/GoogleCloudPlatform/python-docs-samples/issues/3262) Co-authored-by: Benson Kuang Co-authored-by: Takashi Matsuo --- kms/attestations/README.rst.in | 19 ++++ kms/attestations/requirements-test.txt | 1 + kms/attestations/requirements.txt | 2 + kms/attestations/verify_attestation.py | 71 +++++++++++++ kms/attestations/verify_attestation_test.py | 109 ++++++++++++++++++++ 5 files changed, 202 insertions(+) create mode 100644 kms/attestations/README.rst.in create mode 100644 kms/attestations/requirements-test.txt create mode 100644 kms/attestations/requirements.txt create mode 100644 kms/attestations/verify_attestation.py create mode 100644 kms/attestations/verify_attestation_test.py diff --git a/kms/attestations/README.rst.in b/kms/attestations/README.rst.in new file mode 100644 index 000000000000..3e188a17a5e0 --- /dev/null +++ b/kms/attestations/README.rst.in @@ -0,0 +1,19 @@ +# This file is used to generate README.rst + +product: + name: Google Cloud Key Management Service + short_name: Cloud Key Management Service + url: https://cloud.google.com/kms/docs/ + description: > + The `Cloud Key Management Service`_ allows you to create, import, and manage + cryptographic keys and perform cryptographic operations in a single centralized cloud service. + +setup: +- install_deps + +samples: +- name: Verify attestations for keys generated by Cloud HSM + file: verify_attestation.py + show_help: True + +folder: kms/attestations diff --git a/kms/attestations/requirements-test.txt b/kms/attestations/requirements-test.txt new file mode 100644 index 000000000000..781d4326c947 --- /dev/null +++ b/kms/attestations/requirements-test.txt @@ -0,0 +1 @@ +pytest==5.3.2 diff --git a/kms/attestations/requirements.txt b/kms/attestations/requirements.txt new file mode 100644 index 000000000000..036cf984150d --- /dev/null +++ b/kms/attestations/requirements.txt @@ -0,0 +1,2 @@ +cryptography==2.8 +pem==20.1.0 diff --git a/kms/attestations/verify_attestation.py b/kms/attestations/verify_attestation.py new file mode 100644 index 000000000000..69c16425f78c --- /dev/null +++ b/kms/attestations/verify_attestation.py @@ -0,0 +1,71 @@ +#!/usr/bin/env python + +# Copyright 2020 Google, LLC. +# +# 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. + +"""This sample demonstrates how to verify HSM attestations using certificate +bundles obtained from Cloud HSM. + +For more information, visit https://cloud.google.com/kms/docs/attest-key. +""" + +# [START verify_attestations] +import gzip + +from cryptography import exceptions +from cryptography import x509 +from cryptography.hazmat import backends +from cryptography.hazmat.primitives.asymmetric import padding +import pem + + +def verify(attestation_file, bundle_file): + """Verifies an attestation using a bundle of certificates. + + Args: + attestation_file: The name of the attestation file. + bundle_file: The name of the bundle file containing the certificates + used to verify the attestation. + + Returns: + True if at least one of the certificates in bundle_file can verify the + attestation data and its signature. + """ + with gzip.open(attestation_file, 'rb') as f: + # An attestation file consists of a data portion and a 256 byte + # signature portion concatenated together. + attestation = f.read() + # Separate the components. + data = attestation[:-256] + signature = attestation[-256:] + + # Verify the attestation with one of the certificates in the bundle + for cert in pem.parse_file(bundle_file): + cert_obj = x509.load_pem_x509_certificate( + str(cert).encode('utf-8'), backends.default_backend()) + try: + # Check if the data was signed by the private key assosicated + # with the public key in the certificate. The data should have + # been signed with PKCS1v15 padding. + cert_obj.public_key().verify( + signature, data, padding.PKCS1v15(), + cert_obj.signature_hash_algorithm) + return True + except exceptions.InvalidSignature: + # Certificate bundles contain certificates that will not be + # able to verify the attestation, so the InvalidSignature + # errors can be ignored. + continue + return False +# [END verify_attestations] diff --git a/kms/attestations/verify_attestation_test.py b/kms/attestations/verify_attestation_test.py new file mode 100644 index 000000000000..5cdc5ef2deef --- /dev/null +++ b/kms/attestations/verify_attestation_test.py @@ -0,0 +1,109 @@ +# Copyright 2020 Google, LLC. +# +# 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. + +import tempfile + +import verify_attestation + +# Test certificate bundles can be generated with the following steps: +# 1. Generate test key pairs. +# - openssl genrsa -out test1.key 2048 +# - openssl genrsa -out test2.key 2048 +# 2. Generate test certificates using the key pairs. +# - openssl req -x509 -key test1.key -days 3650 -out test1.pem +# - openssl req -x509 -key test2.key -days 3650 -out test2.pem +# 3. Create a bundle using the test certificates. +# - cat test1.pem test2.pem > bundle.pem +# For instructions on downloading certificate bundles from Cloud HSM, refer to: +# https://cloud.google.com/kms/docs/attest-key#downloading_the_certificates +TEST_CERT_BUNDLE = b"""-----BEGIN CERTIFICATE----- +MIIDZDCCAkwCFE2PSNf++wMw+Jv86m41lbsa9aUMMA0GCSqGSIb3DQEBCwUAMFkx +CzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRl +cm5ldCBXaWRnaXRzIFB0eSBMdGQxEjAQBgNVBAMMCVRlc3QgQ2FyZDAeFw0yMDAz +MzEyMTQ0MjNaFw0zMDAzMjkyMTQ0MjNaMIGDMQswCQYDVQQGEwJBVTETMBEGA1UE +CAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRk +MSMwIQYDVQQLDBpjbG91ZC1rbXMtcHJvZC11cy1jZW50cmFsMTEXMBUGA1UEAwwO +VGVzdCBQYXJ0aXRpb24wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDh +cOk8hil8G4vl66jb02eXu2rKO6PmNF1GziXtzawyhx/+PDmEuGu+g/8hpivY6vDr +buAMFs8OIBBBlfED/soVANflXktDRGqWJau+rIrw9EGcclcwzlIboIi6KLPcLih0 +N0TTxqRLgy2EsEQ6UKS7su4bOIxD3Z6FSeTsoq+C2sgSWXmLitO0iRYYcgRjoyCU +kdzzO/JCwPKhhQx5NUrrHseALaIltG4D0aWLuBZKyV38yA1XEMdyCGk7RedEYC+v +OzaJrNToQBCIaCdn3F0uqJd49irLNPyQ5CY3NNL8rupJSq3iVxhEIZ8ANaU8UDvo +5iaQNKV1/KiQsXfUW6fbAgMBAAEwDQYJKoZIhvcNAQELBQADggEBAIIGB0aXhd6k +xyWgYzJ0DHpYP2ALwHRWXde5PtEkdHDguPlUTzZ5iTfqOJlEeUXlDO9RV82jc4mE +hguCaMl3Q+2JGLJLCnSDgcaY5WAVBF9FSakdbHBj4Ik9L8NDlUQB6Me4d4gKWpg1 +bUD4n2KtvCZGZzA3pfRBcYyAbwC+xEi1XrITyshb0pkjsWO4Urg36W/RpkCiYAw0 +Xua0jJMG/wcF+xktd7kgcsBh5Es2VCzyQwisXoOIi3EY7lMJK2+ctjQFy1GxumBU +jBlXj0VjAm3QOVLTh3mfb1XofoIjOOYkMBjXMiQhFy/Lv68u5q7qlEYe92OKxkCO +0UaAcqt8+QM= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDRjCCAi4CFBVm+eV+oRkaYq2NyuTfwxWapjFOMA0GCSqGSIb3DQEBCwUAMGYx +CzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRl +cm5ldCBXaWRnaXRzIFB0eSBMdGQxHzAdBgNVBAMMFlRlc3QgTWFudWZhY3R1cmVy +IFJvb3QwHhcNMjAwMzMxMjE0MjU1WhcNMzAwMzI5MjE0MjU1WjBZMQswCQYDVQQG +EwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lk +Z2l0cyBQdHkgTHRkMRIwEAYDVQQDDAlUZXN0IENhcmQwggEiMA0GCSqGSIb3DQEB +AQUAA4IBDwAwggEKAoIBAQC28Wu0dusN6AYkYon8RIuHlJWWwZWlTxXSMK4v/IOY +pG9F2/gUEDMQOgpyCCpTc5eLHRPa/Z2QgB0c2VSlQC8FZ1l9/YL7uBTJ0UpDoBf8 +LUimIqotneXpL+7CW1kWFLZIgpm0iVuTPjV2b3frtvu0B+nYuyo4dtToebqoOKse +F3ymLsAjSqA9aoCD0XbspAkLJIvdQU28vXY4Y2y0OTGUnaQ7ZDwkNLxeAfeIdNJD +FRCcYsLRopsyptFMYLLDrI70gywAGYaGOxYG8747BIZELyT5Gnt0o7JwpuF8Mi53 +T5NGiu5/wLwXnxRRhb3M5+lStdTfvbEfgK1mC0ac8ym5AgMBAAEwDQYJKoZIhvcN +AQELBQADggEBAILH0Q8WlgaGBosPBjnpAsp4eZOfq9skKZERYzFA2wBAy4B0q9/S +3oL1MIZEU6/ckiFyAm3r4/ZxMLX0UrisuRQUFQ3w+gqFccqlmGETsZGJpPtfIm+n +JQo44XXnTHndqoYPNfvfQkp0WtJQS8hSgTASP+1GYjqOn1fZaa28m39/mx9Mrw7K +xtXOtrdKqJhWCWJPprfC5sYNCYTA2HXVmBU2Y4AP4A4w+A1gCAdzvH8EEyDjnvxJ +GEa4uczhA3n+NmhLipg1aGbxJO5ZHXdyFF2rTXVVXSiX8EEasnwcTDjeXDKhdpu6 +biaxW9fnsJIXirAE03FFkC/tWelkGFkmMfs= +-----END CERTIFICATE-----""" + +# Test attestations can be generated with the following steps: +# 1. Create a file containing the test attestation statement. +# - echo "content" > attestation.dat +# 2. Sign the file with one the key pairs used to create the test certificates. +# - openssl dgst -sha256 -sign test1.key -out signature.dat attestation.dat +# 3. Concatenate the signature to the statement to create an attestation. +# - cat signature.dat >> attestation.dat +# 4. Compress the test attestation. +# - gzip attestation.dat +# For instructions on downloading attestations from Cloud HSM, refer to: +# https://cloud.google.com/kms/docs/attest-key#downloading_the_attestation_statement +TEST_ATTESTATION_GZ = ( + b'\x1f\x8b\x08\x08\xda\xde\x84^\x00\x03attestation\x00\x01\x06\x01\xf9\xfe' + b'\x15\xa7~W\xdazHq03\x95\xd1F\xcf\x1d\n\xe0\xbbv\x11\xed\xae\x186\xc0\xcc' + b'.\xcf)\xf1?\xf7!\xf3\xd6M\x85\xfe\xb9\x84\xb2\x08V2(\xa1\x87]\xab\x01=' + b'\xb5\x0f)~\x06\xee\xfa/\x94\xa6x\x96o\xb1\xcb$\x82\x90\xe03J\t\x03\xf0' + b'\xa4\xa5\xa9\xf9\xb2\xce\xdd2\xfam\x94W\x07\x00~\xa5\xc2\xcdq\xa1\x81' + b'\x18\x83\xe0\xd9\x11k]\xbd\xf8\x81@\x9c*\x80\x91R\xb0\xae\x9d\x88\xb8T' + b'\xd1>\xf6;\xe4\x83q%_\x8aw\x894\xb5:\xeab\xd2\x9a\x81\xdd\xa6\xf9\x94' + b'\xff8\xb1\xed\x7fs\x0e\xc0\xde\x89\x00]\x8fL\x82\x8a\x11\x8f\\\xe483\x9d' + b'&\x0b%\xfd\x0et\x8f\xa8\x1a\xb5K\xb4\xc7\x96\xd1}\x06\xdd\x93i\x1f\xc1@' + b'\x92\xef}(B\x0f\xd1\x03\xaaYo\x9b\xad\xa9zw#\xc8\x9a\xad\x94\xfc\x07q]x' + b'\xeb\xa2CA\xf8\xac\x96\xd9\xe5y4\xae]\x81\xb0$\x93\tx\xdb\xcc\x08:%\x1d' + b'\xe2q\xaa\xc8:\xc2 Date: Tue, 5 May 2020 01:39:22 +0200 Subject: [PATCH 052/136] chore(deps): update dependency cryptography to v2.9.2 [(#3666)](https://github.com/GoogleCloudPlatform/python-docs-samples/issues/3666) Co-authored-by: Takashi Matsuo --- kms/attestations/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kms/attestations/requirements.txt b/kms/attestations/requirements.txt index 036cf984150d..9f3e724fee12 100644 --- a/kms/attestations/requirements.txt +++ b/kms/attestations/requirements.txt @@ -1,2 +1,2 @@ -cryptography==2.8 +cryptography==2.9.2 pem==20.1.0 From 63607043fc8509b16f6ae69873373c63fb95c22e Mon Sep 17 00:00:00 2001 From: Seth Vargo Date: Tue, 5 May 2020 18:46:19 -0400 Subject: [PATCH 053/136] Update and add Cloud KMS samples [(#3690)](https://github.com/GoogleCloudPlatform/python-docs-samples/issues/3690) This updates the Cloud KMS samples to match the format from the other 6 languages. It also updates the samples to note the workaround for https://github.com/googleapis/gapic-generator-python/issues/364. --- kms/attestations/README.rst | 74 ++++++++++++++++++++++++++ kms/attestations/requirements-test.txt | 2 +- 2 files changed, 75 insertions(+), 1 deletion(-) create mode 100644 kms/attestations/README.rst diff --git a/kms/attestations/README.rst b/kms/attestations/README.rst new file mode 100644 index 000000000000..dddddfbcd7d3 --- /dev/null +++ b/kms/attestations/README.rst @@ -0,0 +1,74 @@ +.. This file is automatically generated. Do not edit this file directly. + +Google Cloud Key Management Service Python Samples +=============================================================================== + +.. image:: https://gstatic.com/cloudssh/images/open-btn.png + :target: https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/GoogleCloudPlatform/python-docs-samples&page=editor&open_in_editor=kms/attestations/README.rst + + +This directory contains samples for Google Cloud Key Management Service. The `Cloud Key Management Service`_ allows you to create, import, and manage cryptographic keys and perform cryptographic operations in a single centralized cloud service. + + + + +.. _Google Cloud Key Management Service: https://cloud.google.com/kms/docs/ + +Setup +------------------------------------------------------------------------------- + + +Install Dependencies +++++++++++++++++++++ + +#. Clone python-docs-samples and change directory to the sample directory you want to use. + + .. code-block:: bash + + $ git clone https://github.com/GoogleCloudPlatform/python-docs-samples.git + +#. Install `pip`_ and `virtualenv`_ if you do not already have them. You may want to refer to the `Python Development Environment Setup Guide`_ for Google Cloud Platform for instructions. + + .. _Python Development Environment Setup Guide: + https://cloud.google.com/python/setup + +#. Create a virtualenv. Samples are compatible with Python 2.7 and 3.4+. + + .. code-block:: bash + + $ virtualenv env + $ source env/bin/activate + +#. Install the dependencies needed to run the samples. + + .. code-block:: bash + + $ pip install -r requirements.txt + +.. _pip: https://pip.pypa.io/ +.. _virtualenv: https://virtualenv.pypa.io/ + +Samples +------------------------------------------------------------------------------- + +Verify attestations for keys generated by Cloud HSM ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +.. image:: https://gstatic.com/cloudssh/images/open-btn.png + :target: https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/GoogleCloudPlatform/python-docs-samples&page=editor&open_in_editor=kms/attestations/verify_attestation.py,kms/attestations/README.rst + + + + +To run this sample: + +.. code-block:: bash + + $ python verify_attestation.py + + + + + + +.. _Google Cloud SDK: https://cloud.google.com/sdk/ \ No newline at end of file diff --git a/kms/attestations/requirements-test.txt b/kms/attestations/requirements-test.txt index 781d4326c947..d3e30fa6c737 100644 --- a/kms/attestations/requirements-test.txt +++ b/kms/attestations/requirements-test.txt @@ -1 +1 @@ -pytest==5.3.2 +pytest==5.4.1 From 7084ad4b0da57fc7318cb2f4a7bd5557428e75f5 Mon Sep 17 00:00:00 2001 From: Benson Kuang <3453547+bkuang@users.noreply.github.com> Date: Fri, 15 May 2020 15:47:27 -0400 Subject: [PATCH 054/136] Add main function to attestation verification script [(#3705)](https://github.com/GoogleCloudPlatform/python-docs-samples/issues/3705) * Add main function to attestation verification script. fixes #3704 * Add newline to end of file * remove a blank line at the end Co-authored-by: Benson Kuang Co-authored-by: Takashi Matsuo --- kms/attestations/verify_attestation.py | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/kms/attestations/verify_attestation.py b/kms/attestations/verify_attestation.py index 69c16425f78c..e534ad9eecb4 100644 --- a/kms/attestations/verify_attestation.py +++ b/kms/attestations/verify_attestation.py @@ -14,13 +14,14 @@ # See the License for the specific language governing permissions and # limitations under the License. -"""This sample demonstrates how to verify HSM attestations using certificate -bundles obtained from Cloud HSM. +"""This application verifies HSM attestations using certificate bundles +obtained from Cloud HSM. For more information, visit https://cloud.google.com/kms/docs/attest-key. """ # [START verify_attestations] +import argparse import gzip from cryptography import exceptions @@ -69,3 +70,17 @@ def verify(attestation_file, bundle_file): continue return False # [END verify_attestations] + + +if __name__ == '__main__': + parser = argparse.ArgumentParser( + description=__doc__) + parser.add_argument('attestation_file', help="Name of attestation file.") + parser.add_argument('bundle_file', help="Name of certificate bundle file.") + + args = parser.parse_args() + + if verify(args.attestation_file, args.bundle_file): + print('Signature verified.') + else: + print('Signature verification failed.') From 1bdb253257cd243edf2dc87d342332c0c38d61e3 Mon Sep 17 00:00:00 2001 From: Bu Sun Kim Date: Tue, 16 Jun 2020 22:44:31 +0000 Subject: [PATCH 055/136] test: add noxfile --- kms/attestations/noxfile.py | 225 ++++++++++++++++++++++++++++++++++++ 1 file changed, 225 insertions(+) create mode 100644 kms/attestations/noxfile.py diff --git a/kms/attestations/noxfile.py b/kms/attestations/noxfile.py new file mode 100644 index 000000000000..b23055f14a65 --- /dev/null +++ b/kms/attestations/noxfile.py @@ -0,0 +1,225 @@ +# Copyright 2019 Google LLC +# +# 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. + +from __future__ import print_function + +import os +from pathlib import Path +import sys + +import nox + + +# WARNING - WARNING - WARNING - WARNING - WARNING +# WARNING - WARNING - WARNING - WARNING - WARNING +# DO NOT EDIT THIS FILE EVER! +# WARNING - WARNING - WARNING - WARNING - WARNING +# WARNING - WARNING - WARNING - WARNING - WARNING + +# Copy `noxfile_config.py` to your directory and modify it instead. + + +# `TEST_CONFIG` dict is a configuration hook that allows users to +# modify the test configurations. The values here should be in sync +# with `noxfile_config.py`. Users will copy `noxfile_config.py` into +# their directory and modify it. + +TEST_CONFIG = { + # You can opt out from the test for specific Python versions. + 'ignored_versions': ["2.7"], + + # An envvar key for determining the project id to use. Change it + # to 'BUILD_SPECIFIC_GCLOUD_PROJECT' if you want to opt in using a + # build specific Cloud project. You can also use your own string + # to use your own Cloud project. + 'gcloud_project_env': 'GCLOUD_PROJECT', + # 'gcloud_project_env': 'BUILD_SPECIFIC_GCLOUD_PROJECT', + + # A dictionary you want to inject into your test. Don't put any + # secrets here. These values will override predefined values. + 'envs': {}, +} + + +try: + # Ensure we can import noxfile_config in the project's directory. + sys.path.append('.') + from noxfile_config import TEST_CONFIG_OVERRIDE +except ImportError as e: + print("No user noxfile_config found: detail: {}".format(e)) + TEST_CONFIG_OVERRIDE = {} + +# Update the TEST_CONFIG with the user supplied values. +TEST_CONFIG.update(TEST_CONFIG_OVERRIDE) + + +def get_pytest_env_vars(): + """Returns a dict for pytest invocation.""" + ret = {} + + # Override the GCLOUD_PROJECT and the alias. + env_key = TEST_CONFIG['gcloud_project_env'] + # This should error out if not set. + ret['GOOGLE_CLOUD_PROJECT'] = os.environ[env_key] + ret['GCLOUD_PROJECT'] = os.environ[env_key] + + # Apply user supplied envs. + ret.update(TEST_CONFIG['envs']) + return ret + + +# DO NOT EDIT - automatically generated. +# All versions used to tested samples. +ALL_VERSIONS = ["2.7", "3.6", "3.7", "3.8"] + +# Any default versions that should be ignored. +IGNORED_VERSIONS = TEST_CONFIG['ignored_versions'] + +TESTED_VERSIONS = sorted([v for v in ALL_VERSIONS if v not in IGNORED_VERSIONS]) + +INSTALL_LIBRARY_FROM_SOURCE = bool(os.environ.get("INSTALL_LIBRARY_FROM_SOURCE", False)) +# +# Style Checks +# + + +def _determine_local_import_names(start_dir): + """Determines all import names that should be considered "local". + + This is used when running the linter to insure that import order is + properly checked. + """ + file_ext_pairs = [os.path.splitext(path) for path in os.listdir(start_dir)] + return [ + basename + for basename, extension in file_ext_pairs + if extension == ".py" + or os.path.isdir(os.path.join(start_dir, basename)) + and basename not in ("__pycache__") + ] + + +# Linting with flake8. +# +# We ignore the following rules: +# E203: whitespace before ‘:’ +# E266: too many leading ‘#’ for block comment +# E501: line too long +# I202: Additional newline in a section of imports +# +# We also need to specify the rules which are ignored by default: +# ['E226', 'W504', 'E126', 'E123', 'W503', 'E24', 'E704', 'E121'] +FLAKE8_COMMON_ARGS = [ + "--show-source", + "--builtin=gettext", + "--max-complexity=20", + "--import-order-style=google", + "--exclude=.nox,.cache,env,lib,generated_pb2,*_pb2.py,*_pb2_grpc.py", + "--ignore=E121,E123,E126,E203,E226,E24,E266,E501,E704,W503,W504,I202", + "--max-line-length=88", +] + + +@nox.session +def lint(session): + session.install("flake8", "flake8-import-order") + + local_names = _determine_local_import_names(".") + args = FLAKE8_COMMON_ARGS + [ + "--application-import-names", + ",".join(local_names), + "." + ] + session.run("flake8", *args) + + +# +# Sample Tests +# + + +PYTEST_COMMON_ARGS = ["--junitxml=sponge_log.xml"] + + +def _session_tests(session, post_install=None): + """Runs py.test for a particular project.""" + if os.path.exists("requirements.txt"): + session.install("-r", "requirements.txt") + + if os.path.exists("requirements-test.txt"): + session.install("-r", "requirements-test.txt") + + if INSTALL_LIBRARY_FROM_SOURCE: + session.install("-e", _get_repo_root()) + + if post_install: + post_install(session) + + session.run( + "pytest", + *(PYTEST_COMMON_ARGS + session.posargs), + # Pytest will return 5 when no tests are collected. This can happen + # on travis where slow and flaky tests are excluded. + # See http://doc.pytest.org/en/latest/_modules/_pytest/main.html + success_codes=[0, 5], + env=get_pytest_env_vars() + ) + + +@nox.session(python=ALL_VERSIONS) +def py(session): + """Runs py.test for a sample using the specified version of Python.""" + if session.python in TESTED_VERSIONS: + _session_tests(session) + else: + session.skip("SKIPPED: {} tests are disabled for this sample.".format( + session.python + )) + + +# +# Readmegen +# + + +def _get_repo_root(): + """ Returns the root folder of the project. """ + # Get root of this repository. Assume we don't have directories nested deeper than 10 items. + p = Path(os.getcwd()) + for i in range(10): + if p is None: + break + if Path(p / ".git").exists(): + return str(p) + p = p.parent + raise Exception("Unable to detect repository root.") + + +GENERATED_READMES = sorted([x for x in Path(".").rglob("*.rst.in")]) + + +@nox.session +@nox.parametrize("path", GENERATED_READMES) +def readmegen(session, path): + """(Re-)generates the readme for a sample.""" + session.install("jinja2", "pyyaml") + dir_ = os.path.dirname(path) + + if os.path.exists(os.path.join(dir_, "requirements.txt")): + session.install("-r", os.path.join(dir_, "requirements.txt")) + + in_file = os.path.join(dir_, "README.rst.in") + session.run( + "python", _get_repo_root() + "/scripts/readme-gen/readme_gen.py", in_file + ) From cd681446a45d0dbc2d93cd5dd9a404ba3f739416 Mon Sep 17 00:00:00 2001 From: WhiteSource Renovate Date: Wed, 29 Jul 2020 00:15:23 +0200 Subject: [PATCH 056/136] chore(deps): update dependency cryptography to v3 (#24) --- kms/attestations/requirements.txt | 2 +- kms/snippets/requirements.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/kms/attestations/requirements.txt b/kms/attestations/requirements.txt index 9f3e724fee12..c8639da017b8 100644 --- a/kms/attestations/requirements.txt +++ b/kms/attestations/requirements.txt @@ -1,2 +1,2 @@ -cryptography==2.9.2 +cryptography==3.0 pem==20.1.0 diff --git a/kms/snippets/requirements.txt b/kms/snippets/requirements.txt index 6e2cc2a4558b..f829e4a9caf6 100644 --- a/kms/snippets/requirements.txt +++ b/kms/snippets/requirements.txt @@ -1,2 +1,2 @@ google-cloud-kms==1.4.0 -cryptography==2.9.2 +cryptography==3.0 From 656593d53e0107b6169ac9d2734b5564ac30b604 Mon Sep 17 00:00:00 2001 From: Bu Sun Kim <8822365+busunkim96@users.noreply.github.com> Date: Thu, 30 Jul 2020 13:35:29 -0700 Subject: [PATCH 057/136] feat!: migrate to microgenerator. (#16) --- kms/attestations/README.rst | 29 +++- kms/attestations/noxfile.py | 3 +- kms/snippets/create_key_asymmetric_decrypt.py | 6 +- kms/snippets/create_key_asymmetric_sign.py | 6 +- kms/snippets/create_key_hsm.py | 8 +- kms/snippets/create_key_labels.py | 6 +- kms/snippets/create_key_ring.py | 4 +- kms/snippets/create_key_rotation_schedule.py | 6 +- .../create_key_symmetric_encrypt_decrypt.py | 6 +- kms/snippets/create_key_version.py | 2 +- kms/snippets/decrypt_asymmetric.py | 2 +- kms/snippets/decrypt_symmetric.py | 2 +- kms/snippets/destroy_key_version.py | 2 +- kms/snippets/disable_key_version.py | 12 +- kms/snippets/enable_key_version.py | 12 +- kms/snippets/encrypt_asymmetric.py | 2 +- kms/snippets/encrypt_symmetric.py | 2 +- kms/snippets/get_key_labels.py | 2 +- kms/snippets/get_key_version_attestation.py | 2 +- kms/snippets/get_public_key.py | 2 +- kms/snippets/iam_add_member.py | 9 +- kms/snippets/iam_get_policy.py | 2 +- kms/snippets/iam_remove_member.py | 8 +- kms/snippets/noxfile.py | 3 +- kms/snippets/quickstart.py | 4 +- kms/snippets/restore_key_version.py | 2 +- kms/snippets/sign_asymmetric.py | 2 +- kms/snippets/snippets_test.py | 132 +++++++++--------- kms/snippets/update_key_add_rotation.py | 22 ++- kms/snippets/update_key_remove_labels.py | 12 +- kms/snippets/update_key_remove_rotation.py | 10 +- kms/snippets/update_key_set_primary.py | 2 +- kms/snippets/update_key_update_labels.py | 14 +- kms/snippets/verify_asymmetric_ec.py | 2 +- kms/snippets/verify_asymmetric_rsa.py | 2 +- 35 files changed, 180 insertions(+), 162 deletions(-) diff --git a/kms/attestations/README.rst b/kms/attestations/README.rst index dddddfbcd7d3..0c56a914359f 100644 --- a/kms/attestations/README.rst +++ b/kms/attestations/README.rst @@ -32,7 +32,7 @@ Install Dependencies .. _Python Development Environment Setup Guide: https://cloud.google.com/python/setup -#. Create a virtualenv. Samples are compatible with Python 2.7 and 3.4+. +#. Create a virtualenv. Samples are compatible with Python 3.6+. .. code-block:: bash @@ -48,9 +48,15 @@ Install Dependencies .. _pip: https://pip.pypa.io/ .. _virtualenv: https://virtualenv.pypa.io/ + + + + + Samples ------------------------------------------------------------------------------- + Verify attestations for keys generated by Cloud HSM +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ @@ -66,9 +72,26 @@ To run this sample: $ python verify_attestation.py - + + usage: verify_attestation.py [-h] attestation_file bundle_file + + This application verifies HSM attestations using certificate bundles obtained + from Cloud HSM. For more information, visit + https://cloud.google.com/kms/docs/attest-key. + + positional arguments: + attestation_file Name of attestation file. + bundle_file Name of certificate bundle file. + + optional arguments: + -h, --help show this help message and exit + + + + + -.. _Google Cloud SDK: https://cloud.google.com/sdk/ \ No newline at end of file +.. _Google Cloud SDK: https://cloud.google.com/sdk/ diff --git a/kms/attestations/noxfile.py b/kms/attestations/noxfile.py index b23055f14a65..ba55d7ce53ca 100644 --- a/kms/attestations/noxfile.py +++ b/kms/attestations/noxfile.py @@ -43,7 +43,7 @@ # to 'BUILD_SPECIFIC_GCLOUD_PROJECT' if you want to opt in using a # build specific Cloud project. You can also use your own string # to use your own Cloud project. - 'gcloud_project_env': 'GCLOUD_PROJECT', + 'gcloud_project_env': 'GOOGLE_CLOUD_PROJECT', # 'gcloud_project_env': 'BUILD_SPECIFIC_GCLOUD_PROJECT', # A dictionary you want to inject into your test. Don't put any @@ -72,7 +72,6 @@ def get_pytest_env_vars(): env_key = TEST_CONFIG['gcloud_project_env'] # This should error out if not set. ret['GOOGLE_CLOUD_PROJECT'] = os.environ[env_key] - ret['GCLOUD_PROJECT'] = os.environ[env_key] # Apply user supplied envs. ret.update(TEST_CONFIG['envs']) diff --git a/kms/snippets/create_key_asymmetric_decrypt.py b/kms/snippets/create_key_asymmetric_decrypt.py index cac157958ebd..4865a266cf45 100644 --- a/kms/snippets/create_key_asymmetric_decrypt.py +++ b/kms/snippets/create_key_asymmetric_decrypt.py @@ -38,8 +38,8 @@ def create_key_asymmetric_decrypt(project_id, location_id, key_ring_id, id): key_ring_name = client.key_ring_path(project_id, location_id, key_ring_id) # Build the key. - purpose = kms.enums.CryptoKey.CryptoKeyPurpose.ASYMMETRIC_DECRYPT - algorithm = kms.enums.CryptoKeyVersion.CryptoKeyVersionAlgorithm.RSA_DECRYPT_OAEP_2048_SHA256 + purpose = kms.CryptoKey.CryptoKeyPurpose.ASYMMETRIC_DECRYPT + algorithm = kms.CryptoKeyVersion.CryptoKeyVersionAlgorithm.RSA_DECRYPT_OAEP_2048_SHA256 key = { 'purpose': purpose, 'version_template': { @@ -48,7 +48,7 @@ def create_key_asymmetric_decrypt(project_id, location_id, key_ring_id, id): } # Call the API. - created_key = client.create_crypto_key(key_ring_name, id, key) + created_key = client.create_crypto_key(request={'parent': key_ring_name, 'crypto_key_id': id, 'crypto_key': key}) print('Created asymmetric decrypt key: {}'.format(created_key.name)) return created_key # [END kms_create_key_asymmetric_decrypt] diff --git a/kms/snippets/create_key_asymmetric_sign.py b/kms/snippets/create_key_asymmetric_sign.py index 9bf18a7a996d..1b05799727b4 100644 --- a/kms/snippets/create_key_asymmetric_sign.py +++ b/kms/snippets/create_key_asymmetric_sign.py @@ -38,8 +38,8 @@ def create_key_asymmetric_sign(project_id, location_id, key_ring_id, id): key_ring_name = client.key_ring_path(project_id, location_id, key_ring_id) # Build the key. - purpose = kms.enums.CryptoKey.CryptoKeyPurpose.ASYMMETRIC_SIGN - algorithm = kms.enums.CryptoKeyVersion.CryptoKeyVersionAlgorithm.RSA_SIGN_PKCS1_2048_SHA256 + purpose = kms.CryptoKey.CryptoKeyPurpose.ASYMMETRIC_SIGN + algorithm = kms.CryptoKeyVersion.CryptoKeyVersionAlgorithm.RSA_SIGN_PKCS1_2048_SHA256 key = { 'purpose': purpose, 'version_template': { @@ -48,7 +48,7 @@ def create_key_asymmetric_sign(project_id, location_id, key_ring_id, id): } # Call the API. - created_key = client.create_crypto_key(key_ring_name, id, key) + created_key = client.create_crypto_key(request={'parent': key_ring_name, 'crypto_key_id': id, 'crypto_key': key}) print('Created asymmetric signing key: {}'.format(created_key.name)) return created_key # [END kms_create_key_asymmetric_sign] diff --git a/kms/snippets/create_key_hsm.py b/kms/snippets/create_key_hsm.py index 84ba37e5d00e..34a9c8a2c509 100644 --- a/kms/snippets/create_key_hsm.py +++ b/kms/snippets/create_key_hsm.py @@ -38,9 +38,9 @@ def create_key_hsm(project_id, location_id, key_ring_id, id): key_ring_name = client.key_ring_path(project_id, location_id, key_ring_id) # Build the key. - purpose = kms.enums.CryptoKey.CryptoKeyPurpose.ENCRYPT_DECRYPT - algorithm = kms.enums.CryptoKeyVersion.CryptoKeyVersionAlgorithm.GOOGLE_SYMMETRIC_ENCRYPTION - protection_level = kms.enums.ProtectionLevel.HSM + purpose = kms.CryptoKey.CryptoKeyPurpose.ENCRYPT_DECRYPT + algorithm = kms.CryptoKeyVersion.CryptoKeyVersionAlgorithm.GOOGLE_SYMMETRIC_ENCRYPTION + protection_level = kms.ProtectionLevel.HSM key = { 'purpose': purpose, 'version_template': { @@ -50,7 +50,7 @@ def create_key_hsm(project_id, location_id, key_ring_id, id): } # Call the API. - created_key = client.create_crypto_key(key_ring_name, id, key) + created_key = client.create_crypto_key(request={'parent': key_ring_name, 'crypto_key_id': id, 'crypto_key': key}) print('Created hsm key: {}'.format(created_key.name)) return created_key # [END kms_create_key_hsm] diff --git a/kms/snippets/create_key_labels.py b/kms/snippets/create_key_labels.py index e64a10cb955f..1bef62ebfb24 100644 --- a/kms/snippets/create_key_labels.py +++ b/kms/snippets/create_key_labels.py @@ -38,8 +38,8 @@ def create_key_labels(project_id, location_id, key_ring_id, id): key_ring_name = client.key_ring_path(project_id, location_id, key_ring_id) # Build the key. - purpose = kms.enums.CryptoKey.CryptoKeyPurpose.ENCRYPT_DECRYPT - algorithm = kms.enums.CryptoKeyVersion.CryptoKeyVersionAlgorithm.GOOGLE_SYMMETRIC_ENCRYPTION + purpose = kms.CryptoKey.CryptoKeyPurpose.ENCRYPT_DECRYPT + algorithm = kms.CryptoKeyVersion.CryptoKeyVersionAlgorithm.GOOGLE_SYMMETRIC_ENCRYPTION key = { 'purpose': purpose, 'version_template': { @@ -52,7 +52,7 @@ def create_key_labels(project_id, location_id, key_ring_id, id): } # Call the API. - created_key = client.create_crypto_key(key_ring_name, id, key) + created_key = client.create_crypto_key(request={'parent': key_ring_name, 'crypto_key_id': id, 'crypto_key': key}) print('Created labeled key: {}'.format(created_key.name)) return created_key # [END kms_create_key_labels] diff --git a/kms/snippets/create_key_ring.py b/kms/snippets/create_key_ring.py index c01e8490516b..49348aa9a20d 100644 --- a/kms/snippets/create_key_ring.py +++ b/kms/snippets/create_key_ring.py @@ -34,13 +34,13 @@ def create_key_ring(project_id, location_id, id): client = kms.KeyManagementServiceClient() # Build the parent location name. - location_name = client.location_path(project_id, location_id) + location_name = f'projects/{project_id}/locations/{location_id}' # Build the key ring. key_ring = {} # Call the API. - created_key_ring = client.create_key_ring(location_name, id, key_ring) + created_key_ring = client.create_key_ring(request={'parent': location_name, 'key_ring_id': id, 'key_ring': key_ring}) print('Created key ring: {}'.format(created_key_ring.name)) return created_key_ring # [END kms_create_key_ring] diff --git a/kms/snippets/create_key_rotation_schedule.py b/kms/snippets/create_key_rotation_schedule.py index e6bbdb62d361..02e323345e6f 100644 --- a/kms/snippets/create_key_rotation_schedule.py +++ b/kms/snippets/create_key_rotation_schedule.py @@ -41,8 +41,8 @@ def create_key_rotation_schedule(project_id, location_id, key_ring_id, id): key_ring_name = client.key_ring_path(project_id, location_id, key_ring_id) # Build the key. - purpose = kms.enums.CryptoKey.CryptoKeyPurpose.ENCRYPT_DECRYPT - algorithm = kms.enums.CryptoKeyVersion.CryptoKeyVersionAlgorithm.GOOGLE_SYMMETRIC_ENCRYPTION + purpose = kms.CryptoKey.CryptoKeyPurpose.ENCRYPT_DECRYPT + algorithm = kms.CryptoKeyVersion.CryptoKeyVersionAlgorithm.GOOGLE_SYMMETRIC_ENCRYPTION key = { 'purpose': purpose, 'version_template': { @@ -61,7 +61,7 @@ def create_key_rotation_schedule(project_id, location_id, key_ring_id, id): } # Call the API. - created_key = client.create_crypto_key(key_ring_name, id, key) + created_key = client.create_crypto_key(request={'parent': key_ring_name, 'crypto_key_id': id, 'crypto_key': key}) print('Created labeled key: {}'.format(created_key.name)) return created_key # [END kms_create_key_rotation_schedule] diff --git a/kms/snippets/create_key_symmetric_encrypt_decrypt.py b/kms/snippets/create_key_symmetric_encrypt_decrypt.py index 54b9c5f40981..1b6b88c5cf50 100644 --- a/kms/snippets/create_key_symmetric_encrypt_decrypt.py +++ b/kms/snippets/create_key_symmetric_encrypt_decrypt.py @@ -38,8 +38,8 @@ def create_key_symmetric_encrypt_decrypt(project_id, location_id, key_ring_id, i key_ring_name = client.key_ring_path(project_id, location_id, key_ring_id) # Build the key. - purpose = kms.enums.CryptoKey.CryptoKeyPurpose.ENCRYPT_DECRYPT - algorithm = kms.enums.CryptoKeyVersion.CryptoKeyVersionAlgorithm.GOOGLE_SYMMETRIC_ENCRYPTION + purpose = kms.CryptoKey.CryptoKeyPurpose.ENCRYPT_DECRYPT + algorithm = kms.CryptoKeyVersion.CryptoKeyVersionAlgorithm.GOOGLE_SYMMETRIC_ENCRYPTION key = { 'purpose': purpose, 'version_template': { @@ -48,7 +48,7 @@ def create_key_symmetric_encrypt_decrypt(project_id, location_id, key_ring_id, i } # Call the API. - created_key = client.create_crypto_key(key_ring_name, id, key) + created_key = client.create_crypto_key(request={'parent': key_ring_name, 'crypto_key_id': id, 'crypto_key': key}) print('Created symmetric key: {}'.format(created_key.name)) return created_key # [END kms_create_key_symmetric_encrypt_decrypt] diff --git a/kms/snippets/create_key_version.py b/kms/snippets/create_key_version.py index 9c84f808a943..aced5abfc9db 100644 --- a/kms/snippets/create_key_version.py +++ b/kms/snippets/create_key_version.py @@ -41,7 +41,7 @@ def create_key_version(project_id, location_id, key_ring_id, key_id): version = {} # Call the API. - created_version = client.create_crypto_key_version(key_name, version) + created_version = client.create_crypto_key_version(request={'parent': key_name, 'crypto_key_version': version}) print('Created key version: {}'.format(created_version.name)) return created_version # [END kms_create_key_version] diff --git a/kms/snippets/decrypt_asymmetric.py b/kms/snippets/decrypt_asymmetric.py index 7b040cdd4203..7f5397c92392 100644 --- a/kms/snippets/decrypt_asymmetric.py +++ b/kms/snippets/decrypt_asymmetric.py @@ -40,7 +40,7 @@ def decrypt_asymmetric(project_id, location_id, key_ring_id, key_id, version_id, key_version_name = client.crypto_key_version_path(project_id, location_id, key_ring_id, key_id, version_id) # Call the API. - decrypt_response = client.asymmetric_decrypt(key_version_name, ciphertext) + decrypt_response = client.asymmetric_decrypt(request={'name': key_version_name, 'ciphertext': ciphertext}) print('Plaintext: {}'.format(decrypt_response.plaintext)) return decrypt_response # [END kms_decrypt_asymmetric] diff --git a/kms/snippets/decrypt_symmetric.py b/kms/snippets/decrypt_symmetric.py index a5cbe714279b..c0b64d3b2d16 100644 --- a/kms/snippets/decrypt_symmetric.py +++ b/kms/snippets/decrypt_symmetric.py @@ -39,7 +39,7 @@ def decrypt_symmetric(project_id, location_id, key_ring_id, key_id, ciphertext): key_name = client.crypto_key_path(project_id, location_id, key_ring_id, key_id) # Call the API. - decrypt_response = client.decrypt(key_name, ciphertext) + decrypt_response = client.decrypt(request={'name': key_name, 'ciphertext': ciphertext}) print('Plaintext: {}'.format(decrypt_response.plaintext)) return decrypt_response # [END kms_decrypt_symmetric] diff --git a/kms/snippets/destroy_key_version.py b/kms/snippets/destroy_key_version.py index 7423ca7e099e..1425c890e4b0 100644 --- a/kms/snippets/destroy_key_version.py +++ b/kms/snippets/destroy_key_version.py @@ -39,7 +39,7 @@ def destroy_key_version(project_id, location_id, key_ring_id, key_id, version_id key_version_name = client.crypto_key_version_path(project_id, location_id, key_ring_id, key_id, version_id) # Call the API. - destroyed_version = client.destroy_crypto_key_version(key_version_name) + destroyed_version = client.destroy_crypto_key_version(request={'name': key_version_name}) print('Destroyed key version: {}'.format(destroyed_version.name)) return destroyed_version # [END kms_destroy_key_version] diff --git a/kms/snippets/disable_key_version.py b/kms/snippets/disable_key_version.py index a4a16dd57a65..a4625d704393 100644 --- a/kms/snippets/disable_key_version.py +++ b/kms/snippets/disable_key_version.py @@ -38,18 +38,16 @@ def disable_key_version(project_id, location_id, key_ring_id, key_id, version_id # Build the key version name. key_version_name = client.crypto_key_version_path(project_id, location_id, key_ring_id, key_id, version_id) - # Build the key version. We need to build a full proto instead of a dict due - # to https://github.com/googleapis/gapic-generator-python/issues/364. - from google.cloud.kms_v1.proto import resources_pb2 - key_version = resources_pb2.CryptoKeyVersion() - key_version.name = key_version_name - key_version.state = kms.enums.CryptoKeyVersion.CryptoKeyVersionState.DISABLED + key_version = { + 'name': key_version_name, + 'state': kms.CryptoKeyVersion.CryptoKeyVersionState.DISABLED + } # Build the update mask. update_mask = {'paths': ['state']} # Call the API. - disabled_version = client.update_crypto_key_version(key_version, update_mask) + disabled_version = client.update_crypto_key_version(request={'crypto_key_version': key_version, 'update_mask': update_mask}) print('Disabled key version: {}'.format(disabled_version.name)) return disabled_version # [END kms_disable_key_version] diff --git a/kms/snippets/enable_key_version.py b/kms/snippets/enable_key_version.py index 9cb8daadd66f..edad8eabe1c9 100644 --- a/kms/snippets/enable_key_version.py +++ b/kms/snippets/enable_key_version.py @@ -38,18 +38,16 @@ def enable_key_version(project_id, location_id, key_ring_id, key_id, version_id) # Build the key version name. key_version_name = client.crypto_key_version_path(project_id, location_id, key_ring_id, key_id, version_id) - # Build the key version. We need to build a full proto instead of a dict due - # to https://github.com/googleapis/gapic-generator-python/issues/364. - from google.cloud.kms_v1.proto import resources_pb2 - key_version = resources_pb2.CryptoKeyVersion() - key_version.name = key_version_name - key_version.state = kms.enums.CryptoKeyVersion.CryptoKeyVersionState.ENABLED + key_version = { + 'name': key_version_name, + 'state': kms.CryptoKeyVersion.CryptoKeyVersionState.ENABLED + } # Build the update mask. update_mask = {'paths': ['state']} # Call the API. - enabled_version = client.update_crypto_key_version(key_version, update_mask) + enabled_version = client.update_crypto_key_version(request={'crypto_key_version': key_version, 'update_mask': update_mask}) print('Enabled key version: {}'.format(enabled_version.name)) return enabled_version # [END kms_enable_key_version] diff --git a/kms/snippets/encrypt_asymmetric.py b/kms/snippets/encrypt_asymmetric.py index efe40322c425..065c7e9bf70d 100644 --- a/kms/snippets/encrypt_asymmetric.py +++ b/kms/snippets/encrypt_asymmetric.py @@ -51,7 +51,7 @@ def encrypt_asymmetric(project_id, location_id, key_ring_id, key_id, version_id, key_version_name = client.crypto_key_version_path(project_id, location_id, key_ring_id, key_id, version_id) # Get the public key. - public_key = client.get_public_key(key_version_name) + public_key = client.get_public_key(request={'name': key_version_name}) # Extract and parse the public key as a PEM-encoded RSA key. pem = public_key.pem.encode('utf-8') diff --git a/kms/snippets/encrypt_symmetric.py b/kms/snippets/encrypt_symmetric.py index b90da358f676..9cc3b1a5d12c 100644 --- a/kms/snippets/encrypt_symmetric.py +++ b/kms/snippets/encrypt_symmetric.py @@ -45,7 +45,7 @@ def encrypt_symmetric(project_id, location_id, key_ring_id, key_id, plaintext): key_name = client.crypto_key_path(project_id, location_id, key_ring_id, key_id) # Call the API. - encrypt_response = client.encrypt(key_name, plaintext_bytes) + encrypt_response = client.encrypt(request={'name': key_name, 'plaintext': plaintext_bytes}) print('Ciphertext: {}'.format(base64.b64encode(encrypt_response.ciphertext))) return encrypt_response # [END kms_encrypt_symmetric] diff --git a/kms/snippets/get_key_labels.py b/kms/snippets/get_key_labels.py index 363bcfbaf03b..504dbcaa0c03 100644 --- a/kms/snippets/get_key_labels.py +++ b/kms/snippets/get_key_labels.py @@ -38,7 +38,7 @@ def get_key_labels(project_id, location_id, key_ring_id, key_id): key_name = client.crypto_key_path(project_id, location_id, key_ring_id, key_id) # Call the API. - key = client.get_crypto_key(key_name) + key = client.get_crypto_key(request={'name': key_name}) # Example of iterating over labels. for k, v in key.labels.items(): diff --git a/kms/snippets/get_key_version_attestation.py b/kms/snippets/get_key_version_attestation.py index 615d4653d8ef..569cf2045bba 100644 --- a/kms/snippets/get_key_version_attestation.py +++ b/kms/snippets/get_key_version_attestation.py @@ -42,7 +42,7 @@ def get_key_version_attestation(project_id, location_id, key_ring_id, key_id, ve key_version_name = client.crypto_key_version_path(project_id, location_id, key_ring_id, key_id, version_id) # Call the API. - version = client.get_crypto_key_version(key_version_name) + version = client.get_crypto_key_version(request={'name': key_version_name}) # Only HSM keys have an attestation. For other key types, the attestion # will be None. diff --git a/kms/snippets/get_public_key.py b/kms/snippets/get_public_key.py index 1b810d15f6ad..bdc91139944d 100644 --- a/kms/snippets/get_public_key.py +++ b/kms/snippets/get_public_key.py @@ -39,7 +39,7 @@ def get_public_key(project_id, location_id, key_ring_id, key_id, version_id): key_version_name = client.crypto_key_version_path(project_id, location_id, key_ring_id, key_id, version_id) # Call the API. - public_key = client.get_public_key(key_version_name) + public_key = client.get_public_key(request={'name': key_version_name}) print('Public key: {}'.format(public_key.pem)) return public_key # [END kms_get_public_key] diff --git a/kms/snippets/iam_add_member.py b/kms/snippets/iam_add_member.py index 442f248390de..7847aa4a7079 100644 --- a/kms/snippets/iam_add_member.py +++ b/kms/snippets/iam_add_member.py @@ -42,7 +42,7 @@ def iam_add_member(project_id, location_id, key_ring_id, key_id, member): # resource_name = client.key_ring_path(project_id, location_id, key_ring_id); # Get the current policy. - policy = client.get_iam_policy(resource_name) + policy = client.get_iam_policy(request={'resource': resource_name}) # Add the member to the policy. policy.bindings.add( @@ -50,7 +50,12 @@ def iam_add_member(project_id, location_id, key_ring_id, key_id, member): members=[member]) # Save the updated IAM policy. - updated_policy = client.set_iam_policy(resource_name, policy) + request = { + 'resource': resource_name, + 'policy': policy + } + + updated_policy = client.set_iam_policy(request=request) print('Added {} to {}'.format(member, resource_name)) return updated_policy # [END kms_iam_add_member] diff --git a/kms/snippets/iam_get_policy.py b/kms/snippets/iam_get_policy.py index c00172e98a5b..96ae743ebb5a 100644 --- a/kms/snippets/iam_get_policy.py +++ b/kms/snippets/iam_get_policy.py @@ -41,7 +41,7 @@ def iam_get_policy(project_id, location_id, key_ring_id, key_id): # resource_name = client.key_ring_path(project_id, location_id, key_ring_id); # Get the current policy. - policy = client.get_iam_policy(resource_name) + policy = client.get_iam_policy(request={'resource': resource_name}) # Print the policy print('IAM policy for {}'.format(resource_name)) diff --git a/kms/snippets/iam_remove_member.py b/kms/snippets/iam_remove_member.py index ad73fab943c5..890a027d9e54 100644 --- a/kms/snippets/iam_remove_member.py +++ b/kms/snippets/iam_remove_member.py @@ -42,7 +42,7 @@ def iam_remove_member(project_id, location_id, key_ring_id, key_id, member): # resource_name = client.key_ring_path(project_id, location_id, key_ring_id); # Get the current policy. - policy = client.get_iam_policy(resource_name) + policy = client.get_iam_policy(request={'resource': resource_name}) # Remove the member from the policy. for binding in policy.bindings: @@ -51,7 +51,11 @@ def iam_remove_member(project_id, location_id, key_ring_id, key_id, member): binding.members.remove(member) # Save the updated IAM policy. - updated_policy = client.set_iam_policy(resource_name, policy) + request = { + 'resource': resource_name, + 'policy': policy + } + updated_policy = client.set_iam_policy(request=request) print('Removed {} from {}'.format(member, resource_name)) return updated_policy # [END kms_iam_remove_member] diff --git a/kms/snippets/noxfile.py b/kms/snippets/noxfile.py index b23055f14a65..ba55d7ce53ca 100644 --- a/kms/snippets/noxfile.py +++ b/kms/snippets/noxfile.py @@ -43,7 +43,7 @@ # to 'BUILD_SPECIFIC_GCLOUD_PROJECT' if you want to opt in using a # build specific Cloud project. You can also use your own string # to use your own Cloud project. - 'gcloud_project_env': 'GCLOUD_PROJECT', + 'gcloud_project_env': 'GOOGLE_CLOUD_PROJECT', # 'gcloud_project_env': 'BUILD_SPECIFIC_GCLOUD_PROJECT', # A dictionary you want to inject into your test. Don't put any @@ -72,7 +72,6 @@ def get_pytest_env_vars(): env_key = TEST_CONFIG['gcloud_project_env'] # This should error out if not set. ret['GOOGLE_CLOUD_PROJECT'] = os.environ[env_key] - ret['GCLOUD_PROJECT'] = os.environ[env_key] # Apply user supplied envs. ret.update(TEST_CONFIG['envs']) diff --git a/kms/snippets/quickstart.py b/kms/snippets/quickstart.py index 91b5a49ad41f..6b24d643f5e0 100644 --- a/kms/snippets/quickstart.py +++ b/kms/snippets/quickstart.py @@ -25,10 +25,10 @@ def quickstart(project_id, location_id): client = kms.KeyManagementServiceClient() # Build the parent location name. - location_name = client.location_path(project_id, location_id) + location_name = f'projects/{project_id}/locations/{location_id}' # Call the API. - key_rings = client.list_key_rings(location_name) + key_rings = client.list_key_rings(request={'parent': location_name}) # Example of iterating over key rings. for key_ring in key_rings: diff --git a/kms/snippets/restore_key_version.py b/kms/snippets/restore_key_version.py index 3c4668d6bedf..c65456b2dff2 100644 --- a/kms/snippets/restore_key_version.py +++ b/kms/snippets/restore_key_version.py @@ -39,7 +39,7 @@ def restore_key_version(project_id, location_id, key_ring_id, key_id, version_id key_version_name = client.crypto_key_version_path(project_id, location_id, key_ring_id, key_id, version_id) # Call the API. - restored_version = client.restore_crypto_key_version(key_version_name) + restored_version = client.restore_crypto_key_version(request={'name': key_version_name}) print('Restored key version: {}'.format(restored_version.name)) return restored_version # [END kms_restore_key_version] diff --git a/kms/snippets/sign_asymmetric.py b/kms/snippets/sign_asymmetric.py index a92a13ec20e2..c12a31d2d1f5 100644 --- a/kms/snippets/sign_asymmetric.py +++ b/kms/snippets/sign_asymmetric.py @@ -58,7 +58,7 @@ def sign_asymmetric(project_id, location_id, key_ring_id, key_id, version_id, me digest = {'sha256': hash_} # Call the API - sign_response = client.asymmetric_sign(key_version_name, digest) + sign_response = client.asymmetric_sign(request={'name': key_version_name, 'digest': digest}) print('Signature: {}'.format(base64.b64encode(sign_response.signature))) return sign_response # [END kms_sign_asymmetric] diff --git a/kms/snippets/snippets_test.py b/kms/snippets/snippets_test.py index 795edeb47370..7e3f02ef04ce 100644 --- a/kms/snippets/snippets_test.py +++ b/kms/snippets/snippets_test.py @@ -11,6 +11,7 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and +import datetime import hashlib import os import time @@ -21,7 +22,6 @@ from cryptography.hazmat.primitives import hashes, serialization from cryptography.hazmat.primitives.asymmetric import padding, utils from google.cloud import kms -from google.cloud.kms_v1.proto import resources_pb2 import pytest from create_key_asymmetric_decrypt import create_key_asymmetric_decrypt @@ -64,7 +64,7 @@ def client(): @pytest.fixture(scope="module") def project_id(): - return os.environ['GCLOUD_PROJECT'] + return os.environ['GOOGLE_CLOUD_PROJECT'] @pytest.fixture(scope="module") @@ -74,36 +74,34 @@ def location_id(): @pytest.fixture(scope="module") def key_ring_id(client, project_id, location_id): - location_name = client.location_path(project_id, location_id) + location_name = f"projects/{project_id}/locations/{location_id}" key_ring_id = '{}'.format(uuid.uuid4()) - key_ring = client.create_key_ring(location_name, key_ring_id, {}) + key_ring = client.create_key_ring(request={'parent': location_name, 'key_ring_id': key_ring_id, 'key_ring': {}}) yield key_ring_id - for key in client.list_crypto_keys(key_ring.name): - if key.rotation_period.seconds > 0 or key.next_rotation_time.seconds > 0: - # https://github.com/googleapis/gapic-generator-python/issues/364 - updated_key = resources_pb2.CryptoKey() - updated_key.name = key.name + for key in client.list_crypto_keys(request={'parent': key_ring.name}): + if key.rotation_period or key.next_rotation_time: + updated_key = {'name': key.name} update_mask = {'paths': ['rotation_period', 'next_rotation_time']} - client.update_crypto_key(updated_key, update_mask) + client.update_crypto_key(request={'crypto_key': updated_key, 'update_mask': update_mask}) f = 'state != DESTROYED AND state != DESTROY_SCHEDULED' - for version in client.list_crypto_key_versions(key.name, filter_=f): - client.destroy_crypto_key_version(version.name) + for version in client.list_crypto_key_versions(request={'parent': key.name, 'filter': f}): + client.destroy_crypto_key_version(request={'name': version.name}) @pytest.fixture(scope="module") def asymmetric_decrypt_key_id(client, project_id, location_id, key_ring_id): key_ring_name = client.key_ring_path(project_id, location_id, key_ring_id) key_id = '{}'.format(uuid.uuid4()) - key = client.create_crypto_key(key_ring_name, key_id, { - 'purpose': kms.enums.CryptoKey.CryptoKeyPurpose.ASYMMETRIC_DECRYPT, + key = client.create_crypto_key(request={'parent': key_ring_name, 'crypto_key_id': key_id, 'crypto_key': { + 'purpose': kms.CryptoKey.CryptoKeyPurpose.ASYMMETRIC_DECRYPT, 'version_template': { - 'algorithm': kms.enums.CryptoKeyVersion.CryptoKeyVersionAlgorithm.RSA_DECRYPT_OAEP_2048_SHA256 + 'algorithm': kms.CryptoKeyVersion.CryptoKeyVersionAlgorithm.RSA_DECRYPT_OAEP_2048_SHA256 }, 'labels': {'foo': 'bar', 'zip': 'zap'} - }) + }}) wait_for_ready(client, '{}/cryptoKeyVersions/1'.format(key.name)) return key_id @@ -112,13 +110,13 @@ def asymmetric_decrypt_key_id(client, project_id, location_id, key_ring_id): def asymmetric_sign_ec_key_id(client, project_id, location_id, key_ring_id): key_ring_name = client.key_ring_path(project_id, location_id, key_ring_id) key_id = '{}'.format(uuid.uuid4()) - key = client.create_crypto_key(key_ring_name, key_id, { - 'purpose': kms.enums.CryptoKey.CryptoKeyPurpose.ASYMMETRIC_SIGN, + key = client.create_crypto_key(request={'parent': key_ring_name, 'crypto_key_id': key_id, 'crypto_key': { + 'purpose': kms.CryptoKey.CryptoKeyPurpose.ASYMMETRIC_SIGN, 'version_template': { - 'algorithm': kms.enums.CryptoKeyVersion.CryptoKeyVersionAlgorithm.EC_SIGN_P256_SHA256 + 'algorithm': kms.CryptoKeyVersion.CryptoKeyVersionAlgorithm.EC_SIGN_P256_SHA256 }, 'labels': {'foo': 'bar', 'zip': 'zap'} - }) + }}) wait_for_ready(client, '{}/cryptoKeyVersions/1'.format(key.name)) return key_id @@ -127,13 +125,13 @@ def asymmetric_sign_ec_key_id(client, project_id, location_id, key_ring_id): def asymmetric_sign_rsa_key_id(client, project_id, location_id, key_ring_id): key_ring_name = client.key_ring_path(project_id, location_id, key_ring_id) key_id = '{}'.format(uuid.uuid4()) - key = client.create_crypto_key(key_ring_name, key_id, { - 'purpose': kms.enums.CryptoKey.CryptoKeyPurpose.ASYMMETRIC_SIGN, + key = client.create_crypto_key(request={'parent': key_ring_name, 'crypto_key_id': key_id, 'crypto_key': { + 'purpose': kms.CryptoKey.CryptoKeyPurpose.ASYMMETRIC_SIGN, 'version_template': { - 'algorithm': kms.enums.CryptoKeyVersion.CryptoKeyVersionAlgorithm.RSA_SIGN_PKCS1_2048_SHA256 + 'algorithm': kms.CryptoKeyVersion.CryptoKeyVersionAlgorithm.RSA_SIGN_PKCS1_2048_SHA256 }, 'labels': {'foo': 'bar', 'zip': 'zap'} - }) + }}) wait_for_ready(client, '{}/cryptoKeyVersions/1'.format(key.name)) return key_id @@ -142,14 +140,14 @@ def asymmetric_sign_rsa_key_id(client, project_id, location_id, key_ring_id): def hsm_key_id(client, project_id, location_id, key_ring_id): key_ring_name = client.key_ring_path(project_id, location_id, key_ring_id) key_id = '{}'.format(uuid.uuid4()) - key = client.create_crypto_key(key_ring_name, key_id, { - 'purpose': kms.enums.CryptoKey.CryptoKeyPurpose.ENCRYPT_DECRYPT, + key = client.create_crypto_key(request={'parent': key_ring_name, 'crypto_key_id': key_id, 'crypto_key': { + 'purpose': kms.CryptoKey.CryptoKeyPurpose.ENCRYPT_DECRYPT, 'version_template': { - 'algorithm': kms.enums.CryptoKeyVersion.CryptoKeyVersionAlgorithm.GOOGLE_SYMMETRIC_ENCRYPTION, - 'protection_level': kms.enums.ProtectionLevel.HSM + 'algorithm': kms.CryptoKeyVersion.CryptoKeyVersionAlgorithm.GOOGLE_SYMMETRIC_ENCRYPTION, + 'protection_level': kms.ProtectionLevel.HSM }, 'labels': {'foo': 'bar', 'zip': 'zap'} - }) + }}) wait_for_ready(client, '{}/cryptoKeyVersions/1'.format(key.name)) return key_id @@ -158,21 +156,21 @@ def hsm_key_id(client, project_id, location_id, key_ring_id): def symmetric_key_id(client, project_id, location_id, key_ring_id): key_ring_name = client.key_ring_path(project_id, location_id, key_ring_id) key_id = '{}'.format(uuid.uuid4()) - key = client.create_crypto_key(key_ring_name, key_id, { - 'purpose': kms.enums.CryptoKey.CryptoKeyPurpose.ENCRYPT_DECRYPT, + key = client.create_crypto_key(request={'parent': key_ring_name, 'crypto_key_id': key_id, 'crypto_key': { + 'purpose': kms.CryptoKey.CryptoKeyPurpose.ENCRYPT_DECRYPT, 'version_template': { - 'algorithm': kms.enums.CryptoKeyVersion.CryptoKeyVersionAlgorithm.GOOGLE_SYMMETRIC_ENCRYPTION + 'algorithm': kms.CryptoKeyVersion.CryptoKeyVersionAlgorithm.GOOGLE_SYMMETRIC_ENCRYPTION }, 'labels': {'foo': 'bar', 'zip': 'zap'} - }) + }}) wait_for_ready(client, '{}/cryptoKeyVersions/1'.format(key.name)) return key_id def wait_for_ready(client, key_version_name): for i in range(5): - key_version = client.get_crypto_key_version(key_version_name) - if key_version.state == kms.enums.CryptoKeyVersion.CryptoKeyVersionState.ENABLED: + key_version = client.get_crypto_key_version(request={'name': key_version_name}) + if key_version.state == kms.CryptoKeyVersion.CryptoKeyVersionState.ENABLED: return time.sleep(0.1*(i**2)) pytest.fail('{} not ready'.format(key_version_name)) @@ -181,30 +179,30 @@ def wait_for_ready(client, key_version_name): def test_create_key_asymmetric_decrypt(project_id, location_id, key_ring_id): key_id = '{}'.format(uuid.uuid4()) key = create_key_asymmetric_decrypt(project_id, location_id, key_ring_id, key_id) - assert key.purpose == kms.enums.CryptoKey.CryptoKeyPurpose.ASYMMETRIC_DECRYPT - assert key.version_template.algorithm == kms.enums.CryptoKeyVersion.CryptoKeyVersionAlgorithm.RSA_DECRYPT_OAEP_2048_SHA256 + assert key.purpose == kms.CryptoKey.CryptoKeyPurpose.ASYMMETRIC_DECRYPT + assert key.version_template.algorithm == kms.CryptoKeyVersion.CryptoKeyVersionAlgorithm.RSA_DECRYPT_OAEP_2048_SHA256 def test_create_key_asymmetric_sign(project_id, location_id, key_ring_id): key_id = '{}'.format(uuid.uuid4()) key = create_key_asymmetric_sign(project_id, location_id, key_ring_id, key_id) - assert key.purpose == kms.enums.CryptoKey.CryptoKeyPurpose.ASYMMETRIC_SIGN - assert key.version_template.algorithm == kms.enums.CryptoKeyVersion.CryptoKeyVersionAlgorithm.RSA_SIGN_PKCS1_2048_SHA256 + assert key.purpose == kms.CryptoKey.CryptoKeyPurpose.ASYMMETRIC_SIGN + assert key.version_template.algorithm == kms.CryptoKeyVersion.CryptoKeyVersionAlgorithm.RSA_SIGN_PKCS1_2048_SHA256 def test_create_key_hsm(project_id, location_id, key_ring_id): key_id = '{}'.format(uuid.uuid4()) key = create_key_hsm(project_id, location_id, key_ring_id, key_id) - assert key.purpose == kms.enums.CryptoKey.CryptoKeyPurpose.ENCRYPT_DECRYPT - assert key.version_template.algorithm == kms.enums.CryptoKeyVersion.CryptoKeyVersionAlgorithm.GOOGLE_SYMMETRIC_ENCRYPTION - assert key.version_template.protection_level == kms.enums.ProtectionLevel.HSM + assert key.purpose == kms.CryptoKey.CryptoKeyPurpose.ENCRYPT_DECRYPT + assert key.version_template.algorithm == kms.CryptoKeyVersion.CryptoKeyVersionAlgorithm.GOOGLE_SYMMETRIC_ENCRYPTION + assert key.version_template.protection_level == kms.ProtectionLevel.HSM def test_create_key_labels(project_id, location_id, key_ring_id): key_id = '{}'.format(uuid.uuid4()) key = create_key_labels(project_id, location_id, key_ring_id, key_id) - assert key.purpose == kms.enums.CryptoKey.CryptoKeyPurpose.ENCRYPT_DECRYPT - assert key.version_template.algorithm == kms.enums.CryptoKeyVersion.CryptoKeyVersionAlgorithm.GOOGLE_SYMMETRIC_ENCRYPTION + assert key.purpose == kms.CryptoKey.CryptoKeyPurpose.ENCRYPT_DECRYPT + assert key.version_template.algorithm == kms.CryptoKeyVersion.CryptoKeyVersionAlgorithm.GOOGLE_SYMMETRIC_ENCRYPTION assert key.labels == {'team': 'alpha', 'cost_center': 'cc1234'} @@ -217,15 +215,15 @@ def test_create_key_ring(project_id, location_id): def test_create_key_rotation_schedule(project_id, location_id, key_ring_id): key_id = '{}'.format(uuid.uuid4()) key = create_key_rotation_schedule(project_id, location_id, key_ring_id, key_id) - assert key.rotation_period.seconds == 60*60*24*30 - assert key.next_rotation_time.seconds > 0 + assert key.rotation_period == datetime.timedelta(seconds=60*60*24*30) + assert key.next_rotation_time def test_create_key_symmetric_encrypt_decrypt(project_id, location_id, key_ring_id): key_id = '{}'.format(uuid.uuid4()) key = create_key_symmetric_encrypt_decrypt(project_id, location_id, key_ring_id, key_id) - assert key.purpose == kms.enums.CryptoKey.CryptoKeyPurpose.ENCRYPT_DECRYPT - assert key.version_template.algorithm == kms.enums.CryptoKeyVersion.CryptoKeyVersionAlgorithm.GOOGLE_SYMMETRIC_ENCRYPTION + assert key.purpose == kms.CryptoKey.CryptoKeyPurpose.ENCRYPT_DECRYPT + assert key.version_template.algorithm == kms.CryptoKeyVersion.CryptoKeyVersionAlgorithm.GOOGLE_SYMMETRIC_ENCRYPTION def test_create_key_version(project_id, location_id, key_ring_id, symmetric_key_id): @@ -237,7 +235,7 @@ def test_decrypt_asymmetric(client, project_id, location_id, key_ring_id, asymme message = 'my message'.encode('utf-8') key_version_name = client.crypto_key_version_path(project_id, location_id, key_ring_id, asymmetric_decrypt_key_id, '1') - public_key = client.get_public_key(key_version_name) + public_key = client.get_public_key(request={'name': key_version_name}) pem = public_key.pem.encode('utf-8') rsa_key = serialization.load_pem_public_key(pem, default_backend()) @@ -255,7 +253,7 @@ def test_decrypt_symmetric(client, project_id, location_id, key_ring_id, symmetr plaintext = 'my message'.encode('utf-8') key_version_name = client.crypto_key_path(project_id, location_id, key_ring_id, symmetric_key_id) - encrypt_response = client.encrypt(key_version_name, plaintext) + encrypt_response = client.encrypt(request={'name': key_version_name, 'plaintext': plaintext}) ciphertext = encrypt_response.ciphertext decrypt_response = decrypt_symmetric(project_id, location_id, key_ring_id, symmetric_key_id, ciphertext) @@ -264,30 +262,30 @@ def test_decrypt_symmetric(client, project_id, location_id, key_ring_id, symmetr def test_destroy_restore_key_version(client, project_id, location_id, key_ring_id, asymmetric_decrypt_key_id): key_name = client.crypto_key_path(project_id, location_id, key_ring_id, asymmetric_decrypt_key_id) - version = client.create_crypto_key_version(key_name, {}) + version = client.create_crypto_key_version(request={'parent': key_name, 'crypto_key_version': {}}) version_id = version.name.split('/')[-1] wait_for_ready(client, version.name) destroyed_version = destroy_key_version(project_id, location_id, key_ring_id, asymmetric_decrypt_key_id, version_id) - assert destroyed_version.state == kms.enums.CryptoKeyVersion.CryptoKeyVersionState.DESTROY_SCHEDULED + assert destroyed_version.state == kms.CryptoKeyVersion.CryptoKeyVersionState.DESTROY_SCHEDULED restored_version = restore_key_version(project_id, location_id, key_ring_id, asymmetric_decrypt_key_id, version_id) - assert restored_version.state == kms.enums.CryptoKeyVersion.CryptoKeyVersionState.DISABLED + assert restored_version.state == kms.CryptoKeyVersion.CryptoKeyVersionState.DISABLED def test_disable_enable_key_version(client, project_id, location_id, key_ring_id, asymmetric_decrypt_key_id): key_name = client.crypto_key_path(project_id, location_id, key_ring_id, asymmetric_decrypt_key_id) - version = client.create_crypto_key_version(key_name, {}) + version = client.create_crypto_key_version(request={'parent': key_name, 'crypto_key_version': {}}) version_id = version.name.split('/')[-1] wait_for_ready(client, version.name) disabled_version = disable_key_version(project_id, location_id, key_ring_id, asymmetric_decrypt_key_id, version_id) - assert disabled_version.state == kms.enums.CryptoKeyVersion.CryptoKeyVersionState.DISABLED + assert disabled_version.state == kms.CryptoKeyVersion.CryptoKeyVersionState.DISABLED enabled_version = enable_key_version(project_id, location_id, key_ring_id, asymmetric_decrypt_key_id, version_id) - assert enabled_version.state == kms.enums.CryptoKeyVersion.CryptoKeyVersionState.ENABLED + assert enabled_version.state == kms.CryptoKeyVersion.CryptoKeyVersionState.ENABLED def test_encrypt_asymmetric(client, project_id, location_id, key_ring_id, asymmetric_decrypt_key_id): @@ -295,7 +293,7 @@ def test_encrypt_asymmetric(client, project_id, location_id, key_ring_id, asymme ciphertext = encrypt_asymmetric(project_id, location_id, key_ring_id, asymmetric_decrypt_key_id, '1', plaintext) key_version_name = client.crypto_key_version_path(project_id, location_id, key_ring_id, asymmetric_decrypt_key_id, '1') - response = client.asymmetric_decrypt(key_version_name, ciphertext) + response = client.asymmetric_decrypt(request={'name': key_version_name, 'ciphertext': ciphertext}) assert response.plaintext == plaintext.encode('utf-8') @@ -304,7 +302,7 @@ def test_encrypt_symmetric(client, project_id, location_id, key_ring_id, symmetr encrypt_response = encrypt_symmetric(project_id, location_id, key_ring_id, symmetric_key_id, plaintext) key_name = client.crypto_key_path(project_id, location_id, key_ring_id, symmetric_key_id) - decrypt_response = client.decrypt(key_name, encrypt_response.ciphertext) + decrypt_response = client.decrypt(request={'name': key_name, 'ciphertext': encrypt_response.ciphertext}) assert decrypt_response.plaintext == plaintext.encode('utf-8') @@ -338,11 +336,11 @@ def test_iam_get_policy(project_id, location_id, key_ring_id, symmetric_key_id): def test_iam_remove_member(client, project_id, location_id, key_ring_id, asymmetric_sign_rsa_key_id): resource_name = client.crypto_key_path(project_id, location_id, key_ring_id, asymmetric_sign_rsa_key_id) - policy = client.get_iam_policy(resource_name) + policy = client.get_iam_policy(request={"resource": resource_name}) policy.bindings.add( role='roles/cloudkms.cryptoKeyEncrypterDecrypter', members=['group:test@google.com', 'group:tester@google.com']) - client.set_iam_policy(resource_name, policy) + client.set_iam_policy(request={"resource": resource_name, "policy": policy}) policy = iam_remove_member(project_id, location_id, key_ring_id, asymmetric_sign_rsa_key_id, 'group:test@google.com') assert not any('group:test@google.com' in b.members for b in policy.bindings) @@ -356,7 +354,7 @@ def test_sign_asymmetric(client, project_id, location_id, key_ring_id, asymmetri assert sign_response.signature key_version_name = client.crypto_key_version_path(project_id, location_id, key_ring_id, asymmetric_sign_rsa_key_id, '1') - public_key = client.get_public_key(key_version_name) + public_key = client.get_public_key(request={'name': key_version_name}) pem = public_key.pem.encode('utf-8') rsa_key = serialization.load_pem_public_key(pem, default_backend()) hash_ = hashlib.sha256(message.encode('utf-8')).digest() @@ -371,8 +369,8 @@ def test_sign_asymmetric(client, project_id, location_id, key_ring_id, asymmetri def test_update_key_add_rotation(project_id, location_id, key_ring_id, symmetric_key_id): key = update_key_add_rotation(project_id, location_id, key_ring_id, symmetric_key_id) - assert key.rotation_period.seconds == 60*60*24*30 - assert key.next_rotation_time.seconds > 0 + assert key.rotation_period == datetime.timedelta(seconds=60*60*24*30) + assert key.next_rotation_time def test_update_key_remove_labels(project_id, location_id, key_ring_id, symmetric_key_id): @@ -382,8 +380,8 @@ def test_update_key_remove_labels(project_id, location_id, key_ring_id, symmetri def test_update_key_remove_rotation(project_id, location_id, key_ring_id, symmetric_key_id): key = update_key_remove_rotation(project_id, location_id, key_ring_id, symmetric_key_id) - assert key.rotation_period.seconds == 0 - assert key.next_rotation_time.seconds == 0 + assert not key.rotation_period + assert not key.next_rotation_time def test_update_key_set_primary(project_id, location_id, key_ring_id, symmetric_key_id): @@ -401,7 +399,7 @@ def test_verify_asymmetric_ec(client, project_id, location_id, key_ring_id, asym key_version_name = client.crypto_key_version_path(project_id, location_id, key_ring_id, asymmetric_sign_ec_key_id, '1') hash_ = hashlib.sha256(message.encode('utf-8')).digest() - sign_response = client.asymmetric_sign(key_version_name, {'sha256': hash_}) + sign_response = client.asymmetric_sign(request={'name': key_version_name, 'digest': {'sha256': hash_}}) verified = verify_asymmetric_ec(project_id, location_id, key_ring_id, asymmetric_sign_ec_key_id, '1', message, sign_response.signature) assert verified @@ -412,7 +410,7 @@ def test_verify_asymmetric_rsa(client, project_id, location_id, key_ring_id, asy key_version_name = client.crypto_key_version_path(project_id, location_id, key_ring_id, asymmetric_sign_rsa_key_id, '1') hash_ = hashlib.sha256(message.encode('utf-8')).digest() - sign_response = client.asymmetric_sign(key_version_name, {'sha256': hash_}) + sign_response = client.asymmetric_sign(request={'name': key_version_name, 'digest': {'sha256': hash_}}) verified = verify_asymmetric_rsa(project_id, location_id, key_ring_id, asymmetric_sign_rsa_key_id, '1', message, sign_response.signature) assert verified diff --git a/kms/snippets/update_key_add_rotation.py b/kms/snippets/update_key_add_rotation.py index 22dd6b6622fc..acc4d95612a9 100644 --- a/kms/snippets/update_key_add_rotation.py +++ b/kms/snippets/update_key_add_rotation.py @@ -40,23 +40,21 @@ def update_key_add_rotation(project_id, location_id, key_ring_id, key_id): # Build the key name. key_name = client.crypto_key_path(project_id, location_id, key_ring_id, key_id) - # Build the key. We need to build a full proto instead of a dict due to - # https://github.com/googleapis/gapic-generator-python/issues/364. - from google.cloud.kms_v1.proto import resources_pb2 - key = resources_pb2.CryptoKey() - key.name = key_name - - # Rotate the key every 30 days. - key.rotation_period.seconds = 60*60*24*30 - - # Start the first rotation in 24 hours. - key.next_rotation_time.seconds = int(time.time()) + 60*60*24 + key = { + 'name': key_name, + 'rotation_period': { + 'seconds': 60*60*24*30 # Rotate the key every 30 days. + }, + 'next_rotation_time': { + 'seconds': int(time.time()) + 60*60*24 # Start the first rotation in 24 hours. + } + } # Build the update mask. update_mask = {'paths': ['rotation_period', 'next_rotation_time']} # Call the API. - updated_key = client.update_crypto_key(key, update_mask) + updated_key = client.update_crypto_key(request={'crypto_key': key, 'update_mask': update_mask}) print('Updated key: {}'.format(updated_key.name)) return updated_key # [END kms_update_key_add_rotation_schedule] diff --git a/kms/snippets/update_key_remove_labels.py b/kms/snippets/update_key_remove_labels.py index a44ab214b7a8..648db99c5973 100644 --- a/kms/snippets/update_key_remove_labels.py +++ b/kms/snippets/update_key_remove_labels.py @@ -37,18 +37,16 @@ def update_key_remove_labels(project_id, location_id, key_ring_id, key_id): # Build the key name. key_name = client.crypto_key_path(project_id, location_id, key_ring_id, key_id) - # Build the key. We need to build a full proto instead of a dict due to - # https://github.com/googleapis/gapic-generator-python/issues/364. - from google.cloud.kms_v1.proto import resources_pb2 - key = resources_pb2.CryptoKey() - key.name = key_name - key.labels.clear() + key = { + 'name': key_name, + 'labels': [], + } # Build the update mask. update_mask = {'paths': ['labels']} # Call the API. - updated_key = client.update_crypto_key(key, update_mask) + updated_key = client.update_crypto_key(request={'crypto_key': key, 'update_mask': update_mask}) print('Updated key: {}'.format(updated_key.name)) return updated_key # [END kms_update_key_remove_labels] diff --git a/kms/snippets/update_key_remove_rotation.py b/kms/snippets/update_key_remove_rotation.py index 7f8707eb6eb0..5dd596a7822b 100644 --- a/kms/snippets/update_key_remove_rotation.py +++ b/kms/snippets/update_key_remove_rotation.py @@ -37,17 +37,15 @@ def update_key_remove_rotation(project_id, location_id, key_ring_id, key_id): # Build the key name. key_name = client.crypto_key_path(project_id, location_id, key_ring_id, key_id) - # Build the key. We need to build a full proto instead of a dict due to - # https://github.com/googleapis/gapic-generator-python/issues/364. - from google.cloud.kms_v1.proto import resources_pb2 - key = resources_pb2.CryptoKey() - key.name = key_name + key = { + 'name': key_name + } # Build the update mask. update_mask = {'paths': ['rotation_period', 'next_rotation_time']} # Call the API. - updated_key = client.update_crypto_key(key, update_mask) + updated_key = client.update_crypto_key(request={'crypto_key': key, 'update_mask': update_mask}) print('Updated key: {}'.format(updated_key.name)) return updated_key # [END kms_update_key_remove_rotation_schedule] diff --git a/kms/snippets/update_key_set_primary.py b/kms/snippets/update_key_set_primary.py index dd889dbd407f..74ba5cdf845a 100644 --- a/kms/snippets/update_key_set_primary.py +++ b/kms/snippets/update_key_set_primary.py @@ -39,7 +39,7 @@ def update_key_set_primary(project_id, location_id, key_ring_id, key_id, version key_name = client.crypto_key_path(project_id, location_id, key_ring_id, key_id) # Call the API. - updated_key = client.update_crypto_key_primary_version(key_name, version_id) + updated_key = client.update_crypto_key_primary_version(request={'name': key_name, 'crypto_key_version_id': version_id}) print('Updated {} primary to {}'.format(updated_key.name, version_id)) return updated_key # [END kms_update_key_set_primary] diff --git a/kms/snippets/update_key_update_labels.py b/kms/snippets/update_key_update_labels.py index 21372472bc2a..3f58f15f142c 100644 --- a/kms/snippets/update_key_update_labels.py +++ b/kms/snippets/update_key_update_labels.py @@ -37,18 +37,18 @@ def update_key_update_labels(project_id, location_id, key_ring_id, key_id): # Build the key name. key_name = client.crypto_key_path(project_id, location_id, key_ring_id, key_id) - # Build the key. We need to build a full proto instead of a dict due to - # https://github.com/googleapis/gapic-generator-python/issues/364. - from google.cloud.kms_v1.proto import resources_pb2 - key = resources_pb2.CryptoKey() - key.name = key_name - key.labels.update({'new_label': 'new_value'}) + key = { + 'name': key_name, + 'labels': { + 'new_label': 'new_value' + } + } # Build the update mask. update_mask = {'paths': ['labels']} # Call the API. - updated_key = client.update_crypto_key(key, update_mask) + updated_key = client.update_crypto_key(request={'crypto_key': key, 'update_mask': update_mask}) print('Updated key: {}'.format(updated_key.name)) return updated_key # [END kms_update_key_update_labels] diff --git a/kms/snippets/verify_asymmetric_ec.py b/kms/snippets/verify_asymmetric_ec.py index ac77a64b8681..d29128bd8aca 100644 --- a/kms/snippets/verify_asymmetric_ec.py +++ b/kms/snippets/verify_asymmetric_ec.py @@ -53,7 +53,7 @@ def verify_asymmetric_ec(project_id, location_id, key_ring_id, key_id, version_i key_version_name = client.crypto_key_version_path(project_id, location_id, key_ring_id, key_id, version_id) # Get the public key. - public_key = client.get_public_key(key_version_name) + public_key = client.get_public_key(request={'name': key_version_name}) # Extract and parse the public key as a PEM-encoded RSA key. pem = public_key.pem.encode('utf-8') diff --git a/kms/snippets/verify_asymmetric_rsa.py b/kms/snippets/verify_asymmetric_rsa.py index 6df3d862f83b..ee7330367d75 100644 --- a/kms/snippets/verify_asymmetric_rsa.py +++ b/kms/snippets/verify_asymmetric_rsa.py @@ -53,7 +53,7 @@ def verify_asymmetric_rsa(project_id, location_id, key_ring_id, key_id, version_ key_version_name = client.crypto_key_version_path(project_id, location_id, key_ring_id, key_id, version_id) # Get the public key. - public_key = client.get_public_key(key_version_name) + public_key = client.get_public_key(request={'name': key_version_name}) # Extract and parse the public key as a PEM-encoded RSA key. pem = public_key.pem.encode('utf-8') From 7624359def115f02a4cc27ac72b619aeda6e89b4 Mon Sep 17 00:00:00 2001 From: Alexa B Date: Fri, 7 Aug 2020 14:11:43 -0400 Subject: [PATCH 058/136] docs: Generate using new common.py_samples() synthtool functionality (#35) * docs: Generate using new common.py_samples() synthtool functionality * docs: Generate using new common.py_samples() synthtool functionality * Delete old README * Updated README to remove duplicate info * Minor change --- kms/snippets/README.md | 54 +++++++++++++++++++++ kms/snippets/README.rst | 98 -------------------------------------- kms/snippets/README.rst.in | 19 -------- 3 files changed, 54 insertions(+), 117 deletions(-) create mode 100644 kms/snippets/README.md delete mode 100644 kms/snippets/README.rst delete mode 100644 kms/snippets/README.rst.in diff --git a/kms/snippets/README.md b/kms/snippets/README.md new file mode 100644 index 000000000000..f2bb82908a72 --- /dev/null +++ b/kms/snippets/README.md @@ -0,0 +1,54 @@ +[//]: # "This README.md file is auto-generated, all changes to this file will be lost." +[//]: # "To regenerate it, use `python -m synthtool`." + +## Python Samples for Google Cloud Key Management Service + +This directory contains samples for Google Cloud Key Management Service, which may be used as a refererence for how to use Google Cloud Key Management Service. +The Google Cloud KMS API is a service that allows you to keep encryption keys centrally in the cloud, for direct use by cloud services. More info about Cloud KMS can be found at https://cloud.google.com/kms/docs/ +Samples, quickstarts, and other documentation are available at cloud.google.com. + + +### Quickstart + +This quickstart shows you how to create and use encryption keys with Cloud Key Management Service. + + +Open in Cloud Shell + + +To run this sample: + +1. If this is your first time working with GCP products, you will need to set up [the Cloud SDK][cloud_sdk] or utilize [Google Cloud Shell][gcloud_shell]. This sample may [require authetication][authentication] and you will need to [enable billing][enable_billing]. + +1. Make a fork of this repo and clone the branch locally, then navigate to the sample directory you want to use. + +1. Install the dependencies needed to run the samples. + + pip install -r requirements.txt + +1. Run the sample using + + python quickstart.py + + +More information about the Cloud KMS quickstart is available at https://cloud.google.com/kms/docs/quickstart + +## Additional Information + +These samples use the [Google Cloud Client Library for Python][client_library_python]. +You can read the documentation for more details on API usage and use GitHub +to [browse the source][source] and [report issues][issues]. + +### Contributing +For [contributing guidelines][contrib_guide], the [Python style guide][py_style], and more information on prerequisite steps to contribute, view the source code at googleapis/python-kms. + +[authentication]: https://cloud.google.com/docs/authentication/getting-started +[enable_billing]:https://cloud.google.com/apis/docs/getting-started#enabling_billing +[client_library_python]: https://googlecloudplatform.github.io/google-cloud-python/ +[source]: https://github.com/GoogleCloudPlatform/google-cloud-python +[issues]: https://github.com/GoogleCloudPlatform/google-cloud-python/issues +[contrib_guide]: https://github.com/googleapis/google-cloud-python/blob/master/CONTRIBUTING.rst +[py_style]: http://google.github.io/styleguide/pyguide.html +[cloud_sdk]: https://cloud.google.com/sdk/docs +[gcloud_shell]: https://cloud.google.com/shell/docs +[gcloud_shell]: https://cloud.google.com/shell/docs diff --git a/kms/snippets/README.rst b/kms/snippets/README.rst deleted file mode 100644 index 7a52a0817bf3..000000000000 --- a/kms/snippets/README.rst +++ /dev/null @@ -1,98 +0,0 @@ - -.. This file is automatically generated. Do not edit this file directly. - -Google Cloud KMS API Python Samples -=============================================================================== - -.. image:: https://gstatic.com/cloudssh/images/open-btn.png - :target: https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/GoogleCloudPlatform/python-docs-samples&page=editor&open_in_editor=kms/api-client/README.rst - - -This directory contains samples for Google Cloud KMS API. The `Google Cloud KMS API`_ is a service that allows you to keep encryption keys centrally in the cloud, for direct use by cloud services. - - - - -.. _Google Cloud KMS API: https://cloud.google.com/kms/docs/ - - -Setup -------------------------------------------------------------------------------- - - - -Authentication -++++++++++++++ - -This sample requires you to have authentication setup. Refer to the -`Authentication Getting Started Guide`_ for instructions on setting up -credentials for applications. - -.. _Authentication Getting Started Guide: - https://cloud.google.com/docs/authentication/getting-started - - - - -Install Dependencies -++++++++++++++++++++ - -#. Clone python-docs-samples and change directory to the sample directory you want to use. - - .. code-block:: bash - - $ git clone https://github.com/GoogleCloudPlatform/python-docs-samples.git - -#. Install `pip`_ and `virtualenv`_ if you do not already have them. You may want to refer to the `Python Development Environment Setup Guide`_ for Google Cloud Platform for instructions. - - .. _Python Development Environment Setup Guide: - https://cloud.google.com/python/setup - -#. Create a virtualenv. Samples are compatible with Python 3.6+. - - .. code-block:: bash - - $ virtualenv env - $ source env/bin/activate - -#. Install the dependencies needed to run the samples. - - .. code-block:: bash - - $ pip install -r requirements.txt - -.. _pip: https://pip.pypa.io/ -.. _virtualenv: https://virtualenv.pypa.io/ - - - - - - -Samples -------------------------------------------------------------------------------- - - -Quickstart -+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - -.. image:: https://gstatic.com/cloudssh/images/open-btn.png - :target: https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/GoogleCloudPlatform/python-docs-samples&page=editor&open_in_editor=kms/api-client/quickstart.py,kms/api-client/README.rst - - - - -To run this sample: - -.. code-block:: bash - - $ python quickstart.py - - - - - - - - -.. _Google Cloud SDK: https://cloud.google.com/sdk/ diff --git a/kms/snippets/README.rst.in b/kms/snippets/README.rst.in deleted file mode 100644 index cfd81fc800bd..000000000000 --- a/kms/snippets/README.rst.in +++ /dev/null @@ -1,19 +0,0 @@ -# This file is used to generate README.rst - -product: - name: Google Cloud KMS API - short_name: Cloud KMS API - url: https://cloud.google.com/kms/docs/ - description: > - The `Google Cloud KMS API`_ is a service that allows you to keep encryption - keys centrally in the cloud, for direct use by cloud services. - -setup: -- auth -- install_deps - -samples: -- name: Quickstart - file: quickstart.py - -folder: kms/api-client From 64056c162d62bbcfddf6944fcc72d0120e96909e Mon Sep 17 00:00:00 2001 From: Yoshi Automation Bot Date: Thu, 27 Aug 2020 09:20:08 -0700 Subject: [PATCH 059/136] chore: update templates (#42) This PR was generated using Autosynth. :rainbow: Synth log will be available here: https://source.cloud.google.com/results/invocations/0d320425-3c32-43fb-ac20-f19efc26053f/targets - [ ] To automatically regenerate this PR, check this box. Source-Link: https://github.com/googleapis/synthtool/commit/2e85c10b5153defd9d654c34b57e7e9263361959 Source-Link: https://github.com/googleapis/synthtool/commit/4f8f5dc24af79694887385015294e4dbb214c352 Source-Link: https://github.com/googleapis/synthtool/commit/bfcdbe0da977b2de6c1c0471bb6dc2f1e13bf669 Source-Link: https://github.com/googleapis/synthtool/commit/39b527a39f5cd56d4882b3874fc08eed4756cebe Source-Link: https://github.com/googleapis/synthtool/commit/5dfda5621df45b71b6e88544ebbb53b1a8c90214 Source-Link: https://github.com/googleapis/synthtool/commit/5506723fef367557d83cf072d0c18020c049fcb8 --- kms/snippets/README.md | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/kms/snippets/README.md b/kms/snippets/README.md index f2bb82908a72..bd4f0609f4cb 100644 --- a/kms/snippets/README.md +++ b/kms/snippets/README.md @@ -3,7 +3,7 @@ ## Python Samples for Google Cloud Key Management Service -This directory contains samples for Google Cloud Key Management Service, which may be used as a refererence for how to use Google Cloud Key Management Service. +This directory contains samples for Google Cloud Key Management Service, which may be used as a refererence for how to use this product. The Google Cloud KMS API is a service that allows you to keep encryption keys centrally in the cloud, for direct use by cloud services. More info about Cloud KMS can be found at https://cloud.google.com/kms/docs/ Samples, quickstarts, and other documentation are available at cloud.google.com. @@ -37,15 +37,14 @@ More information about the Cloud KMS quickstart is available at https://cloud.go These samples use the [Google Cloud Client Library for Python][client_library_python]. You can read the documentation for more details on API usage and use GitHub -to [browse the source][source] and [report issues][issues]. +to browse the source and [report issues][issues]. ### Contributing -For [contributing guidelines][contrib_guide], the [Python style guide][py_style], and more information on prerequisite steps to contribute, view the source code at googleapis/python-kms. +View the [contributing guidelines][contrib_guide], the [Python style guide][py_style] for more information. [authentication]: https://cloud.google.com/docs/authentication/getting-started [enable_billing]:https://cloud.google.com/apis/docs/getting-started#enabling_billing [client_library_python]: https://googlecloudplatform.github.io/google-cloud-python/ -[source]: https://github.com/GoogleCloudPlatform/google-cloud-python [issues]: https://github.com/GoogleCloudPlatform/google-cloud-python/issues [contrib_guide]: https://github.com/googleapis/google-cloud-python/blob/master/CONTRIBUTING.rst [py_style]: http://google.github.io/styleguide/pyguide.html From f59e62c6f1c737dd724465396dad8ffa0ecd0810 Mon Sep 17 00:00:00 2001 From: WhiteSource Renovate Date: Thu, 27 Aug 2020 18:28:04 +0200 Subject: [PATCH 060/136] chore(deps): update dependency cryptography to v3.1 (#44) This PR contains the following updates: | Package | Update | Change | |---|---|---| | [cryptography](https://togithub.com/pyca/cryptography) | minor | `==3.0` -> `==3.1` | --- ### Release Notes
pyca/cryptography ### [`v3.1`](https://togithub.com/pyca/cryptography/compare/3.0...3.1) [Compare Source](https://togithub.com/pyca/cryptography/compare/3.0...3.1)
--- ### Renovate configuration :date: **Schedule**: At any time (no schedule defined). :vertical_traffic_light: **Automerge**: Disabled by config. Please merge this manually once you are satisfied. :recycle: **Rebasing**: Renovate will not automatically rebase this PR, because other commits have been found. :no_bell: **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] If you want to rebase/retry this PR, check this box --- This PR has been generated by [WhiteSource Renovate](https://renovate.whitesourcesoftware.com). View repository job log [here](https://app.renovatebot.com/dashboard#github/googleapis/python-kms). --- kms/attestations/requirements.txt | 2 +- kms/snippets/requirements.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/kms/attestations/requirements.txt b/kms/attestations/requirements.txt index c8639da017b8..1c2e2d8273bd 100644 --- a/kms/attestations/requirements.txt +++ b/kms/attestations/requirements.txt @@ -1,2 +1,2 @@ -cryptography==3.0 +cryptography==3.1 pem==20.1.0 diff --git a/kms/snippets/requirements.txt b/kms/snippets/requirements.txt index f829e4a9caf6..6e4d9973c20c 100644 --- a/kms/snippets/requirements.txt +++ b/kms/snippets/requirements.txt @@ -1,2 +1,2 @@ google-cloud-kms==1.4.0 -cryptography==3.0 +cryptography==3.1 From deeaedcfbb7d33aab72edc51c56e5fb17c758c24 Mon Sep 17 00:00:00 2001 From: arithmetic1728 <58957152+arithmetic1728@users.noreply.github.com> Date: Wed, 16 Sep 2020 11:17:33 -0700 Subject: [PATCH 061/136] feat: regenerate client lib to pick up new mtls env (#55) * feat: regenerate client lib to pick up new mtls env * update google-api-core and proto-plus version --- kms/snippets/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/kms/snippets/README.md b/kms/snippets/README.md index bd4f0609f4cb..56715580b612 100644 --- a/kms/snippets/README.md +++ b/kms/snippets/README.md @@ -31,6 +31,7 @@ To run this sample: python quickstart.py + More information about the Cloud KMS quickstart is available at https://cloud.google.com/kms/docs/quickstart ## Additional Information From 03427d83d702ff31f5b6249c10feda35024aafde Mon Sep 17 00:00:00 2001 From: WhiteSource Renovate Date: Wed, 16 Sep 2020 22:20:08 +0200 Subject: [PATCH 062/136] chore(deps): update dependency google-cloud-kms to v2 (#29) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR contains the following updates: | Package | Update | Change | |---|---|---| | [google-cloud-kms](https://togithub.com/googleapis/python-kms) | major | `==1.4.0` -> `==2.0.0` | --- ### Release Notes
googleapis/python-kms ### [`v2.0.0`](https://togithub.com/googleapis/python-kms/blob/master/CHANGELOG.md#​200-httpswwwgithubcomgoogleapispython-kmscomparev140v200-2020-07-30) [Compare Source](https://togithub.com/googleapis/python-kms/compare/v1.4.0...v2.0.0) ##### âš  BREAKING CHANGES - migrate to microgenerator. ([#​16](https://togithub.com/googleapis/python-kms/issues/16)) ##### Features - migrate to microgenerator. See [Migration Guide](https://togithub.com/googleapis/python-kms/blob/release-v2.0.0/UPGRADING.md). ([#​16](https://www.github.com/googleapis/python-kms/issues/16)) ([605f757](https://www.github.com/googleapis/python-kms/commit/605f7577a9a9f1a2b39fa69da7e250b5f70e945e))
--- ### Renovate configuration :date: **Schedule**: At any time (no schedule defined). :vertical_traffic_light: **Automerge**: Disabled by config. Please merge this manually once you are satisfied. :recycle: **Rebasing**: Renovate will not automatically rebase this PR, because other commits have been found. :no_bell: **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] If you want to rebase/retry this PR, check this box --- This PR has been generated by [WhiteSource Renovate](https://renovate.whitesourcesoftware.com). View repository job log [here](https://app.renovatebot.com/dashboard#github/googleapis/python-kms). --- kms/snippets/requirements.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kms/snippets/requirements.txt b/kms/snippets/requirements.txt index 6e4d9973c20c..f5ec4487a25e 100644 --- a/kms/snippets/requirements.txt +++ b/kms/snippets/requirements.txt @@ -1,2 +1,2 @@ -google-cloud-kms==1.4.0 -cryptography==3.1 +google-cloud-kms==2.0.0 +cryptography==3.1 \ No newline at end of file From 35d6e905a3d33923699972f77a985f7063bd04e7 Mon Sep 17 00:00:00 2001 From: WhiteSource Renovate Date: Fri, 16 Oct 2020 21:51:16 +0200 Subject: [PATCH 063/136] chore(deps): update dependency cryptography to v3.1.1 (#61) --- kms/attestations/requirements.txt | 2 +- kms/snippets/requirements.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/kms/attestations/requirements.txt b/kms/attestations/requirements.txt index 1c2e2d8273bd..273aa982d101 100644 --- a/kms/attestations/requirements.txt +++ b/kms/attestations/requirements.txt @@ -1,2 +1,2 @@ -cryptography==3.1 +cryptography==3.1.1 pem==20.1.0 diff --git a/kms/snippets/requirements.txt b/kms/snippets/requirements.txt index f5ec4487a25e..9171879b2eb1 100644 --- a/kms/snippets/requirements.txt +++ b/kms/snippets/requirements.txt @@ -1,2 +1,2 @@ google-cloud-kms==2.0.0 -cryptography==3.1 \ No newline at end of file +cryptography==3.1.1 \ No newline at end of file From bc54668ed2b28244b6232ea9865baeb1cf9be829 Mon Sep 17 00:00:00 2001 From: WhiteSource Renovate Date: Fri, 16 Oct 2020 22:00:06 +0200 Subject: [PATCH 064/136] chore(deps): update dependency google-cloud-kms to v2.2.0 (#57) This PR contains the following updates: | Package | Update | Change | |---|---|---| | [google-cloud-kms](https://togithub.com/googleapis/python-kms) | minor | `==2.0.0` -> `==2.2.0` | --- ### Release Notes
googleapis/python-kms ### [`v2.2.0`](https://togithub.com/googleapis/python-kms/blob/master/CHANGELOG.md#​220-httpswwwgithubcomgoogleapispython-kmscomparev210v220-2020-09-16) [Compare Source](https://togithub.com/googleapis/python-kms/compare/v2.1.0...v2.2.0) ##### Features - regenerate client lib to pick up new mtls env ([#​55](https://www.github.com/googleapis/python-kms/issues/55)) ([4d62c19](https://www.github.com/googleapis/python-kms/commit/4d62c19d2f0f7c597214f2b39dfecb85f9d75a58)) ##### Documentation - add crypto_key_path_path method rename to UPGRADING.md ([#​45](https://www.github.com/googleapis/python-kms/issues/45)) ([81db5d9](https://www.github.com/googleapis/python-kms/commit/81db5d90112092772b83aec57e2358088ed88e0d)), closes [#​43](https://www.github.com/googleapis/python-kms/issues/43) ### [`v2.1.0`](https://togithub.com/googleapis/python-kms/blob/master/CHANGELOG.md#​210-httpswwwgithubcomgoogleapispython-kmscomparev201v210-2020-08-27) [Compare Source](https://togithub.com/googleapis/python-kms/compare/v2.0.1...v2.1.0) ##### Features - accept custom client_info ([#​41](https://www.github.com/googleapis/python-kms/issues/41)) ([6688e80](https://www.github.com/googleapis/python-kms/commit/6688e80aa4db74980d4a6194519c814a22cde177)) ##### [2.0.1](https://www.github.com/googleapis/python-kms/compare/v2.0.0...v2.0.1) (2020-08-24) ##### Bug Fixes - add system test back ([#​39](https://www.github.com/googleapis/python-kms/issues/39)) ([fc5a720](https://www.github.com/googleapis/python-kms/commit/fc5a720d93ba41cd2616c7c9c8012d9a3e8f4a9c)) ##### Documentation - Generate using new common.py_samples() synthtool functionality ([#​35](https://www.github.com/googleapis/python-kms/issues/35)) ([90097bc](https://www.github.com/googleapis/python-kms/commit/90097bca7660f148f36e009f70d108404efa5308)) ### [`v2.0.1`](https://togithub.com/googleapis/python-kms/blob/master/CHANGELOG.md#​201-httpswwwgithubcomgoogleapispython-kmscomparev200v201-2020-08-24) [Compare Source](https://togithub.com/googleapis/python-kms/compare/v2.0.0...v2.0.1)
--- ### Renovate configuration :date: **Schedule**: At any time (no schedule defined). :vertical_traffic_light: **Automerge**: Disabled by config. Please merge this manually once you are satisfied. :recycle: **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox. :no_bell: **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] If you want to rebase/retry this PR, check this box --- This PR has been generated by [WhiteSource Renovate](https://renovate.whitesourcesoftware.com). View repository job log [here](https://app.renovatebot.com/dashboard#github/googleapis/python-kms). --- kms/snippets/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kms/snippets/requirements.txt b/kms/snippets/requirements.txt index 9171879b2eb1..43b8cbd603fb 100644 --- a/kms/snippets/requirements.txt +++ b/kms/snippets/requirements.txt @@ -1,2 +1,2 @@ -google-cloud-kms==2.0.0 +google-cloud-kms==2.2.0 cryptography==3.1.1 \ No newline at end of file From 9d82d9ad925619bd05d57a92565e45947c39a60f Mon Sep 17 00:00:00 2001 From: WhiteSource Renovate Date: Wed, 28 Oct 2020 19:16:18 +0100 Subject: [PATCH 065/136] chore(deps): update dependency cryptography to v3.2.1 (#64) --- kms/attestations/requirements.txt | 2 +- kms/snippets/requirements.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/kms/attestations/requirements.txt b/kms/attestations/requirements.txt index 273aa982d101..23b26085ffa8 100644 --- a/kms/attestations/requirements.txt +++ b/kms/attestations/requirements.txt @@ -1,2 +1,2 @@ -cryptography==3.1.1 +cryptography==3.2.1 pem==20.1.0 diff --git a/kms/snippets/requirements.txt b/kms/snippets/requirements.txt index 43b8cbd603fb..4ad464f21f06 100644 --- a/kms/snippets/requirements.txt +++ b/kms/snippets/requirements.txt @@ -1,2 +1,2 @@ google-cloud-kms==2.2.0 -cryptography==3.1.1 \ No newline at end of file +cryptography==3.2.1 \ No newline at end of file From d8e0fdfeafccade806512a42dce93c15cb39a338 Mon Sep 17 00:00:00 2001 From: lwolfowitz-google <72566822+lwolfowitz-google@users.noreply.github.com> Date: Thu, 5 Nov 2020 17:53:01 -0500 Subject: [PATCH 066/136] samples: Add Python code snippets for importing-a-key doc (#67) --- kms/snippets/check_state_import_job.py | 41 ++++++++++++ kms/snippets/check_state_imported_key.py | 41 ++++++++++++ kms/snippets/create_import_job.py | 44 ++++++++++++ kms/snippets/create_key_for_import.py | 67 +++++++++++++++++++ kms/snippets/import_manually_wrapped_key.py | 74 +++++++++++++++++++++ kms/snippets/snippets_test.py | 52 ++++++++++++++- 6 files changed, 318 insertions(+), 1 deletion(-) create mode 100644 kms/snippets/check_state_import_job.py create mode 100644 kms/snippets/check_state_imported_key.py create mode 100644 kms/snippets/create_import_job.py create mode 100644 kms/snippets/create_key_for_import.py create mode 100644 kms/snippets/import_manually_wrapped_key.py diff --git a/kms/snippets/check_state_import_job.py b/kms/snippets/check_state_import_job.py new file mode 100644 index 000000000000..5d8e05e2a855 --- /dev/null +++ b/kms/snippets/check_state_import_job.py @@ -0,0 +1,41 @@ +# Copyright 2020 Google LLC +# +# 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 + + +# [START kms_check_state_import_job] +def check_state_import_job(project_id, location_id, key_ring_id, import_job_id): + """ + Check the state of an import job in Cloud KMS. + + Args: + project_id (string): Google Cloud project ID (e.g. 'my-project'). + location_id (string): Cloud KMS location (e.g. 'us-east1'). + key_ring_id (string): ID of the Cloud KMS key ring (e.g. 'my-key-ring'). + import_job_id (string): ID of the import job (e.g. 'my-import-job'). + """ + + # Import the client library. + from google.cloud import kms + + # Create the client. + client = kms.KeyManagementServiceClient() + + # Retrieve the fully-qualified import_job string. + import_job_name = client.import_job_path( + project_id, location_id, key_ring_id, import_job_id) + + # Retrieve the state from an existing import job. + import_job = client.get_import_job(name=import_job_name) + + print('Current state of import job {}: {}'.format(import_job.name, import_job.state)) +# [END kms_check_state_import_job] diff --git a/kms/snippets/check_state_imported_key.py b/kms/snippets/check_state_imported_key.py new file mode 100644 index 000000000000..1b65eee1e0ba --- /dev/null +++ b/kms/snippets/check_state_imported_key.py @@ -0,0 +1,41 @@ +# Copyright 2020 Google LLC +# +# 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 + + +# [START kms_check_state_imported_key] +def check_state_imported_key(project_id, location_id, key_ring_id, import_job_id): + """ + Check the state of an import job in Cloud KMS. + + Args: + project_id (string): Google Cloud project ID (e.g. 'my-project'). + location_id (string): Cloud KMS location (e.g. 'us-east1'). + key_ring_id (string): ID of the Cloud KMS key ring (e.g. 'my-key-ring'). + import_job_id (string): ID of the import job (e.g. 'my-import-job'). + """ + + # Import the client library. + from google.cloud import kms + + # Create the client. + client = kms.KeyManagementServiceClient() + + # Retrieve the fully-qualified import_job string. + import_job_name = client.import_job_path( + project_id, location_id, key_ring_id, import_job_id) + + # Retrieve the state from an existing import job. + import_job = client.get_import_job(name=import_job_name) + + print('Current state of import job {}: {}'.format(import_job.name, import_job.state)) +# [END kms_check_state_imported_key] diff --git a/kms/snippets/create_import_job.py b/kms/snippets/create_import_job.py new file mode 100644 index 000000000000..dabd0483c4d1 --- /dev/null +++ b/kms/snippets/create_import_job.py @@ -0,0 +1,44 @@ +# Copyright 2020 Google LLC +# +# 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 + + +# [START kms_create_import_job] +def create_import_job(project_id, location_id, key_ring_id, import_job_id): + """ + Create a new import job in Cloud KMS. + + Args: + project_id (string): Google Cloud project ID (e.g. 'my-project'). + location_id (string): Cloud KMS location (e.g. 'us-east1'). + key_ring_id (string): ID of the Cloud KMS key ring (e.g. 'my-key-ring'). + import_job_id (string): ID of the import job (e.g. 'my-import-job'). + """ + + # Import the client library. + from google.cloud import kms + + # Create the client. + client = kms.KeyManagementServiceClient() + + # Retrieve the fully-qualified key_ring string. + key_ring_name = client.key_ring_path(project_id, location_id, key_ring_id) + + # Set paramaters for the import job, allowed values for ImportMethod and ProtectionLevel found here: + # https://googleapis.dev/python/cloudkms/latest/_modules/google/cloud/kms_v1/types/resources.html + import_job_params = {"import_method": kms.ImportJob.ImportMethod.RSA_OAEP_3072_SHA1_AES_256, "protection_level": kms.ProtectionLevel.HSM} + + # Call the client to create a new import job. + import_job = client.create_import_job({"parent": key_ring_name, "import_job_id": import_job_id, "import_job": import_job_params}) + + print('Created import job: {}'.format(import_job.name)) +# [END kms_create_import_job] diff --git a/kms/snippets/create_key_for_import.py b/kms/snippets/create_key_for_import.py new file mode 100644 index 000000000000..0bd97816406a --- /dev/null +++ b/kms/snippets/create_key_for_import.py @@ -0,0 +1,67 @@ +# Copyright 2020 Google LLC +# +# 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 + + +# [START kms_create_key_for_import] +def create_key_for_import(project_id, location_id, key_ring_id, crypto_key_id): + """ + Generate Cloud KMS-compatible key material locally and sets up an empty CryptoKey within a KeyRing for import. + + Args: + project_id (string): Google Cloud project ID (e.g. 'my-project'). + location_id (string): Cloud KMS location (e.g. 'us-east1'). + key_ring_id (string): ID of the Cloud KMS key ring (e.g. 'my-key-ring'). + crypto_key_id (string): ID of the key to import (e.g. 'my-asymmetric-signing-key'). + """ + + # Import Python standard cryptographic libraries. + from cryptography.hazmat.backends import default_backend + from cryptography.hazmat.primitives import serialization + from cryptography.hazmat.primitives.asymmetric import ec + + # Import the client library. + from google.cloud import kms + + # Generate some key material in Python and format it in PKCS #8 DER as + # required by Google Cloud KMS. + key = ec.generate_private_key(ec.SECP256R1, default_backend()) + formatted_key = key.private_bytes( + serialization.Encoding.DER, + serialization.PrivateFormat.PKCS8, + serialization.NoEncryption()) + + print('Generated key bytes: {}'.format(formatted_key)) + + # Create the client. + client = kms.KeyManagementServiceClient() + + # Build the key. For more information regarding allowed values of these fields, see: + # https://googleapis.dev/python/cloudkms/latest/_modules/google/cloud/kms_v1/types/resources.html + purpose = kms.CryptoKey.CryptoKeyPurpose.ASYMMETRIC_SIGN + algorithm = kms.CryptoKeyVersion.CryptoKeyVersionAlgorithm.EC_SIGN_P256_SHA256 + protection_level = kms.ProtectionLevel.HSM + key = { + 'purpose': purpose, + 'version_template': { + 'algorithm': algorithm, + 'protection_level': protection_level + } + } + + # Build the parent key ring name. + key_ring_name = client.key_ring_path(project_id, location_id, key_ring_id) + + # Call the API. + created_key = client.create_crypto_key(request={'parent': key_ring_name, 'crypto_key_id': crypto_key_id, 'crypto_key': key}) + print('Created hsm key: {}'.format(created_key.name)) +# [END kms_create_key_for_import] diff --git a/kms/snippets/import_manually_wrapped_key.py b/kms/snippets/import_manually_wrapped_key.py new file mode 100644 index 000000000000..97cfcd7bce80 --- /dev/null +++ b/kms/snippets/import_manually_wrapped_key.py @@ -0,0 +1,74 @@ +# Copyright 2020 Google LLC +# +# 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 + + +# [START kms_import_manually_wrapped_key] +def import_manually_wrapped_key(project_id, location_id, key_ring_id, crypto_key_id, import_job_id, key_material): + """ + Imports local key material to Cloud KMS. + + Args: + project_id (string): Google Cloud project ID (e.g. 'my-project'). + location_id (string): Cloud KMS location (e.g. 'us-east1'). + key_ring_id (string): ID of the Cloud KMS key ring (e.g. 'my-key-ring'). + crypto_key_id (string): ID of the key to import (e.g. 'my-asymmetric-signing-key'). + import_job_id (string): ID of the import job (e.g. 'my-import-job'). + key_material (bytes): Locally generated key material in PKCS #8 DER format. + Returns: + CryptoKeyVersion: An instance of the imported key in Cloud KMS. + """ + + # Import the client library and Python standard cryptographic libraries. + import os + from cryptography.hazmat.backends import default_backend + from cryptography.hazmat.primitives import hashes, keywrap, serialization + from cryptography.hazmat.primitives.asymmetric import padding + from google.cloud import kms + + # Create the client. + client = kms.KeyManagementServiceClient() + + # Retrieve the fully-qualified crypto_key and import_job string. + crypto_key_name = client.crypto_key_path( + project_id, location_id, key_ring_id, crypto_key_id) + import_job_name = client.import_job_path( + project_id, location_id, key_ring_id, import_job_id) + + # Generate a temporary 32-byte key for AES-KWP and wrap the key material. + kwp_key = os.urandom(32) + wrapped_target_key = keywrap.aes_key_wrap_with_padding( + kwp_key, key_material, default_backend()) + + # Retrieve the public key from the import job. + import_job = client.get_import_job(name=import_job_name) + import_job_pub = serialization.load_pem_public_key( + bytes(import_job.public_key.pem, 'UTF-8'), default_backend()) + + # Wrap the KWP key using the import job key. + wrapped_kwp_key = import_job_pub.encrypt( + kwp_key, + padding.OAEP( + mgf=padding.MGF1(algorithm=hashes.SHA1()), + algorithm=hashes.SHA1(), + label=None)) + + # Import the wrapped key material. + client.import_crypto_key_version({ + "parent": crypto_key_name, + "import_job": import_job_name, + "algorithm": kms.CryptoKeyVersion.CryptoKeyVersionAlgorithm.EC_SIGN_P256_SHA256, + "rsa_aes_wrapped_key": wrapped_kwp_key + wrapped_target_key, + }) + + print('Imported: {}'.format(import_job.name)) +# [END kms_import_manually_wrapped_key] diff --git a/kms/snippets/snippets_test.py b/kms/snippets/snippets_test.py index 7e3f02ef04ce..b94359b8a6ab 100644 --- a/kms/snippets/snippets_test.py +++ b/kms/snippets/snippets_test.py @@ -20,12 +20,16 @@ from cryptography.exceptions import InvalidSignature from cryptography.hazmat.backends import default_backend from cryptography.hazmat.primitives import hashes, serialization -from cryptography.hazmat.primitives.asymmetric import padding, utils +from cryptography.hazmat.primitives.asymmetric import ec, padding, utils from google.cloud import kms import pytest +from check_state_import_job import check_state_import_job +from check_state_imported_key import check_state_imported_key +from create_import_job import create_import_job from create_key_asymmetric_decrypt import create_key_asymmetric_decrypt from create_key_asymmetric_sign import create_key_asymmetric_sign +from create_key_for_import import create_key_for_import from create_key_hsm import create_key_hsm from create_key_labels import create_key_labels from create_key_ring import create_key_ring @@ -45,6 +49,7 @@ from iam_add_member import iam_add_member from iam_get_policy import iam_get_policy from iam_remove_member import iam_remove_member +from import_manually_wrapped_key import import_manually_wrapped_key from quickstart import quickstart from restore_key_version import restore_key_version from sign_asymmetric import sign_asymmetric @@ -72,6 +77,16 @@ def location_id(): return "us-east1" +@pytest.fixture(scope="module") +def import_job_id(): + return "my-import-job" + + +@pytest.fixture(scope="module") +def import_tests_key_id(): + return "my-import-job-ec-key" + + @pytest.fixture(scope="module") def key_ring_id(client, project_id, location_id): location_name = f"projects/{project_id}/locations/{location_id}" @@ -176,6 +191,24 @@ def wait_for_ready(client, key_version_name): pytest.fail('{} not ready'.format(key_version_name)) +def test_create_import_job(project_id, location_id, key_ring_id, import_job_id, capsys): + create_import_job(project_id, location_id, key_ring_id, import_job_id) + out, _ = capsys.readouterr() + assert "Created import job" in out + + +def test_check_state_import_job(project_id, location_id, key_ring_id, import_job_id, capsys): + check_state_import_job(project_id, location_id, key_ring_id, import_job_id) + out, _ = capsys.readouterr() + assert "Current state" in out + + +def test_check_state_imported_key(project_id, location_id, key_ring_id, import_job_id, capsys): + check_state_imported_key(project_id, location_id, key_ring_id, import_job_id) + out, _ = capsys.readouterr() + assert "Current state" in out + + def test_create_key_asymmetric_decrypt(project_id, location_id, key_ring_id): key_id = '{}'.format(uuid.uuid4()) key = create_key_asymmetric_decrypt(project_id, location_id, key_ring_id, key_id) @@ -190,6 +223,12 @@ def test_create_key_asymmetric_sign(project_id, location_id, key_ring_id): assert key.version_template.algorithm == kms.CryptoKeyVersion.CryptoKeyVersionAlgorithm.RSA_SIGN_PKCS1_2048_SHA256 +def test_create_key_for_import(project_id, location_id, key_ring_id, import_tests_key_id, capsys): + create_key_for_import(project_id, location_id, key_ring_id, import_tests_key_id) + out, _ = capsys.readouterr() + assert "Generated key" in out + + def test_create_key_hsm(project_id, location_id, key_ring_id): key_id = '{}'.format(uuid.uuid4()) key = create_key_hsm(project_id, location_id, key_ring_id, key_id) @@ -347,6 +386,17 @@ def test_iam_remove_member(client, project_id, location_id, key_ring_id, asymmet assert any('group:tester@google.com' in b.members for b in policy.bindings) +def test_import_manually_wrapped_key(project_id, location_id, key_ring_id, import_job_id, import_tests_key_id, capsys): + key = ec.generate_private_key(ec.SECP256R1, default_backend()) + formatted_key = key.private_bytes( + serialization.Encoding.DER, + serialization.PrivateFormat.PKCS8, + serialization.NoEncryption()) + import_manually_wrapped_key(project_id, location_id, key_ring_id, import_tests_key_id, import_job_id, formatted_key) + out, _ = capsys.readouterr() + assert "Imported" in out + + def test_sign_asymmetric(client, project_id, location_id, key_ring_id, asymmetric_sign_rsa_key_id): message = 'my message' From 3dd5d051957a894e0f062f9424541e32aa04c05f Mon Sep 17 00:00:00 2001 From: lwolfowitz-google <72566822+lwolfowitz-google@users.noreply.github.com> Date: Mon, 9 Nov 2020 15:43:51 -0500 Subject: [PATCH 067/136] samples: Minor fixes for importing-a-key snippets (#68) --- kms/snippets/create_import_job.py | 5 ++++- kms/snippets/create_key_for_import.py | 19 +++------------- kms/snippets/import_manually_wrapped_key.py | 25 +++++++++++++-------- kms/snippets/snippets_test.py | 11 +++------ 4 files changed, 26 insertions(+), 34 deletions(-) diff --git a/kms/snippets/create_import_job.py b/kms/snippets/create_import_job.py index dabd0483c4d1..dd79c4e488ea 100644 --- a/kms/snippets/create_import_job.py +++ b/kms/snippets/create_import_job.py @@ -35,7 +35,10 @@ def create_import_job(project_id, location_id, key_ring_id, import_job_id): # Set paramaters for the import job, allowed values for ImportMethod and ProtectionLevel found here: # https://googleapis.dev/python/cloudkms/latest/_modules/google/cloud/kms_v1/types/resources.html - import_job_params = {"import_method": kms.ImportJob.ImportMethod.RSA_OAEP_3072_SHA1_AES_256, "protection_level": kms.ProtectionLevel.HSM} + + import_method = kms.ImportJob.ImportMethod.RSA_OAEP_3072_SHA1_AES_256 + protection_level = kms.ProtectionLevel.HSM + import_job_params = {"import_method": import_method, "protection_level": protection_level} # Call the client to create a new import job. import_job = client.create_import_job({"parent": key_ring_name, "import_job_id": import_job_id, "import_job": import_job_params}) diff --git a/kms/snippets/create_key_for_import.py b/kms/snippets/create_key_for_import.py index 0bd97816406a..3c4e895039cb 100644 --- a/kms/snippets/create_key_for_import.py +++ b/kms/snippets/create_key_for_import.py @@ -15,7 +15,9 @@ # [START kms_create_key_for_import] def create_key_for_import(project_id, location_id, key_ring_id, crypto_key_id): """ - Generate Cloud KMS-compatible key material locally and sets up an empty CryptoKey within a KeyRing for import. + + Sets up an empty CryptoKey within a KeyRing for import. + Args: project_id (string): Google Cloud project ID (e.g. 'my-project'). @@ -24,24 +26,9 @@ def create_key_for_import(project_id, location_id, key_ring_id, crypto_key_id): crypto_key_id (string): ID of the key to import (e.g. 'my-asymmetric-signing-key'). """ - # Import Python standard cryptographic libraries. - from cryptography.hazmat.backends import default_backend - from cryptography.hazmat.primitives import serialization - from cryptography.hazmat.primitives.asymmetric import ec - # Import the client library. from google.cloud import kms - # Generate some key material in Python and format it in PKCS #8 DER as - # required by Google Cloud KMS. - key = ec.generate_private_key(ec.SECP256R1, default_backend()) - formatted_key = key.private_bytes( - serialization.Encoding.DER, - serialization.PrivateFormat.PKCS8, - serialization.NoEncryption()) - - print('Generated key bytes: {}'.format(formatted_key)) - # Create the client. client = kms.KeyManagementServiceClient() diff --git a/kms/snippets/import_manually_wrapped_key.py b/kms/snippets/import_manually_wrapped_key.py index 97cfcd7bce80..fec269e00db0 100644 --- a/kms/snippets/import_manually_wrapped_key.py +++ b/kms/snippets/import_manually_wrapped_key.py @@ -13,9 +13,9 @@ # [START kms_import_manually_wrapped_key] -def import_manually_wrapped_key(project_id, location_id, key_ring_id, crypto_key_id, import_job_id, key_material): +def import_manually_wrapped_key(project_id, location_id, key_ring_id, crypto_key_id, import_job_id): """ - Imports local key material to Cloud KMS. + Generates and imports local key material to Cloud KMS. Args: project_id (string): Google Cloud project ID (e.g. 'my-project'). @@ -23,18 +23,25 @@ def import_manually_wrapped_key(project_id, location_id, key_ring_id, crypto_key key_ring_id (string): ID of the Cloud KMS key ring (e.g. 'my-key-ring'). crypto_key_id (string): ID of the key to import (e.g. 'my-asymmetric-signing-key'). import_job_id (string): ID of the import job (e.g. 'my-import-job'). - key_material (bytes): Locally generated key material in PKCS #8 DER format. - Returns: - CryptoKeyVersion: An instance of the imported key in Cloud KMS. """ # Import the client library and Python standard cryptographic libraries. import os - from cryptography.hazmat.backends import default_backend + from cryptography.hazmat import backends from cryptography.hazmat.primitives import hashes, keywrap, serialization - from cryptography.hazmat.primitives.asymmetric import padding + from cryptography.hazmat.primitives.asymmetric import ec, padding from google.cloud import kms + # Generate some key material in Python and format it in PKCS #8 DER as + # required by Google Cloud KMS. + key = ec.generate_private_key(ec.SECP256R1, backends.default_backend()) + formatted_key = key.private_bytes( + serialization.Encoding.DER, + serialization.PrivateFormat.PKCS8, + serialization.NoEncryption()) + + print('Generated key bytes: {}'.format(formatted_key)) + # Create the client. client = kms.KeyManagementServiceClient() @@ -47,12 +54,12 @@ def import_manually_wrapped_key(project_id, location_id, key_ring_id, crypto_key # Generate a temporary 32-byte key for AES-KWP and wrap the key material. kwp_key = os.urandom(32) wrapped_target_key = keywrap.aes_key_wrap_with_padding( - kwp_key, key_material, default_backend()) + kwp_key, formatted_key, backends.default_backend()) # Retrieve the public key from the import job. import_job = client.get_import_job(name=import_job_name) import_job_pub = serialization.load_pem_public_key( - bytes(import_job.public_key.pem, 'UTF-8'), default_backend()) + bytes(import_job.public_key.pem, 'UTF-8'), backends.default_backend()) # Wrap the KWP key using the import job key. wrapped_kwp_key = import_job_pub.encrypt( diff --git a/kms/snippets/snippets_test.py b/kms/snippets/snippets_test.py index b94359b8a6ab..8efeb514d170 100644 --- a/kms/snippets/snippets_test.py +++ b/kms/snippets/snippets_test.py @@ -20,7 +20,7 @@ from cryptography.exceptions import InvalidSignature from cryptography.hazmat.backends import default_backend from cryptography.hazmat.primitives import hashes, serialization -from cryptography.hazmat.primitives.asymmetric import ec, padding, utils +from cryptography.hazmat.primitives.asymmetric import padding, utils from google.cloud import kms import pytest @@ -226,7 +226,7 @@ def test_create_key_asymmetric_sign(project_id, location_id, key_ring_id): def test_create_key_for_import(project_id, location_id, key_ring_id, import_tests_key_id, capsys): create_key_for_import(project_id, location_id, key_ring_id, import_tests_key_id) out, _ = capsys.readouterr() - assert "Generated key" in out + assert "Created hsm key" in out def test_create_key_hsm(project_id, location_id, key_ring_id): @@ -387,12 +387,7 @@ def test_iam_remove_member(client, project_id, location_id, key_ring_id, asymmet def test_import_manually_wrapped_key(project_id, location_id, key_ring_id, import_job_id, import_tests_key_id, capsys): - key = ec.generate_private_key(ec.SECP256R1, default_backend()) - formatted_key = key.private_bytes( - serialization.Encoding.DER, - serialization.PrivateFormat.PKCS8, - serialization.NoEncryption()) - import_manually_wrapped_key(project_id, location_id, key_ring_id, import_tests_key_id, import_job_id, formatted_key) + import_manually_wrapped_key(project_id, location_id, key_ring_id, import_tests_key_id, import_job_id) out, _ = capsys.readouterr() assert "Imported" in out From abe0570c76f2534495e985f94df8ec34ef9f61ad Mon Sep 17 00:00:00 2001 From: Tamara Aviv <73185172+iamtamjam@users.noreply.github.com> Date: Thu, 12 Nov 2020 14:06:39 -0500 Subject: [PATCH 068/136] samples: add request/response integrity verification to encrypt_symmetric.py (#70) --- kms/snippets/encrypt_symmetric.py | 33 ++++++++++++++++++++++++++++++- kms/snippets/requirements.txt | 3 ++- 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/kms/snippets/encrypt_symmetric.py b/kms/snippets/encrypt_symmetric.py index 9cc3b1a5d12c..9340133b8b3d 100644 --- a/kms/snippets/encrypt_symmetric.py +++ b/kms/snippets/encrypt_symmetric.py @@ -38,6 +38,10 @@ def encrypt_symmetric(project_id, location_id, key_ring_id, key_id, plaintext): # Convert the plaintext to bytes. plaintext_bytes = plaintext.encode('utf-8') + # Optional, but recommended: compute plaintext's CRC32C. + # See crc32c() function defined below. + plaintext_crc32c = crc32c(plaintext_bytes) + # Create the client. client = kms.KeyManagementServiceClient() @@ -45,7 +49,34 @@ def encrypt_symmetric(project_id, location_id, key_ring_id, key_id, plaintext): key_name = client.crypto_key_path(project_id, location_id, key_ring_id, key_id) # Call the API. - encrypt_response = client.encrypt(request={'name': key_name, 'plaintext': plaintext_bytes}) + encrypt_response = client.encrypt( + request={'name': key_name, 'plaintext': plaintext_bytes, 'plaintext_crc32c': plaintext_crc32c}) + + # Optional, but recommended: perform integrity verification on encrypt_response. + # For more details on ensuring E2E in-transit integrity to and from Cloud KMS visit: + # https://cloud.google.com/kms/docs/data-integrity-guidelines + if not encrypt_response.verified_plaintext_crc32c: + raise Exception('The request sent to the server was corrupted in-transit.') + if not encrypt_response.ciphertext_crc32c == crc32c(encrypt_response.ciphertext): + raise Exception('The response received from the server was corrupted in-transit.') + # End integrity verification + print('Ciphertext: {}'.format(base64.b64encode(encrypt_response.ciphertext))) return encrypt_response + + +def crc32c(data): + """ + Calculates the CRC32C checksum of the provided data. + + Args: + data: the bytes over which the checksum should be calculated. + + Returns: + An int representing the CRC32C checksum of the provided bytes. + """ + import crcmod + import six + crc32c_fun = crcmod.predefined.mkPredefinedCrcFun('crc-32c') + return crc32c_fun(six.ensure_binary(data)) # [END kms_encrypt_symmetric] diff --git a/kms/snippets/requirements.txt b/kms/snippets/requirements.txt index 4ad464f21f06..8cb81ca5c7c1 100644 --- a/kms/snippets/requirements.txt +++ b/kms/snippets/requirements.txt @@ -1,2 +1,3 @@ google-cloud-kms==2.2.0 -cryptography==3.2.1 \ No newline at end of file +cryptography==3.2.1 +crcmod==1.7 From fb39d7665d6b7e36c6706d9236f4315de6a729a1 Mon Sep 17 00:00:00 2001 From: Tamara Aviv <73185172+iamtamjam@users.noreply.github.com> Date: Mon, 14 Dec 2020 15:36:37 -0500 Subject: [PATCH 069/136] samples: Add request/response integrity verification to crypto operations (#72) --- kms/snippets/decrypt_asymmetric.py | 31 ++++++++++++++++++++++++++- kms/snippets/decrypt_symmetric.py | 29 ++++++++++++++++++++++++- kms/snippets/get_public_key.py | 25 ++++++++++++++++++++++ kms/snippets/sign_asymmetric.py | 34 ++++++++++++++++++++++++++++-- 4 files changed, 115 insertions(+), 4 deletions(-) diff --git a/kms/snippets/decrypt_asymmetric.py b/kms/snippets/decrypt_asymmetric.py index 7f5397c92392..006d5afb9637 100644 --- a/kms/snippets/decrypt_asymmetric.py +++ b/kms/snippets/decrypt_asymmetric.py @@ -39,8 +39,37 @@ def decrypt_asymmetric(project_id, location_id, key_ring_id, key_id, version_id, # Build the key version name. key_version_name = client.crypto_key_version_path(project_id, location_id, key_ring_id, key_id, version_id) + # Optional, but recommended: compute ciphertext's CRC32C. + # See crc32c() function defined below. + ciphertext_crc32c = crc32c(ciphertext) + # Call the API. - decrypt_response = client.asymmetric_decrypt(request={'name': key_version_name, 'ciphertext': ciphertext}) + decrypt_response = client.asymmetric_decrypt( + request={'name': key_version_name, 'ciphertext': ciphertext, 'ciphertext_crc32c': ciphertext_crc32c}) + + # Optional, but recommended: perform integrity verification on decrypt_response. + # For more details on ensuring E2E in-transit integrity to and from Cloud KMS visit: + # https://cloud.google.com/kms/docs/data-integrity-guidelines + if not decrypt_response.verified_ciphertext_crc32c: + raise Exception('The request sent to the server was corrupted in-transit.') + if not decrypt_response.plaintext_crc32c == crc32c(decrypt_response.plaintext): + raise Exception('The response received from the server was corrupted in-transit.') + # End integrity verification + print('Plaintext: {}'.format(decrypt_response.plaintext)) return decrypt_response + + +def crc32c(data): + """ + Calculates the CRC32C checksum of the provided data. + Args: + data: the bytes over which the checksum should be calculated. + Returns: + An int representing the CRC32C checksum of the provided bytes. + """ + import crcmod + import six + crc32c_fun = crcmod.predefined.mkPredefinedCrcFun('crc-32c') + return crc32c_fun(six.ensure_binary(data)) # [END kms_decrypt_asymmetric] diff --git a/kms/snippets/decrypt_symmetric.py b/kms/snippets/decrypt_symmetric.py index c0b64d3b2d16..8c6ec724f2c3 100644 --- a/kms/snippets/decrypt_symmetric.py +++ b/kms/snippets/decrypt_symmetric.py @@ -38,8 +38,35 @@ def decrypt_symmetric(project_id, location_id, key_ring_id, key_id, ciphertext): # Build the key name. key_name = client.crypto_key_path(project_id, location_id, key_ring_id, key_id) + # Optional, but recommended: compute ciphertext's CRC32C. + # See crc32c() function defined below. + ciphertext_crc32c = crc32c(ciphertext) + # Call the API. - decrypt_response = client.decrypt(request={'name': key_name, 'ciphertext': ciphertext}) + decrypt_response = client.decrypt( + request={'name': key_name, 'ciphertext': ciphertext, 'ciphertext_crc32c': ciphertext_crc32c}) + + # Optional, but recommended: perform integrity verification on decrypt_response. + # For more details on ensuring E2E in-transit integrity to and from Cloud KMS visit: + # https://cloud.google.com/kms/docs/data-integrity-guidelines + if not decrypt_response.plaintext_crc32c == crc32c(decrypt_response.plaintext): + raise Exception('The response received from the server was corrupted in-transit.') + # End integrity verification + print('Plaintext: {}'.format(decrypt_response.plaintext)) return decrypt_response + + +def crc32c(data): + """ + Calculates the CRC32C checksum of the provided data. + Args: + data: the bytes over which the checksum should be calculated. + Returns: + An int representing the CRC32C checksum of the provided bytes. + """ + import crcmod + import six + crc32c_fun = crcmod.predefined.mkPredefinedCrcFun('crc-32c') + return crc32c_fun(six.ensure_binary(data)) # [END kms_decrypt_symmetric] diff --git a/kms/snippets/get_public_key.py b/kms/snippets/get_public_key.py index bdc91139944d..e265f7fd67b3 100644 --- a/kms/snippets/get_public_key.py +++ b/kms/snippets/get_public_key.py @@ -40,6 +40,31 @@ def get_public_key(project_id, location_id, key_ring_id, key_id, version_id): # Call the API. public_key = client.get_public_key(request={'name': key_version_name}) + + # Optional, but recommended: perform integrity verification on public_key. + # For more details on ensuring E2E in-transit integrity to and from Cloud KMS visit: + # https://cloud.google.com/kms/docs/data-integrity-guidelines + if not public_key.name == key_version_name: + raise Exception('The request sent to the server was corrupted in-transit.') + # See crc32c() function defined below. + if not public_key.pem_crc32c == crc32c(public_key.pem): + raise Exception('The response received from the server was corrupted in-transit.') + # End integrity verification + print('Public key: {}'.format(public_key.pem)) return public_key + + +def crc32c(data): + """ + Calculates the CRC32C checksum of the provided data. + Args: + data: the bytes over which the checksum should be calculated. + Returns: + An int representing the CRC32C checksum of the provided bytes. + """ + import crcmod + import six + crc32c_fun = crcmod.predefined.mkPredefinedCrcFun('crc-32c') + return crc32c_fun(six.ensure_binary(data)) # [END kms_get_public_key] diff --git a/kms/snippets/sign_asymmetric.py b/kms/snippets/sign_asymmetric.py index c12a31d2d1f5..6b8baa7a7747 100644 --- a/kms/snippets/sign_asymmetric.py +++ b/kms/snippets/sign_asymmetric.py @@ -27,7 +27,6 @@ def sign_asymmetric(project_id, location_id, key_ring_id, key_id, version_id, me Returns: AsymmetricSignResponse: Signature. - """ # Import the client library. @@ -57,8 +56,39 @@ def sign_asymmetric(project_id, location_id, key_ring_id, key_id, version_id, me # example, EC_SIGN_P384_SHA384 requires SHA-384. digest = {'sha256': hash_} + # Optional, but recommended: compute digest's CRC32C. + # See crc32c() function defined below. + digest_crc32c = crc32c(hash_) + # Call the API - sign_response = client.asymmetric_sign(request={'name': key_version_name, 'digest': digest}) + sign_response = client.asymmetric_sign( + request={'name': key_version_name, 'digest': digest, 'digest_crc32c': digest_crc32c}) + + # Optional, but recommended: perform integrity verification on sign_response. + # For more details on ensuring E2E in-transit integrity to and from Cloud KMS visit: + # https://cloud.google.com/kms/docs/data-integrity-guidelines + if not sign_response.verified_digest_crc32c: + raise Exception('The request sent to the server was corrupted in-transit.') + if not sign_response.name == key_version_name: + raise Exception('The request sent to the server was corrupted in-transit.') + if not sign_response.signature_crc32c == crc32c(sign_response.signature): + raise Exception('The response received from the server was corrupted in-transit.') + # End integrity verification + print('Signature: {}'.format(base64.b64encode(sign_response.signature))) return sign_response + + +def crc32c(data): + """ + Calculates the CRC32C checksum of the provided data. + Args: + data: the bytes over which the checksum should be calculated. + Returns: + An int representing the CRC32C checksum of the provided bytes. + """ + import crcmod + import six + crc32c_fun = crcmod.predefined.mkPredefinedCrcFun('crc-32c') + return crc32c_fun(six.ensure_binary(data)) # [END kms_sign_asymmetric] From 057017ed4863632d3b3d4f1ec35c6440dbbfd393 Mon Sep 17 00:00:00 2001 From: WhiteSource Renovate Date: Tue, 15 Dec 2020 23:30:38 +0100 Subject: [PATCH 070/136] chore(deps): update dependency cryptography to v3.3.1 (#78) --- kms/attestations/requirements.txt | 2 +- kms/snippets/requirements.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/kms/attestations/requirements.txt b/kms/attestations/requirements.txt index 23b26085ffa8..9a251876f98f 100644 --- a/kms/attestations/requirements.txt +++ b/kms/attestations/requirements.txt @@ -1,2 +1,2 @@ -cryptography==3.2.1 +cryptography==3.3.1 pem==20.1.0 diff --git a/kms/snippets/requirements.txt b/kms/snippets/requirements.txt index 8cb81ca5c7c1..5383f21a0129 100644 --- a/kms/snippets/requirements.txt +++ b/kms/snippets/requirements.txt @@ -1,3 +1,3 @@ google-cloud-kms==2.2.0 -cryptography==3.2.1 +cryptography==3.3.1 crcmod==1.7 From 2b395713ae5b5079dbcd6cfe5b6b89131be801b5 Mon Sep 17 00:00:00 2001 From: WhiteSource Renovate Date: Fri, 22 Jan 2021 17:21:52 +0100 Subject: [PATCH 071/136] chore(deps): update dependency pem to v21 (#82) --- kms/attestations/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kms/attestations/requirements.txt b/kms/attestations/requirements.txt index 9a251876f98f..277ba3df448f 100644 --- a/kms/attestations/requirements.txt +++ b/kms/attestations/requirements.txt @@ -1,2 +1,2 @@ cryptography==3.3.1 -pem==20.1.0 +pem==21.1.0 From 391284a210397aa7dcac5d9619e535962508fc46 Mon Sep 17 00:00:00 2001 From: WhiteSource Renovate Date: Wed, 10 Feb 2021 17:13:39 +0100 Subject: [PATCH 072/136] chore(deps): update dependency cryptography to v3.4.4 (#85) --- kms/attestations/requirements.txt | 2 +- kms/snippets/requirements.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/kms/attestations/requirements.txt b/kms/attestations/requirements.txt index 277ba3df448f..24dc23d15175 100644 --- a/kms/attestations/requirements.txt +++ b/kms/attestations/requirements.txt @@ -1,2 +1,2 @@ -cryptography==3.3.1 +cryptography==3.4.4 pem==21.1.0 diff --git a/kms/snippets/requirements.txt b/kms/snippets/requirements.txt index 5383f21a0129..df9126b039c0 100644 --- a/kms/snippets/requirements.txt +++ b/kms/snippets/requirements.txt @@ -1,3 +1,3 @@ google-cloud-kms==2.2.0 -cryptography==3.3.1 +cryptography==3.4.4 crcmod==1.7 From 6101b1fedb01d8298ae6e743c73ed85771c4c57c Mon Sep 17 00:00:00 2001 From: WhiteSource Renovate Date: Tue, 16 Feb 2021 20:34:02 +0100 Subject: [PATCH 073/136] chore(deps): update dependency cryptography to v3.4.5 (#88) --- kms/attestations/requirements.txt | 2 +- kms/snippets/requirements.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/kms/attestations/requirements.txt b/kms/attestations/requirements.txt index 24dc23d15175..f8533646cb4b 100644 --- a/kms/attestations/requirements.txt +++ b/kms/attestations/requirements.txt @@ -1,2 +1,2 @@ -cryptography==3.4.4 +cryptography==3.4.5 pem==21.1.0 diff --git a/kms/snippets/requirements.txt b/kms/snippets/requirements.txt index df9126b039c0..8f7238b150b9 100644 --- a/kms/snippets/requirements.txt +++ b/kms/snippets/requirements.txt @@ -1,3 +1,3 @@ google-cloud-kms==2.2.0 -cryptography==3.4.4 +cryptography==3.4.5 crcmod==1.7 From ea46a5e1aaca7abb5ee1be881534cf3b9c7f3936 Mon Sep 17 00:00:00 2001 From: WhiteSource Renovate Date: Sat, 20 Feb 2021 06:58:51 +0100 Subject: [PATCH 074/136] chore(deps): update dependency cryptography to v3.4.6 (#89) --- kms/attestations/requirements.txt | 2 +- kms/snippets/requirements.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/kms/attestations/requirements.txt b/kms/attestations/requirements.txt index f8533646cb4b..e5ec5fa0ef26 100644 --- a/kms/attestations/requirements.txt +++ b/kms/attestations/requirements.txt @@ -1,2 +1,2 @@ -cryptography==3.4.5 +cryptography==3.4.6 pem==21.1.0 diff --git a/kms/snippets/requirements.txt b/kms/snippets/requirements.txt index 8f7238b150b9..8174aeb05912 100644 --- a/kms/snippets/requirements.txt +++ b/kms/snippets/requirements.txt @@ -1,3 +1,3 @@ google-cloud-kms==2.2.0 -cryptography==3.4.5 +cryptography==3.4.6 crcmod==1.7 From 31fdee1013cac6181c474e6bfd3971941e433948 Mon Sep 17 00:00:00 2001 From: WhiteSource Renovate Date: Fri, 26 Mar 2021 06:27:03 +0100 Subject: [PATCH 075/136] chore(deps): update dependency cryptography to v3.4.7 (#93) --- kms/attestations/requirements.txt | 2 +- kms/snippets/requirements.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/kms/attestations/requirements.txt b/kms/attestations/requirements.txt index e5ec5fa0ef26..350efff8985d 100644 --- a/kms/attestations/requirements.txt +++ b/kms/attestations/requirements.txt @@ -1,2 +1,2 @@ -cryptography==3.4.6 +cryptography==3.4.7 pem==21.1.0 diff --git a/kms/snippets/requirements.txt b/kms/snippets/requirements.txt index 8174aeb05912..2d676ec353a4 100644 --- a/kms/snippets/requirements.txt +++ b/kms/snippets/requirements.txt @@ -1,3 +1,3 @@ google-cloud-kms==2.2.0 -cryptography==3.4.6 +cryptography==3.4.7 crcmod==1.7 From 462b1f7793d4b92ccacc6c803a830da7aa8b5c58 Mon Sep 17 00:00:00 2001 From: WhiteSource Renovate Date: Tue, 13 Apr 2021 19:31:12 +0200 Subject: [PATCH 076/136] chore(deps): update dependency pem to v21.2.0 (#96) --- kms/attestations/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kms/attestations/requirements.txt b/kms/attestations/requirements.txt index 350efff8985d..3f688a1c2cf6 100644 --- a/kms/attestations/requirements.txt +++ b/kms/attestations/requirements.txt @@ -1,2 +1,2 @@ cryptography==3.4.7 -pem==21.1.0 +pem==21.2.0 From 277ffb802cbc3afe01617a98940cdf345aa02925 Mon Sep 17 00:00:00 2001 From: Benson Kuang <3453547+bkuang@users.noreply.github.com> Date: Fri, 23 Apr 2021 13:24:43 -0400 Subject: [PATCH 077/136] feat: add script to verify attestations with certificate chains (#99) Co-authored-by: Benson Kuang --- kms/attestations/verify_attestation_chains.py | 296 ++++++++++++++++ .../verify_attestation_chains_test.py | 321 ++++++++++++++++++ 2 files changed, 617 insertions(+) create mode 100644 kms/attestations/verify_attestation_chains.py create mode 100644 kms/attestations/verify_attestation_chains_test.py diff --git a/kms/attestations/verify_attestation_chains.py b/kms/attestations/verify_attestation_chains.py new file mode 100644 index 000000000000..30a5b9226afa --- /dev/null +++ b/kms/attestations/verify_attestation_chains.py @@ -0,0 +1,296 @@ +#!/usr/bin/env python + +# Copyright 2021 Google, LLC. +# +# 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. +"""This application verifies HSM certificate chains. + +For more information, visit https://cloud.google.com/kms/docs/attest-key. +""" + +# [START kms_verify_chains] +import argparse +import gzip +import io +import zipfile + +from cryptography import exceptions +from cryptography import x509 +from cryptography.hazmat import backends +from cryptography.hazmat.primitives import hashes +from cryptography.hazmat.primitives import serialization +from cryptography.hazmat.primitives.asymmetric import padding +import pem +import requests + +ATTESTATION_SIGNATURE_LEN = 256 + +MANUFACTURER_CERT_URL = 'https://www.marvell.com/content/dam/marvell/en/public-collateral/security-solutions/liquid_security_certificate.zip' + +# +MANUFACTURER_CERT_SUBJECT_BYTES = ( + b'0\x81\x911\x0b0\t\x06\x03U\x04\x06\x13\x02US1\x130\x11\x06\x03U\x04\x08' + b'\x0c\nCalifornia1\x110\x0f\x06\x03U\x04\x07\x0c\x08San Jose1\x150\x13\x06' + b'\x03U\x04\n\x0c\x0cCavium, Inc.1\x170\x15\x06\x03U\x04\x0b\x0c\x0e' + b'LiquidSecurity1*0(\x06\x03U\x04\x03\x0c!localca.liquidsecurity.cavium.com' +) + +# The owner root cert can be obtained from +# 'https://www.gstatic.com/cloudhsm/roots/global_1498867200.pem' +OWNER_ROOT_CERT_PEM = """Certificate: + Data: + Version: 3 (0x2) + Serial Number: 3 (0x3) + Signature Algorithm: sha256WithRSAEncryption + Issuer: C = US, ST = CA, L = Mountain View, O = Google Inc, CN = Hawksbill Root v1 prod + Validity + Not Before: Jul 1 00:00:00 2017 GMT + Not After : Jan 1 00:00:00 2030 GMT + Subject: C = US, ST = CA, L = Mountain View, O = Google Inc, CN = Hawksbill Root v1 prod + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public-Key: (2048 bit) + Modulus: + 00:ac:2e:a8:62:89:21:a0:70:92:df:b0:8e:c3:93: + 4d:26:38:db:a5:a2:5f:6b:1e:6d:a8:6c:2c:83:d6: + 5b:9a:f8:02:a0:f8:b0:16:fb:5c:da:b9:9b:b9:8b: + 4d:bc:15:26:e0:0e:4f:2f:b5:20:43:1c:31:7e:5e: + c1:67:a9:36:c8:19:5e:c2:b5:a8:b6:96:76:90:7b: + 55:15:4d:53:16:10:f0:62:d5:d8:98:19:c7:9e:0e: + b2:69:26:a3:f3:d9:a5:d3:70:88:21:ac:62:12:7b: + 2a:be:20:2e:33:db:9b:90:a7:b1:bf:0f:c0:11:7a: + c2:98:a9:8c:4d:36:a7:1f:66:53:08:93:4b:3a:12: + 1e:1a:3f:2b:c2:5d:8b:4b:97:d4:17:0f:41:83:27: + a9:f3:e0:d9:82:f8:5c:37:d4:1e:5d:e4:a8:3d:59: + 7c:43:64:e6:02:d7:35:39:f4:95:db:77:1c:73:78: + 2f:c4:26:8d:64:d4:01:e0:86:da:3f:27:c7:9d:bd: + 32:25:e4:d4:34:6a:13:87:2a:85:19:ce:18:43:46: + c5:41:8a:81:66:ca:65:6e:c1:a1:ce:71:74:d4:b0: + 77:b7:35:39:0d:c9:e2:c8:7e:81:69:b1:04:38:5d: + c1:fd:92:33:ba:ed:85:d3:91:d0:96:78:d6:30:fc: + 56:19 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Key Usage: critical + Digital Signature, Certificate Sign, CRL Sign + X509v3 Subject Key Identifier: + 31:E8:52:DF:E1:49:F8:12:7B:7C:6E:E7:4E:91:7A:97:75:BC:A8:AE + Signature Algorithm: sha256WithRSAEncryption + 8f:12:8e:8e:7a:fb:59:82:a8:0f:e6:be:b8:09:5d:17:c8:8e: + c1:3a:c7:a4:52:d4:0d:2e:ac:a8:5c:b1:f4:52:ee:b7:c4:25: + 9a:2a:32:fc:91:3d:ba:29:9a:ed:c8:de:1f:75:39:54:16:d1: + 72:74:e0:95:a0:e2:41:36:9c:f8:95:c2:21:10:29:12:5f:4d: + d1:b0:e1:a1:5b:c5:79:3c:d1:23:c9:c9:74:c2:42:58:fa:1b: + 35:75:77:30:7a:58:b2:07:e0:cd:ec:21:e2:51:54:59:08:21: + be:c7:05:df:6e:55:81:21:0d:d1:ad:61:81:77:27:3e:bd:39: + 81:df:bd:91:32:3d:cc:5d:eb:de:fc:a7:73:26:2f:cd:88:a7: + 70:65:f4:35:06:b3:d6:02:56:e1:ba:e6:d5:6f:b0:4d:b5:95: + cb:c6:34:a3:a7:35:79:99:bb:bf:cb:07:a0:d4:a0:de:f2:2c: + e8:9b:27:43:c6:c0:5c:ae:62:da:a3:bf:01:76:50:bb:6e:70: + 1f:56:8f:41:cb:7c:41:d1:b0:c7:62:41:b2:31:23:99:6a:47: + b8:10:c0:5c:f0:9e:b0:3e:5c:bb:d5:33:cc:38:1c:a5:dc:26: + 8b:b5:e2:76:5e:f8:92:3d:df:fc:78:2b:39:e8:a6:45:d3:9b: + f2:51:b9:fc +-----BEGIN CERTIFICATE----- +MIIDjTCCAnWgAwIBAgIBAzANBgkqhkiG9w0BAQsFADBoMQswCQYDVQQGEwJVUzEL +MAkGA1UECAwCQ0ExFjAUBgNVBAcMDU1vdW50YWluIFZpZXcxEzARBgNVBAoMCkdv +b2dsZSBJbmMxHzAdBgNVBAMMFkhhd2tzYmlsbCBSb290IHYxIHByb2QwHhcNMTcw +NzAxMDAwMDAwWhcNMzAwMTAxMDAwMDAwWjBoMQswCQYDVQQGEwJVUzELMAkGA1UE +CAwCQ0ExFjAUBgNVBAcMDU1vdW50YWluIFZpZXcxEzARBgNVBAoMCkdvb2dsZSBJ +bmMxHzAdBgNVBAMMFkhhd2tzYmlsbCBSb290IHYxIHByb2QwggEiMA0GCSqGSIb3 +DQEBAQUAA4IBDwAwggEKAoIBAQCsLqhiiSGgcJLfsI7Dk00mONulol9rHm2obCyD +1lua+AKg+LAW+1zauZu5i028FSbgDk8vtSBDHDF+XsFnqTbIGV7Ctai2lnaQe1UV +TVMWEPBi1diYGceeDrJpJqPz2aXTcIghrGISeyq+IC4z25uQp7G/D8AResKYqYxN +NqcfZlMIk0s6Eh4aPyvCXYtLl9QXD0GDJ6nz4NmC+Fw31B5d5Kg9WXxDZOYC1zU5 +9JXbdxxzeC/EJo1k1AHghto/J8edvTIl5NQ0ahOHKoUZzhhDRsVBioFmymVuwaHO +cXTUsHe3NTkNyeLIfoFpsQQ4XcH9kjO67YXTkdCWeNYw/FYZAgMBAAGjQjBAMA8G +A1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBQx6FLf4Un4 +Ent8budOkXqXdbyorjANBgkqhkiG9w0BAQsFAAOCAQEAjxKOjnr7WYKoD+a+uAld +F8iOwTrHpFLUDS6sqFyx9FLut8Qlmioy/JE9uima7cjeH3U5VBbRcnTglaDiQTac ++JXCIRApEl9N0bDhoVvFeTzRI8nJdMJCWPobNXV3MHpYsgfgzewh4lFUWQghvscF +325VgSEN0a1hgXcnPr05gd+9kTI9zF3r3vyncyYvzYincGX0NQaz1gJW4brm1W+w +TbWVy8Y0o6c1eZm7v8sHoNSg3vIs6JsnQ8bAXK5i2qO/AXZQu25wH1aPQct8QdGw +x2JBsjEjmWpHuBDAXPCesD5cu9UzzDgcpdwmi7Xidl74kj3f/HgrOeimRdOb8lG5 +/A== +-----END CERTIFICATE----- +""" + + +def get_manufacturer_root_certificate(): + """Gets the manufacturer root certificate.""" + resp = requests.get(MANUFACTURER_CERT_URL) + tmp_file = io.BytesIO(resp.content) + zip_file = zipfile.ZipFile(tmp_file) + with zip_file.open('liquid_security_certificate.crt') as f: + return x509.load_pem_x509_certificate(f.read(), backends.default_backend()) + + +def get_owner_root_certificate(): + """Gets the owner root certificate.""" + return x509.load_pem_x509_certificate( + OWNER_ROOT_CERT_PEM.encode('utf-8'), backends.default_backend()) + + +def verify_certificate(signing_cert, issued_cert): + """Verifies the signing_cert issued the issued_cert. + + Args: + signing_cert: The certificate used to verify the issued certificate's + signature. + issued_cert: The issued certificate. + + Returns: + True if the signing_cert issued the issued_cert. + """ + if signing_cert.subject != issued_cert.issuer: + return False + try: + signing_cert.public_key().verify(issued_cert.signature, + issued_cert.tbs_certificate_bytes, + padding.PKCS1v15(), + issued_cert.signature_hash_algorithm) + return True + except exceptions.InvalidSignature: + return False + return False + + +def get_issued_certificate(issuer_cert, + untrusted_certs, + predicate=lambda _: True): + """Finds an issued certificates issued by an issuer certificate. + + The issued certificate is removed from the set of untrusted certificates. + + Args: + issuer_cert: The issuer certificate. + untrusted_certs: A set of untrusted certificates. + predicate: An additional condition for the issued certificate. + + Returns: + A certificate within the set of untrusted certificates that was issued + by the issuer certificate and matches the predicate. + """ + for cert in untrusted_certs: + if verify_certificate(issuer_cert, cert) and predicate(cert): + untrusted_certs.remove(cert) + return cert + return None + + +def verify_attestation(cert, attestation): + """Verifies that the certificate signed the attestation. + + Args: + cert: The certificate used to verify the attestation. + attestation: The attestation to verify. + + Returns: + True if the certificate verified the attestation. + """ + data = attestation[:-ATTESTATION_SIGNATURE_LEN] + signature = attestation[-ATTESTATION_SIGNATURE_LEN:] + try: + cert.public_key().verify(signature, data, padding.PKCS1v15(), + hashes.SHA256()) + return True + except exceptions.InvalidSignature: + return False + return False + + +def verify(certs_file, attestation_file): + """Verifies that the certificate chains are valid. + + Args: + certs_file: The certificate chains filename. + attestation_file: The attestation filename. + + Returns: + True if the certificate chains are valid. + """ + mfr_root_cert = get_manufacturer_root_certificate() + if (mfr_root_cert.subject.public_bytes(backends.default_backend()) != + MANUFACTURER_CERT_SUBJECT_BYTES): + return False + + untrusted_certs_pem = pem.parse_file(certs_file) + untrusted_certs = { + x509.load_pem_x509_certificate( + str(cert_pem).encode('utf-8'), backends.default_backend()) + for cert_pem in untrusted_certs_pem + } + + # Build the manufacturer certificate chain. + mfr_card_cert = get_issued_certificate(mfr_root_cert, untrusted_certs) + mfr_partition_cert = get_issued_certificate(mfr_card_cert, untrusted_certs) + if not mfr_card_cert or not mfr_partition_cert: + print('Invalid HSM manufacturer certificate chain.') + return False + print('Successfully built HSM manufacturer certificate chain.') + + owner_root_cert = get_owner_root_certificate() + + # Build the owner card certificate chain. + def _check_card_pub_key(cert): + cert_pub_key_bytes = cert.public_key().public_bytes( + serialization.Encoding.DER, + serialization.PublicFormat.SubjectPublicKeyInfo) + mfr_card_pub_key_bytes = mfr_card_cert.public_key().public_bytes( + serialization.Encoding.DER, + serialization.PublicFormat.SubjectPublicKeyInfo) + return cert_pub_key_bytes == mfr_card_pub_key_bytes + + owner_card_cert = get_issued_certificate( + owner_root_cert, untrusted_certs, predicate=_check_card_pub_key) + + # Build the owner partition certificate chain. + def _check_partition_pub_key(cert): + cert_pub_key_bytes = cert.public_key().public_bytes( + serialization.Encoding.PEM, + serialization.PublicFormat.SubjectPublicKeyInfo) + mfr_partition_pub_key_bytes = mfr_partition_cert.public_key().public_bytes( + serialization.Encoding.PEM, + serialization.PublicFormat.SubjectPublicKeyInfo) + return cert_pub_key_bytes == mfr_partition_pub_key_bytes + + owner_partition_cert = get_issued_certificate( + owner_root_cert, untrusted_certs, predicate=_check_partition_pub_key) + + if not owner_card_cert or not owner_partition_cert or untrusted_certs: + print('Invalid HSM owner certificate chain.') + return False + print('Successfully built HSM owner certificate chain.') + + with gzip.open(attestation_file, 'rb') as f: + attestation = f.read() + return (verify_attestation(mfr_partition_cert, attestation) and + verify_attestation(owner_partition_cert, attestation)) + + +if __name__ == '__main__': + parser = argparse.ArgumentParser( + description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter) + parser.add_argument( + '--certificates', help='The certificate chains filename.') + parser.add_argument('--attestation', help='The attestation filename.') + + args = parser.parse_args() + + if verify(args.certificates, args.attestation): + print('The attestation has been verified.') + else: + print('The attestation could not be verified.') +# [END kms_verify_chains] diff --git a/kms/attestations/verify_attestation_chains_test.py b/kms/attestations/verify_attestation_chains_test.py new file mode 100644 index 000000000000..480fe318c067 --- /dev/null +++ b/kms/attestations/verify_attestation_chains_test.py @@ -0,0 +1,321 @@ +# Copyright 2021 Google, LLC. +# +# 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. + +import tempfile + +from cryptography import x509 +from cryptography.hazmat import backends +import pytest + +import verify_attestation_chains + +# The following keys and CSRs are needed to generate the test root certificates +# and certificate chains: +# 1. Test manufacturer root key pair. +# - openssl genrsa -out mfr.key +# 2. Test owner root key pair. +# - openssl genrsa -out owner.key +# 3. Test card key pair. +# - openssl genrsa -out card.key +# 4. Test partition key pair. +# - openssl genrsa -out partition.key +# 5. Test card CSR. +# - openssl req -new -key card.key -out card.csr +# 6. Test partition CSR. +# - openssl req -new -key partition.key -out partition.csr + +# The manufacturer root certificate can be generated with the manufacturer root +# key: +# - openssl req -x509 -key mfr.key -days 3650 -out mfr.pem +TEST_MANUFACTURER_ROOT = b"""-----BEGIN CERTIFICATE----- +MIIDujCCAqKgAwIBAgIJAMs+bXbmbsuPMA0GCSqGSIb3DQEBCwUAMHIxCzAJBgNV +BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX +aWRnaXRzIFB0eSBMdGQxKzApBgNVBAMMIlRlc3QgTWFudWZhY3R1cmVyIFJvb3Qg +Q2VydGlmaWNhdGUwHhcNMjAwNDA4MTMzNDI1WhcNMzAwNDA2MTMzNDI1WjByMQsw +CQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJu +ZXQgV2lkZ2l0cyBQdHkgTHRkMSswKQYDVQQDDCJUZXN0IE1hbnVmYWN0dXJlciBS +b290IENlcnRpZmljYXRlMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA +242hKtNxBY2TLzyjIzFJtCf44WKha2A3KcfZ2Ul7Q/f6gAlLOK5/GvIsdB8MK/Y0 +JgJBYUfPIZ8h0gLJVLhopopc4oOTRexCNCca97klSQCTZT4+wGqf/uIEF3PoL2Bb +uLhCQgxu+pPhfweBtEuqVcA33DYNN77J0f5KLKTHpOFEh1S1Q6ee/oRapj6J0hw6 +a/7FW1R7329V5Nr9qRIzhnlpy2lBFfCV95yukAf9pUp1jCVkesugrkFY3U8np4Kn +KhO4x1jHTsTmfq/oCUzj/hiUtD8vlg//0ZL0SMFDCANM+shi/AbyWU1BCESLrKTa +kvI+atplTmLk8o6lOb+hMwIDAQABo1MwUTAdBgNVHQ4EFgQUlDYZuNfW4l4XDGiA +yvJjmAiTtR8wHwYDVR0jBBgwFoAUlDYZuNfW4l4XDGiAyvJjmAiTtR8wDwYDVR0T +AQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEADyDx4HpwOpDNnG+Mf4DiSFAk +ujYaWsQGB8hUXKuJLsLLtcPNTvwSa/umu/IhBVYop1GpTadAG5yjYULwPnM4GIt3 +POffWAptw/a0XtFRxCXtvGlb+KvwQfYN8kq3weHcSvxTkrzgeWxs0LIQrZoaBPoo +MTJ88/s/p0d9Cf//5ukrW3LjF8OD8hd6HLpEie2qKc0wb6NXAuNgZ9m62kHSjXRS +Bd7Bwm5ZX3cOSz9SSseJKxEvD3lYUIF9w7gOeuifEpq2cfdT/VoiSL4GdN9wQ84R +0lM4loNrim85zL8YJdGAMlAQ5gbo9/Y8khSmoUOHHoV6P4UybOj+HEhDObhpQw== +-----END CERTIFICATE-----""" + +TEST_MANUFACTURER_SUBJECT_BYTES = ( + b'0r1\x0b0\t\x06\x03U\x04\x06\x13\x02AU1\x130\x11\x06\x03U\x04\x08\x0c\n' + b'Some-State1!0\x1f\x06\x03U\x04\n\x0c\x18Internet Widgits Pty Ltd1+0)\x06' + b'\x03U\x04\x03\x0c"Test Manufacturer Root Certificate') + +# The manufacturer certificate chain can be generated using the manufacturer +# root and card certificates, the manufacturer and card keys, and the card and +# partition CSRs: +# 1. Sign the card CSR with the manufacturer key and root certificate to create +# the manufacturer card certificate: +# - openssl x509 -req -in card.csr -CA mfr.pem -CAkey mfr.key -CAcreateserial -out mfr_card.pem -days 365 +# 2. Sign the partition CSR with the card key and manufacturer card certificate +# to create the manufacturer partition certificate: +# - openssl x509 -req -in partition.csr -CA mfr_card.pem -CAkey card.key -CAcreateserial -out mfr_partition.pem -days 365 +# 3. Create the manufacturer certificate chain using the manufacturer card and +# partition certificates: +# - cat mfr_partition.pem mfr_card.pem > mfr_chain.pem +TEST_MANUFACTURER_CHAIN = b"""-----BEGIN CERTIFICATE----- +MIIDSzCCAjMCCQDectxvPIHUkzANBgkqhkiG9w0BAQsFADBlMQswCQYDVQQGEwJB +VTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0 +cyBQdHkgTHRkMR4wHAYDVQQDDBVUZXN0IENhcmQgQ2VydGlmaWNhdGUwHhcNMjAw +NDA4MTQ1NDAzWhcNMjEwNDA4MTQ1NDAzWjBqMQswCQYDVQQGEwJBVTETMBEGA1UE +CAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRk +MSMwIQYDVQQDDBpUZXN0IFBhcnRpdGlvbiBDZXJ0aWZpY2F0ZTCCASIwDQYJKoZI +hvcNAQEBBQADggEPADCCAQoCggEBAOKNNkMQXNHO9DnYcD+U8Ll/v9Z4v7oVJ2xV +YlDMMj2IJzhfZI77miii/ll3UZj3EDGC4y4pdS0L81988WWaQ4yVEZtgV5+WHLGr +Bb08Ex5qKRJ5ag2dI/Sz6+M9+5pI1wQ2TscqpFTIjYmBOB91CK96JJOKKtuPcDC1 +31guMzTBpm3WiYyJBhR4Xj1McOwFLGBoPuZl9N8CzbqofVG1aTZi/C+AedU4YMjM +lKnB/Qxv94w6tsNPgbkjUGl3ZqmyUEKOG7zlIatnuXs70QEuv+KIouuFOTGiQppE +QaTNZ7UO0nhEG3e+cXyUzHxzlf8RTJpmhwqEHGnjF6YTsjVipGkCAwEAATANBgkq +hkiG9w0BAQsFAAOCAQEAD0rrWYZ+++ib6vvYi37j7hbwTuCRi1CSxXsrgiBFM1YK +cGzUnmqDXvJiBHX/qDIlkPxJy4AcfJ29r2dQ6kq1nwyaCAjqbGiFNR+VjNo4oAih +/xi1O1tIIZ4j979NAZmozsOXScYV1jVM/chM5QibDvdMp71YN8HwdMfGhssQe4sf +Kmu1IXq8XY/b0f/k3q5URgM+ur0qBJbqumY6fYgAYrfhSv7v4YlH2yqPVMWUOpHt +xFUKVbiXLux9xCsZ948b+lZLlETudUES5MpjHarlrr/CWxibjk6RJomN3eHHauZs +2ccag9KEQnjsBP2N2wqJeHU902attwvOoWQokUp9/Q== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDUzCCAjsCCQDNU9BSQM85jTANBgkqhkiG9w0BAQsFADByMQswCQYDVQQGEwJB +VTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0 +cyBQdHkgTHRkMSswKQYDVQQDDCJUZXN0IE1hbnVmYWN0dXJlciBSb290IENlcnRp +ZmljYXRlMB4XDTIwMDQwODE0NTQwNloXDTIxMDQwODE0NTQwNlowZTELMAkGA1UE +BhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0IFdp +ZGdpdHMgUHR5IEx0ZDEeMBwGA1UEAwwVVGVzdCBDYXJkIENlcnRpZmljYXRlMIIB +IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAmVDLbIEpoVx9IzEalubKQuer +1iOI3c59gQDa9V6+iFBjmeOeE2vI97pojTAvWMWkRRKARklY3BruVKR5698yTLzb +cPwg3vqPvGNQFztJzaYAwRoerdT289upoEADdjQmA2Y7PF3zH88nLh74B9M5O8/t +jCfOWehl/ctUhTnIRCwEs7ZLMc3HHhG+puymhruD+hLNcgWfX2aizDEW8wpNZ6dd +JhGyA/OPXgFOhpqOZd/BFM/9w8rSBHfijitdNRK5UQj6TtRBykBj9ZvBzapRbLS/ +rrqnSoXFo6dlZaxpJKXT/bFvx1ImZSizJln2klYcKv30g4lg+U4PaHvxNOFdrQID +AQABMA0GCSqGSIb3DQEBCwUAA4IBAQCtCrCZFLDYjEcKoMwbHa7XyELcQ79qM+YV +i2UBYZqvoq9ty0cLa1O1pvF35qbG1Z8B7dZ3rKwiXsBnFk87rMaweWvQWZkZEs3T +u4hBRdSrDCb2SEIEOusI49fZVhbZbgqnNX1AkFe9lqNVu82pYKpNSkP13cATVghB +mrDi6mxjdeiTHiek+ND05YEdGi38ja5T3/0PJjyEj35WXT+7CP95MArfNc3rhy6J +wkovm2tDYaojIJJtgFcBP3yhzsJOyHCkEzMqcOSjoT9pDv5qvrHKDMTZRKjcOgKP +YlIjHK237cZfoEh1PO2OI14sM2iD3ZpD5idGZI/GHF6GUWZ2AJqM +-----END CERTIFICATE-----""" + +# The owner root certificate can be generated with the owner root key: +# - openssl req -x509 -key owner.key -days 3650 -out owner.pem +TEST_OWNER_ROOT = b"""-----BEGIN CERTIFICATE----- +MIIDrDCCApSgAwIBAgIJAJdbRMhyDhf+MA0GCSqGSIb3DQEBCwUAMGsxCzAJBgNV +BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX +aWRnaXRzIFB0eSBMdGQxJDAiBgNVBAMMG1Rlc3QgT3duZXIgUm9vdCBDZXJ0aWZp +Y2F0ZTAeFw0yMDA0MDgxMzM3MDVaFw0zMDA0MDYxMzM3MDVaMGsxCzAJBgNVBAYT +AkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBXaWRn +aXRzIFB0eSBMdGQxJDAiBgNVBAMMG1Rlc3QgT3duZXIgUm9vdCBDZXJ0aWZpY2F0 +ZTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANwhPaA1nzlVrl1sFThl +GmwNSVczMmIVXOUyklTI2HIW7iHXWqqyusksQZJBvWpYLom0CzEv42wYWLtx5U9S +KE8P++DLCzspkV+KW11Gyyq5xsVxlrrcQZ6/SXDS8092IIZc/qht9Sgwv/u03tQA +JdwOgisnKRX2wtQfSi8lT+kNiT8IG6nbc1oRGcRa0cNY9uKaElF/EHxj33quZnQ0 +tvxH7NhjxZ+GSiMbLChp3DZGnq9lcTurBFGPUe31riP5uThTiKA5DZDJadFSs8Q1 +O0W0XPyWysm5y/7pAuz4yHZPdVzj6kssklHOE9+Yk3D8Q39n0utQJ84m+IrMrj8r +qSsCAwEAAaNTMFEwHQYDVR0OBBYEFCK8CyqtlBC06Hd9x680rN3nRJeZMB8GA1Ud +IwQYMBaAFCK8CyqtlBC06Hd9x680rN3nRJeZMA8GA1UdEwEB/wQFMAMBAf8wDQYJ +KoZIhvcNAQELBQADggEBAHXopvAk9qAqsW6tK9YmRy+EXCqxoOuKdXlU75G1GVnX +Obk/1DCbT2/ioXmSeA15p7fFdf5JG4J7ejCfJG8uXrKb0JW0RWRGXmGnO967FejD +STV8tp/uAYduPVcR9EqVDfOKU2jf0MoZnP95/dlBxZ+yTMnuusBu8z7ERPsQWve8 +yitpRkFz9nrFytZRJVJxl+bm0Llz2eqINYR3Oia7v0xtS1XaJUGX5mG2gpMlIfpu +1ByJP8g11f9HW84eeZ9ceKU848uJtj+DTDnx4Ck1x6huMvZkxOAVTNWmT1+osDv7 +vsVkjBnGwXfcAv6jFQiErcdpZ1MVdLxsAFHrAvYH67E= +-----END CERTIFICATE-----""" + +# The owner card certificate chain can be generated using the owner +# root certificate, the owner key, and the card CSR. +# 1. Sign the card CSR with the owner root certificate to create the +# owner card certificate: +# - openssl x509 -req -in card.csr -CA owner.pem -CAkey owner.key -CAcreateserial -out owner_card_chain.pem -days 365 +TEST_OWNER_CARD_CHAIN = b"""-----BEGIN CERTIFICATE----- +MIIDTDCCAjQCCQDp+9ouYgrR0DANBgkqhkiG9w0BAQsFADBrMQswCQYDVQQGEwJB +VTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0 +cyBQdHkgTHRkMSQwIgYDVQQDDBtUZXN0IE93bmVyIFJvb3QgQ2VydGlmaWNhdGUw +HhcNMjAwNDA4MTYyMTEyWhcNMjEwNDA4MTYyMTEyWjBlMQswCQYDVQQGEwJBVTET +MBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQ +dHkgTHRkMR4wHAYDVQQDDBVUZXN0IENhcmQgQ2VydGlmaWNhdGUwggEiMA0GCSqG +SIb3DQEBAQUAA4IBDwAwggEKAoIBAQCZUMtsgSmhXH0jMRqW5spC56vWI4jdzn2B +ANr1Xr6IUGOZ454Ta8j3umiNMC9YxaRFEoBGSVjcGu5UpHnr3zJMvNtw/CDe+o+8 +Y1AXO0nNpgDBGh6t1Pbz26mgQAN2NCYDZjs8XfMfzycuHvgH0zk7z+2MJ85Z6GX9 +y1SFOchELASztksxzcceEb6m7KaGu4P6Es1yBZ9fZqLMMRbzCk1np10mEbID849e +AU6Gmo5l38EUz/3DytIEd+KOK101ErlRCPpO1EHKQGP1m8HNqlFstL+uuqdKhcWj +p2VlrGkkpdP9sW/HUiZlKLMmWfaSVhwq/fSDiWD5Tg9oe/E04V2tAgMBAAEwDQYJ +KoZIhvcNAQELBQADggEBAM3hz+TfQNaeuBgPyqBedN6QkhSiTdzpNG7Eyfw3Sx8n +OSuZxcsZgNRo+WNJt4zi9cMaOwgPcuoGCW7Iw2StEtBqgujlExrfUHzu17yoBHxQ +DTvi7QRHb6W2amsSKcuoFkI1txVmVWQA2HkSQVqIzZZoI3qVu2cQMyVHG7MKPHFU +5Mzw0H37gfttXYnUDZM84ETpGuf7EXA7ROdgwDvDD8CqOMDBKpKqau9QVh4aBZW4 +koGMoga+RwjNt4FVCW4F4qn43fteDSmxdUuxqCn6V7CpRlHIc8J2q9nzsne/NCA0 +2W+pXJD8hjvb9YQuXyV1QOaV6dcDLDcKG6NCdtxisxM= +-----END CERTIFICATE-----""" + +# The owner partition certificate chain can be generated using the owner +# root certificate, the owner key, and the partition CSR. +# 1. Sign the partition CSR with the owner key and root certificate to create +# the owner partition certificate: +# - openssl x509 -req -in partition.csr -CA owner.pem -CAkey owner.key -CAcreateserial -out owner_partition_chain.pem -days 365 +TEST_OWNER_PARTITION_CHAIN = b"""-----BEGIN CERTIFICATE----- +MIIDUTCCAjkCCQDp+9ouYgrR0TANBgkqhkiG9w0BAQsFADBrMQswCQYDVQQGEwJB +VTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0 +cyBQdHkgTHRkMSQwIgYDVQQDDBtUZXN0IE93bmVyIFJvb3QgQ2VydGlmaWNhdGUw +HhcNMjAwNDA4MTYyNDQ0WhcNMjEwNDA4MTYyNDQ0WjBqMQswCQYDVQQGEwJBVTET +MBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQ +dHkgTHRkMSMwIQYDVQQDDBpUZXN0IFBhcnRpdGlvbiBDZXJ0aWZpY2F0ZTCCASIw +DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOKNNkMQXNHO9DnYcD+U8Ll/v9Z4 +v7oVJ2xVYlDMMj2IJzhfZI77miii/ll3UZj3EDGC4y4pdS0L81988WWaQ4yVEZtg +V5+WHLGrBb08Ex5qKRJ5ag2dI/Sz6+M9+5pI1wQ2TscqpFTIjYmBOB91CK96JJOK +KtuPcDC131guMzTBpm3WiYyJBhR4Xj1McOwFLGBoPuZl9N8CzbqofVG1aTZi/C+A +edU4YMjMlKnB/Qxv94w6tsNPgbkjUGl3ZqmyUEKOG7zlIatnuXs70QEuv+KIouuF +OTGiQppEQaTNZ7UO0nhEG3e+cXyUzHxzlf8RTJpmhwqEHGnjF6YTsjVipGkCAwEA +ATANBgkqhkiG9w0BAQsFAAOCAQEARAcOL0Y1XBYqIT/ySRFmN6f+cLUO3sPGllt8 +BLYhHsnyJjzV4By00GLcLp5cd14sIfkyVPPFA7kCwOGbL52avRo6+bPB2Bdg6MRt +wbXG3pa6DQXQ2vsZ0I1bXUdCS05YbfvfTrF7LLNCPYbul4Wph5zT360JmBVLKPaX +smw8fAPhdDwHix1ee2bopldrPrS0L55t3HLOBEF4XT9TCXFS23yBpujGsLEwHgaJ +x1un6v2v+bEPr8tpPv33WlSC9Fwlit0Xwf6sp/YuX11t223D7QmGN8rRyqv9Fm5l +RZh2a6rJjlnErdcLx/+5ojsCjbElfluJvsToc+iCcwut6FKcPg== +-----END CERTIFICATE-----""" + +# Test attestations can be generated with the following steps: +# 1. Create a file containing the test attestation statement. +# - echo "content" > attestation.dat +# 2. Sign the file with one the key pairs used to create the test certificates. +# - openssl dgst -sha256 -sign test1.key -out signature.dat attestation.dat +# 3. Concatenate the signature to the statement to create an attestation. +# - cat signature.dat >> attestation.dat +# 4. Compress the test attestation. +# - gzip attestation.dat +# For instructions on downloading attestations from Cloud HSM, refer to: +# https://cloud.google.com/kms/docs/attest-key#downloading_the_attestation_statement +TEST_ATTESTATION = ( + b'\x1f\x8b\x08\x08\xb9\xe37`\x00\x03attestation.dat\x00\x01\x08\x01\xf7' + b'\xfecontent\n>\xede\xeb\xd3\x9d\x9e\x8e*\xa2\xf4\x04i\xec\x10lI\xa1\xc5' + b'\xd6\x0c\xfd\x1a^T\x1f&>f\xb2\xae}UD\xf1\xbaW\xcf\xec\xc5\x10\x86s\x92A' + b'\xa1E\xc3\xf9=8/\xe5\xf4y\xf1\xa4H\xb1"\x08\xe7\x1a\xd1[\xc2\xb1CCO\x82' + b'\xe7-\xbd-=u\x15\x9a=\x1b\x98\xec\xb6\x1d\xc0\xd2\xf7\xcb\x99g\xdd\xed' + b'\xba\xcb\x9bK\xc7\xd8[\xd9\xf8?K\x0f\xd5\xaaO\xd4R0\xf6>\x18\xb2F\x13 ' + b'\xedi\xedV\xdc\x1bR-j\x85\xe3\xd5\x92\x9a\x9dU4\xc8\x13\xa10\xbbg\xee' + b'\xa3R\x8a\xcf\x88\x91p\xde\x9c\xe1\x82\xcd\x8a>\xa0\x1c\xf2\xb5\xb2\xb2' + b'\x91.Z\t\xc8a{\x896\x03+|\x8b\xa0\xb7\x16\xe8E\xca\x0c+\x17)\xd4\xd2s' + b'\x96\xfen\xa9\xf7\xa2\x1eW\xd3\xbd\n\x16\x12\xea8\xaa\x85xJ\x13d\xe5\x85' + b'\xdd\xe6\xca\x82;qw\xbe\x8fa\xb7\xeb\x06L\xd2\\pb\x0b\xbf\x9bj\xcc\xb0' + b'\x92\xf2\x81v\x1c\xa0\xa3?{~\x8e\xc1O\x1a\xc9\x7f\x9cCH\x1d\xef\x85\xe1' + b'\xeb\xa5\x08\x01\x00\x00') + + +def test_verify_certificate(): + signing_cert = x509.load_pem_x509_certificate(TEST_OWNER_ROOT, + backends.default_backend()) + issued_cert = x509.load_pem_x509_certificate(TEST_OWNER_PARTITION_CHAIN, + backends.default_backend()) + assert verify_attestation_chains.verify_certificate(signing_cert, + issued_cert) + + +def test_verify_certificate_fail(): + signing_cert = x509.load_pem_x509_certificate(TEST_OWNER_ROOT, + backends.default_backend()) + issued_cert = x509.load_pem_x509_certificate(TEST_MANUFACTURER_ROOT, + backends.default_backend()) + assert not verify_attestation_chains.verify_certificate(signing_cert, + issued_cert) + + +def get_test_manufacturer_root(): + return x509.load_pem_x509_certificate(TEST_MANUFACTURER_ROOT, + backends.default_backend()) + + +def get_test_owner_root(): + return x509.load_pem_x509_certificate(TEST_OWNER_ROOT, + backends.default_backend()) + + +def make_temporary_file(contents): + """Creates a NamedTemporaryFile with contents and returns its file name. + + Args: + contents: The contents to write to the temporary file. + + Returns: + The name of the temporary file. + """ + temp_file = tempfile.NamedTemporaryFile(delete=False) + temp_file.write(contents) + temp_file.close() + return temp_file.name + + +@pytest.fixture(scope='function') +def test_data(): + mfr_root = make_temporary_file(TEST_MANUFACTURER_ROOT) + mfr_chain = make_temporary_file(TEST_MANUFACTURER_CHAIN) + owner_root = make_temporary_file(TEST_OWNER_ROOT) + owner_card_chain = make_temporary_file(TEST_OWNER_CARD_CHAIN) + owner_partition_chain = make_temporary_file(TEST_OWNER_PARTITION_CHAIN) + cert_chains = make_temporary_file(b'\n'.join([ + TEST_MANUFACTURER_CHAIN, + TEST_OWNER_CARD_CHAIN, + TEST_OWNER_PARTITION_CHAIN + ])) + attestation = make_temporary_file(TEST_ATTESTATION) + + param = { + 'mfr_root': mfr_root, + 'mfr_chain': mfr_chain, + 'owner_root': owner_root, + 'owner_card_chain': owner_card_chain, + 'owner_partition_chain': owner_partition_chain, + 'cert_chains': cert_chains, + 'attestation': attestation + } + yield param + + +def test_verify(monkeypatch, test_data): + monkeypatch.setattr(verify_attestation_chains, + 'MANUFACTURER_CERT_SUBJECT_BYTES', + TEST_MANUFACTURER_SUBJECT_BYTES) + monkeypatch.setattr(verify_attestation_chains, + 'get_manufacturer_root_certificate', + get_test_manufacturer_root) + monkeypatch.setattr(verify_attestation_chains, + 'get_owner_root_certificate', + get_test_owner_root) + assert verify_attestation_chains.verify(test_data['cert_chains'], + test_data['attestation']) + + +def test_verify_invalid_mfr_root_fails(monkeypatch, test_data): + monkeypatch.setattr(verify_attestation_chains, + 'MANUFACTURER_CERT_SUBJECT_BYTES', + b'invalid') + monkeypatch.setattr(verify_attestation_chains, + 'get_manufacturer_root_certificate', + get_test_owner_root) + monkeypatch.setattr(verify_attestation_chains, + 'get_owner_root_certificate', + get_test_owner_root) + + assert not verify_attestation_chains.verify(test_data['cert_chains'], + test_data['attestation']) From 2597804b0c6c2f66f0b2afed1deb977dad71973f Mon Sep 17 00:00:00 2001 From: WhiteSource Renovate Date: Fri, 14 May 2021 03:05:09 +0200 Subject: [PATCH 078/136] chore(deps): update dependency pytest to v6 (#110) --- kms/attestations/requirements-test.txt | 2 +- kms/snippets/requirements-test.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/kms/attestations/requirements-test.txt b/kms/attestations/requirements-test.txt index d3e30fa6c737..95ea1e6a02b0 100644 --- a/kms/attestations/requirements-test.txt +++ b/kms/attestations/requirements-test.txt @@ -1 +1 @@ -pytest==5.4.1 +pytest==6.2.4 diff --git a/kms/snippets/requirements-test.txt b/kms/snippets/requirements-test.txt index d3e30fa6c737..95ea1e6a02b0 100644 --- a/kms/snippets/requirements-test.txt +++ b/kms/snippets/requirements-test.txt @@ -1 +1 @@ -pytest==5.4.1 +pytest==6.2.4 From bcb80c627f118f44b4c4b7a74567b0171553b955 Mon Sep 17 00:00:00 2001 From: WhiteSource Renovate Date: Mon, 14 Jun 2021 23:52:58 +0200 Subject: [PATCH 079/136] chore(deps): update dependency google-cloud-kms to v2.3.0 (#121) --- kms/snippets/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kms/snippets/requirements.txt b/kms/snippets/requirements.txt index 2d676ec353a4..69c18f891216 100644 --- a/kms/snippets/requirements.txt +++ b/kms/snippets/requirements.txt @@ -1,3 +1,3 @@ -google-cloud-kms==2.2.0 +google-cloud-kms==2.3.0 cryptography==3.4.7 crcmod==1.7 From e695b2264e06ee1e7bcddb8d505fdf6c70f7f0eb Mon Sep 17 00:00:00 2001 From: Benson Kuang <3453547+bkuang@users.noreply.github.com> Date: Mon, 12 Jul 2021 16:04:12 -0400 Subject: [PATCH 080/136] docs: Include verify_attestation_chains.py help text to attestations README (#134) --- kms/attestations/README.rst.in | 3 +++ 1 file changed, 3 insertions(+) diff --git a/kms/attestations/README.rst.in b/kms/attestations/README.rst.in index 3e188a17a5e0..1c536fbf1546 100644 --- a/kms/attestations/README.rst.in +++ b/kms/attestations/README.rst.in @@ -12,6 +12,9 @@ setup: - install_deps samples: +- name: Verify attestations and certificate chains for keys generated by Cloud HSM + file: verify_attestation_chains.py + show_help: True - name: Verify attestations for keys generated by Cloud HSM file: verify_attestation.py show_help: True From 079922cfeb9b12770cda5aa2cb1e582241023034 Mon Sep 17 00:00:00 2001 From: WhiteSource Renovate Date: Tue, 13 Jul 2021 15:58:22 +0200 Subject: [PATCH 081/136] chore(deps): update dependency google-cloud-kms to v2.4.0 (#135) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [![WhiteSource Renovate](https://app.renovatebot.com/images/banner.svg)](https://renovatebot.com) This PR contains the following updates: | Package | Change | Age | Adoption | Passing | Confidence | |---|---|---|---|---|---| | [google-cloud-kms](https://togithub.com/googleapis/python-kms) | `==2.3.0` -> `==2.4.0` | [![age](https://badges.renovateapi.com/packages/pypi/google-cloud-kms/2.4.0/age-slim)](https://docs.renovatebot.com/merge-confidence/) | [![adoption](https://badges.renovateapi.com/packages/pypi/google-cloud-kms/2.4.0/adoption-slim)](https://docs.renovatebot.com/merge-confidence/) | [![passing](https://badges.renovateapi.com/packages/pypi/google-cloud-kms/2.4.0/compatibility-slim/2.3.0)](https://docs.renovatebot.com/merge-confidence/) | [![confidence](https://badges.renovateapi.com/packages/pypi/google-cloud-kms/2.4.0/confidence-slim/2.3.0)](https://docs.renovatebot.com/merge-confidence/) | --- ### Release Notes
googleapis/python-kms ### [`v2.4.0`](https://togithub.com/googleapis/python-kms/blob/master/CHANGELOG.md#​240-httpswwwgithubcomgoogleapispython-kmscomparev230v240-2021-07-12) [Compare Source](https://togithub.com/googleapis/python-kms/compare/v2.3.0...v2.4.0) ##### Features - add always_use_jwt_access ([#​129](https://www.github.com/googleapis/python-kms/issues/129)) ([cfa0802](https://www.github.com/googleapis/python-kms/commit/cfa08022db3e096e2414418b63482606af8d46cb)) ##### Bug Fixes - disable always_use_jwt_access ([#​133](https://www.github.com/googleapis/python-kms/issues/133)) ([8007b81](https://www.github.com/googleapis/python-kms/commit/8007b810f11ebf49cd24edd77867abac174841e9)) ##### Documentation - Include verify_attestation_chains.py help text to attestations README ([#​134](https://www.github.com/googleapis/python-kms/issues/134)) ([2f2bb49](https://www.github.com/googleapis/python-kms/commit/2f2bb49adca244031d584ffbb27e32585e64ed42)) - omit mention of Python 2.7 in 'CONTRIBUTING.rst' ([#​1127](https://www.github.com/googleapis/python-kms/issues/1127)) ([#​124](https://www.github.com/googleapis/python-kms/issues/124)) ([5c3e273](https://www.github.com/googleapis/python-kms/commit/5c3e27391c4771b4a03c87e21a5260ed8d61b9c4)), closes [#​1126](https://www.github.com/googleapis/python-kms/issues/1126)
--- ### Configuration 📅 **Schedule**: At any time (no schedule defined). 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. ♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox. 🔕 **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] If you want to rebase/retry this PR, check this box. --- This PR has been generated by [WhiteSource Renovate](https://renovate.whitesourcesoftware.com). View repository job log [here](https://app.renovatebot.com/dashboard#github/googleapis/python-kms). --- kms/snippets/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kms/snippets/requirements.txt b/kms/snippets/requirements.txt index 69c18f891216..de2ff5f338ad 100644 --- a/kms/snippets/requirements.txt +++ b/kms/snippets/requirements.txt @@ -1,3 +1,3 @@ -google-cloud-kms==2.3.0 +google-cloud-kms==2.4.0 cryptography==3.4.7 crcmod==1.7 From b88b9ba149ebbc31a26949385c24dff25d698083 Mon Sep 17 00:00:00 2001 From: WhiteSource Renovate Date: Thu, 22 Jul 2021 16:00:36 +0200 Subject: [PATCH 082/136] chore(deps): update dependency google-cloud-kms to v2.4.1 (#146) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [![WhiteSource Renovate](https://app.renovatebot.com/images/banner.svg)](https://renovatebot.com) This PR contains the following updates: | Package | Change | Age | Adoption | Passing | Confidence | |---|---|---|---|---|---| | [google-cloud-kms](https://togithub.com/googleapis/python-kms) | `==2.4.0` -> `==2.4.1` | [![age](https://badges.renovateapi.com/packages/pypi/google-cloud-kms/2.4.1/age-slim)](https://docs.renovatebot.com/merge-confidence/) | [![adoption](https://badges.renovateapi.com/packages/pypi/google-cloud-kms/2.4.1/adoption-slim)](https://docs.renovatebot.com/merge-confidence/) | [![passing](https://badges.renovateapi.com/packages/pypi/google-cloud-kms/2.4.1/compatibility-slim/2.4.0)](https://docs.renovatebot.com/merge-confidence/) | [![confidence](https://badges.renovateapi.com/packages/pypi/google-cloud-kms/2.4.1/confidence-slim/2.4.0)](https://docs.renovatebot.com/merge-confidence/) | --- ### Release Notes
googleapis/python-kms ### [`v2.4.1`](https://togithub.com/googleapis/python-kms/blob/master/CHANGELOG.md#​241-httpswwwgithubcomgoogleapispython-kmscomparev240v241-2021-07-20) [Compare Source](https://togithub.com/googleapis/python-kms/compare/v2.4.0...v2.4.1)
--- ### Configuration 📅 **Schedule**: At any time (no schedule defined). 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. ♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox. 🔕 **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] If you want to rebase/retry this PR, check this box. --- This PR has been generated by [WhiteSource Renovate](https://renovate.whitesourcesoftware.com). View repository job log [here](https://app.renovatebot.com/dashboard#github/googleapis/python-kms). --- kms/snippets/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kms/snippets/requirements.txt b/kms/snippets/requirements.txt index de2ff5f338ad..1b120859b8de 100644 --- a/kms/snippets/requirements.txt +++ b/kms/snippets/requirements.txt @@ -1,3 +1,3 @@ -google-cloud-kms==2.4.0 +google-cloud-kms==2.4.1 cryptography==3.4.7 crcmod==1.7 From bf615fd419921237a8d99268301d4b536e11e7ac Mon Sep 17 00:00:00 2001 From: WhiteSource Renovate Date: Wed, 28 Jul 2021 16:53:33 +0200 Subject: [PATCH 083/136] chore(deps): update dependency google-cloud-kms to v2.4.2 (#153) --- kms/snippets/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kms/snippets/requirements.txt b/kms/snippets/requirements.txt index 1b120859b8de..4e0c8325051c 100644 --- a/kms/snippets/requirements.txt +++ b/kms/snippets/requirements.txt @@ -1,3 +1,3 @@ -google-cloud-kms==2.4.1 +google-cloud-kms==2.4.2 cryptography==3.4.7 crcmod==1.7 From 8911a48b551a6420ee96f05649df29f652c5c2f9 Mon Sep 17 00:00:00 2001 From: Benson Kuang <3453547+bkuang@users.noreply.github.com> Date: Thu, 29 Jul 2021 10:30:29 -0400 Subject: [PATCH 084/136] docs: update README for attestation verification scripts (#151) --- kms/attestations/README.rst | 54 +++++++++++++------ kms/attestations/README.rst.in | 3 +- kms/attestations/verify_attestation_chains.py | 3 +- 3 files changed, 41 insertions(+), 19 deletions(-) diff --git a/kms/attestations/README.rst b/kms/attestations/README.rst index 0c56a914359f..4a9ff7f74d72 100644 --- a/kms/attestations/README.rst +++ b/kms/attestations/README.rst @@ -4,7 +4,7 @@ Google Cloud Key Management Service Python Samples =============================================================================== .. image:: https://gstatic.com/cloudssh/images/open-btn.png - :target: https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/GoogleCloudPlatform/python-docs-samples&page=editor&open_in_editor=kms/attestations/README.rst + :target: https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/python-kms&page=editor&open_in_editor=samples/attestations/README.rst This directory contains samples for Google Cloud Key Management Service. The `Cloud Key Management Service`_ allows you to create, import, and manage cryptographic keys and perform cryptographic operations in a single centralized cloud service. @@ -14,6 +14,10 @@ This directory contains samples for Google Cloud Key Management Service. The `Cl .. _Google Cloud Key Management Service: https://cloud.google.com/kms/docs/ + + + + Setup ------------------------------------------------------------------------------- @@ -32,36 +36,57 @@ Install Dependencies .. _Python Development Environment Setup Guide: https://cloud.google.com/python/setup -#. Create a virtualenv. Samples are compatible with Python 3.6+. +#. Create a virtualenv. Samples are compatible with Python 2.7 and 3.4+. .. code-block:: bash $ virtualenv env $ source env/bin/activate -#. Install the dependencies needed to run the samples. - - .. code-block:: bash - - $ pip install -r requirements.txt .. _pip: https://pip.pypa.io/ .. _virtualenv: https://virtualenv.pypa.io/ +Samples +------------------------------------------------------------------------------- +Verify attestations and certificate chains for keys generated by Cloud HSM ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +.. image:: https://gstatic.com/cloudssh/images/open-btn.png + :target: https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/python-kms&page=editor&open_in_editor=samples/attestations/verify_attestation_chains.py,samples/attestations/README.rst -Samples -------------------------------------------------------------------------------- + +To run this sample: + +.. code-block:: bash + + $ python verify_attestation_chains.py + + usage: verify_attestation_chains.py [-h] [--certificates CERTIFICATES] + [--attestation ATTESTATION] + + This application verifies HSM attestations using certificate chains + obtained from Cloud HSM and the HSM manufacturer. + + For more information, visit https://cloud.google.com/kms/docs/attest-key. + + optional arguments: + -h, --help show this help message and exit + --certificates CERTIFICATES + The certificate chains filename. + --attestation ATTESTATION + The attestation filename. + Verify attestations for keys generated by Cloud HSM +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ .. image:: https://gstatic.com/cloudssh/images/open-btn.png - :target: https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/GoogleCloudPlatform/python-docs-samples&page=editor&open_in_editor=kms/attestations/verify_attestation.py,kms/attestations/README.rst + :target: https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/GoogleCloudPlatform/python-docs-samples&page=editor&open_in_editor=samples/attestations/verify_attestation.py,samples/attestations/README.rst @@ -72,12 +97,11 @@ To run this sample: $ python verify_attestation.py - usage: verify_attestation.py [-h] attestation_file bundle_file This application verifies HSM attestations using certificate bundles obtained - from Cloud HSM. For more information, visit - https://cloud.google.com/kms/docs/attest-key. + from Cloud HSM. For more information, visit https://cloud.google.com/kms/docs + /attest-key. positional arguments: attestation_file Name of attestation file. @@ -90,8 +114,4 @@ To run this sample: - - - - .. _Google Cloud SDK: https://cloud.google.com/sdk/ diff --git a/kms/attestations/README.rst.in b/kms/attestations/README.rst.in index 1c536fbf1546..596ab5fe5b75 100644 --- a/kms/attestations/README.rst.in +++ b/kms/attestations/README.rst.in @@ -19,4 +19,5 @@ samples: file: verify_attestation.py show_help: True -folder: kms/attestations +folder: samples/attestations + diff --git a/kms/attestations/verify_attestation_chains.py b/kms/attestations/verify_attestation_chains.py index 30a5b9226afa..3fddd8600973 100644 --- a/kms/attestations/verify_attestation_chains.py +++ b/kms/attestations/verify_attestation_chains.py @@ -13,7 +13,8 @@ # 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. -"""This application verifies HSM certificate chains. +"""This application verifies HSM attestations using certificate chains +obtained from Cloud HSM and the HSM manufacturer. For more information, visit https://cloud.google.com/kms/docs/attest-key. """ From 4d72d4d1e5c4d836206fe48b14a9db058088762b Mon Sep 17 00:00:00 2001 From: WhiteSource Renovate Date: Thu, 29 Jul 2021 17:31:43 +0200 Subject: [PATCH 085/136] chore(deps): update dependency google-cloud-kms to v2.4.3 (#155) --- kms/snippets/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kms/snippets/requirements.txt b/kms/snippets/requirements.txt index 4e0c8325051c..4b56c32227e0 100644 --- a/kms/snippets/requirements.txt +++ b/kms/snippets/requirements.txt @@ -1,3 +1,3 @@ -google-cloud-kms==2.4.2 +google-cloud-kms==2.4.3 cryptography==3.4.7 crcmod==1.7 From af529ec69f2be5748d2181488ce98bc5783ca460 Mon Sep 17 00:00:00 2001 From: WhiteSource Renovate Date: Mon, 9 Aug 2021 19:53:01 +0200 Subject: [PATCH 086/136] chore(deps): update dependency google-cloud-kms to v2.5.0 (#159) --- kms/snippets/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kms/snippets/requirements.txt b/kms/snippets/requirements.txt index 4b56c32227e0..4b1e1e1fa615 100644 --- a/kms/snippets/requirements.txt +++ b/kms/snippets/requirements.txt @@ -1,3 +1,3 @@ -google-cloud-kms==2.4.3 +google-cloud-kms==2.5.0 cryptography==3.4.7 crcmod==1.7 From 8653eebfa56af52041d9f24f82b7a2b724ce863b Mon Sep 17 00:00:00 2001 From: Seth Vargo Date: Thu, 12 Aug 2021 16:04:16 -0400 Subject: [PATCH 087/136] feat(kms): add samples for new hmac and rng apis (#161) --- kms/snippets/create_key_asymmetric_decrypt.py | 8 ++- kms/snippets/create_key_asymmetric_sign.py | 8 ++- kms/snippets/create_key_hsm.py | 8 ++- kms/snippets/create_key_mac.py | 60 +++++++++++++++++++ kms/snippets/generate_random_bytes.py | 49 +++++++++++++++ kms/snippets/sign_mac.py | 53 ++++++++++++++++ kms/snippets/snippets_test.py | 54 +++++++++++++++++ kms/snippets/verify_mac.py | 51 ++++++++++++++++ 8 files changed, 288 insertions(+), 3 deletions(-) create mode 100644 kms/snippets/create_key_mac.py create mode 100644 kms/snippets/generate_random_bytes.py create mode 100644 kms/snippets/sign_mac.py create mode 100644 kms/snippets/verify_mac.py diff --git a/kms/snippets/create_key_asymmetric_decrypt.py b/kms/snippets/create_key_asymmetric_decrypt.py index 4865a266cf45..993d6840a2df 100644 --- a/kms/snippets/create_key_asymmetric_decrypt.py +++ b/kms/snippets/create_key_asymmetric_decrypt.py @@ -30,6 +30,8 @@ def create_key_asymmetric_decrypt(project_id, location_id, key_ring_id, id): # Import the client library. from google.cloud import kms + from google.protobuf import duration_pb2 + import datetime # Create the client. client = kms.KeyManagementServiceClient() @@ -44,7 +46,11 @@ def create_key_asymmetric_decrypt(project_id, location_id, key_ring_id, id): 'purpose': purpose, 'version_template': { 'algorithm': algorithm, - } + }, + + # Optional: customize how long key versions should be kept before + # destroying. + 'destroy_scheduled_duration': duration_pb2.Duration().FromTimedelta(datetime.timedelta(days=1)) } # Call the API. diff --git a/kms/snippets/create_key_asymmetric_sign.py b/kms/snippets/create_key_asymmetric_sign.py index 1b05799727b4..b3fbaa9e2fd2 100644 --- a/kms/snippets/create_key_asymmetric_sign.py +++ b/kms/snippets/create_key_asymmetric_sign.py @@ -30,6 +30,8 @@ def create_key_asymmetric_sign(project_id, location_id, key_ring_id, id): # Import the client library. from google.cloud import kms + from google.protobuf import duration_pb2 + import datetime # Create the client. client = kms.KeyManagementServiceClient() @@ -44,7 +46,11 @@ def create_key_asymmetric_sign(project_id, location_id, key_ring_id, id): 'purpose': purpose, 'version_template': { 'algorithm': algorithm, - } + }, + + # Optional: customize how long key versions should be kept before + # destroying. + 'destroy_scheduled_duration': duration_pb2.Duration().FromTimedelta(datetime.timedelta(days=1)) } # Call the API. diff --git a/kms/snippets/create_key_hsm.py b/kms/snippets/create_key_hsm.py index 34a9c8a2c509..a850391a3eb7 100644 --- a/kms/snippets/create_key_hsm.py +++ b/kms/snippets/create_key_hsm.py @@ -30,6 +30,8 @@ def create_key_hsm(project_id, location_id, key_ring_id, id): # Import the client library. from google.cloud import kms + from google.protobuf import duration_pb2 + import datetime # Create the client. client = kms.KeyManagementServiceClient() @@ -46,7 +48,11 @@ def create_key_hsm(project_id, location_id, key_ring_id, id): 'version_template': { 'algorithm': algorithm, 'protection_level': protection_level - } + }, + + # Optional: customize how long key versions should be kept before + # destroying. + 'destroy_scheduled_duration': duration_pb2.Duration().FromTimedelta(datetime.timedelta(days=1)) } # Call the API. diff --git a/kms/snippets/create_key_mac.py b/kms/snippets/create_key_mac.py new file mode 100644 index 000000000000..db8d086eded6 --- /dev/null +++ b/kms/snippets/create_key_mac.py @@ -0,0 +1,60 @@ +# Copyright 2021 Google LLC +# +# 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 + + +# [START kms_create_key_mac] +def create_key_mac(project_id, location_id, key_ring_id, id): + """ + Creates a new key in Cloud KMS for HMAC operations. + + Args: + project_id (string): Google Cloud project ID (e.g. 'my-project'). + location_id (string): Cloud KMS location (e.g. 'us-east1'). + key_ring_id (string): ID of the Cloud KMS key ring (e.g. 'my-key-ring'). + id (string): ID of the key to create (e.g. 'my-mac-key'). + + Returns: + CryptoKey: Cloud KMS key. + + """ + + # Import the client library. + from google.cloud import kms + from google.protobuf import duration_pb2 + import datetime + + # Create the client. + client = kms.KeyManagementServiceClient() + + # Build the parent key ring name. + key_ring_name = client.key_ring_path(project_id, location_id, key_ring_id) + + # Build the key. + purpose = kms.CryptoKey.CryptoKeyPurpose.MAC + algorithm = kms.CryptoKeyVersion.CryptoKeyVersionAlgorithm.HMAC_SHA256 + key = { + 'purpose': purpose, + 'version_template': { + 'algorithm': algorithm, + }, + + # Optional: customize how long key versions should be kept before + # destroying. + 'destroy_scheduled_duration': duration_pb2.Duration().FromTimedelta(datetime.timedelta(days=1)) + } + + # Call the API. + created_key = client.create_crypto_key(request={'parent': key_ring_name, 'crypto_key_id': id, 'crypto_key': key}) + print('Created mac key: {}'.format(created_key.name)) + return created_key +# [END kms_create_key_mac] diff --git a/kms/snippets/generate_random_bytes.py b/kms/snippets/generate_random_bytes.py new file mode 100644 index 000000000000..9b5438315cd6 --- /dev/null +++ b/kms/snippets/generate_random_bytes.py @@ -0,0 +1,49 @@ +# Copyright 2021 Google LLC +# +# 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 + + +# [START kms_generate_random_bytes] +def generate_random_bytes(project_id, location_id, num_bytes): + """ + Generate random bytes with entropy sourced from the given location. + + Args: + project_id (string): Google Cloud project ID (e.g. 'my-project'). + location_id (string): Cloud KMS location (e.g. 'us-east1'). + num_bytes (integer): number of bytes of random data. + + Returns: + bytes: Encrypted ciphertext. + + """ + + # Import the client library. + from google.cloud import kms + + # Import base64 for encoding the bytes for printing. + import base64 + + # Create the client. + client = kms.KeyManagementServiceClient() + + # Build the location name. + location_name = client.common_location_path(project_id, location_id) + + # Call the API. + protection_level = kms.ProtectionLevel.HSM + random_bytes_response = client.generate_random_bytes( + request={'location': location_name, 'length_bytes': num_bytes, 'protection_level': protection_level}) + + print('Random bytes: {}'.format(base64.b64encode(random_bytes_response.data))) + return random_bytes_response +# [END kms_generate_random_bytes] diff --git a/kms/snippets/sign_mac.py b/kms/snippets/sign_mac.py new file mode 100644 index 000000000000..fa054b42abe5 --- /dev/null +++ b/kms/snippets/sign_mac.py @@ -0,0 +1,53 @@ +# Copyright 2021 Google LLC +# +# 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 + + +# [START kms_sign_mac] +def sign_mac(project_id, location_id, key_ring_id, key_id, version_id, data): + """ + Sign a message using the public key part of an asymmetric key. + + Args: + project_id (string): Google Cloud project ID (e.g. 'my-project'). + location_id (string): Cloud KMS location (e.g. 'us-east1'). + key_ring_id (string): ID of the Cloud KMS key ring (e.g. 'my-key-ring'). + key_id (string): ID of the key to use (e.g. 'my-key'). + version_id (string): Version to use (e.g. '1'). + data (string): Data to sign. + + Returns: + MacSignResponse: Signature. + """ + + # Import the client library. + from google.cloud import kms + + # Import base64 for printing the ciphertext. + import base64 + + # Create the client. + client = kms.KeyManagementServiceClient() + + # Build the key version name. + key_version_name = client.crypto_key_version_path(project_id, location_id, key_ring_id, key_id, version_id) + + # Convert the message to bytes. + data_bytes = data.encode('utf-8') + + # Call the API + sign_response = client.mac_sign( + request={'name': key_version_name, 'data': data_bytes}) + + print('Signature: {}'.format(base64.b64encode(sign_response.mac))) + return sign_response +# [END kms_sign_mac] diff --git a/kms/snippets/snippets_test.py b/kms/snippets/snippets_test.py index 8efeb514d170..048f6f8f9cec 100644 --- a/kms/snippets/snippets_test.py +++ b/kms/snippets/snippets_test.py @@ -32,6 +32,7 @@ from create_key_for_import import create_key_for_import from create_key_hsm import create_key_hsm from create_key_labels import create_key_labels +from create_key_mac import create_key_mac from create_key_ring import create_key_ring from create_key_rotation_schedule import create_key_rotation_schedule from create_key_symmetric_encrypt_decrypt import create_key_symmetric_encrypt_decrypt @@ -43,6 +44,7 @@ from enable_key_version import enable_key_version from encrypt_asymmetric import encrypt_asymmetric from encrypt_symmetric import encrypt_symmetric +from generate_random_bytes import generate_random_bytes from get_key_labels import get_key_labels from get_key_version_attestation import get_key_version_attestation from get_public_key import get_public_key @@ -53,6 +55,7 @@ from quickstart import quickstart from restore_key_version import restore_key_version from sign_asymmetric import sign_asymmetric +from sign_mac import sign_mac from update_key_add_rotation import update_key_add_rotation from update_key_remove_labels import update_key_remove_labels from update_key_remove_rotation import update_key_remove_rotation @@ -60,6 +63,7 @@ from update_key_update_labels import update_key_update_labels from verify_asymmetric_ec import verify_asymmetric_ec from verify_asymmetric_rsa import verify_asymmetric_rsa +from verify_mac import verify_mac @pytest.fixture(scope="module") @@ -167,6 +171,22 @@ def hsm_key_id(client, project_id, location_id, key_ring_id): return key_id +@pytest.fixture(scope="module") +def hmac_key_id(client, project_id, location_id, key_ring_id): + key_ring_name = client.key_ring_path(project_id, location_id, key_ring_id) + key_id = '{}'.format(uuid.uuid4()) + key = client.create_crypto_key(request={'parent': key_ring_name, 'crypto_key_id': key_id, 'crypto_key': { + 'purpose': kms.CryptoKey.CryptoKeyPurpose.MAC, + 'version_template': { + 'algorithm': kms.CryptoKeyVersion.CryptoKeyVersionAlgorithm.HMAC_SHA256, + 'protection_level': kms.ProtectionLevel.HSM + }, + 'labels': {'foo': 'bar', 'zip': 'zap'} + }}) + wait_for_ready(client, '{}/cryptoKeyVersions/1'.format(key.name)) + return key_id + + @pytest.fixture(scope="module") def symmetric_key_id(client, project_id, location_id, key_ring_id): key_ring_name = client.key_ring_path(project_id, location_id, key_ring_id) @@ -245,6 +265,13 @@ def test_create_key_labels(project_id, location_id, key_ring_id): assert key.labels == {'team': 'alpha', 'cost_center': 'cc1234'} +def test_create_key_mac(project_id, location_id, key_ring_id): + key_id = '{}'.format(uuid.uuid4()) + key = create_key_mac(project_id, location_id, key_ring_id, key_id) + assert key.purpose == kms.CryptoKey.CryptoKeyPurpose.MAC + assert key.version_template.algorithm == kms.CryptoKeyVersion.CryptoKeyVersionAlgorithm.HMAC_SHA256 + + def test_create_key_ring(project_id, location_id): key_ring_id = '{}'.format(uuid.uuid4()) key_ring = create_key_ring(project_id, location_id, key_ring_id) @@ -345,6 +372,11 @@ def test_encrypt_symmetric(client, project_id, location_id, key_ring_id, symmetr assert decrypt_response.plaintext == plaintext.encode('utf-8') +def test_generate_random_bytes(client, project_id, location_id): + generate_random_bytes_response = generate_random_bytes(project_id, location_id, 256) + assert len(generate_random_bytes_response.data) == 256 + + def test_get_key_labels(project_id, location_id, key_ring_id, symmetric_key_id): key = get_key_labels(project_id, location_id, key_ring_id, symmetric_key_id) assert key.labels == {'foo': 'bar', 'zip': 'zap'} @@ -412,6 +444,18 @@ def test_sign_asymmetric(client, project_id, location_id, key_ring_id, asymmetri pytest.fail('invalid signature') +def test_sign_mac(client, project_id, location_id, key_ring_id, hmac_key_id): + data = 'my data' + + sign_response = sign_mac(project_id, location_id, key_ring_id, hmac_key_id, '1', data) + assert sign_response.mac + + key_version_name = client.crypto_key_version_path(project_id, location_id, key_ring_id, hmac_key_id, '1') + verify_response = client.mac_verify(request={'name': key_version_name, 'data': data.encode('utf-8'), 'mac': sign_response.mac}) + + assert verify_response.success + + def test_update_key_add_rotation(project_id, location_id, key_ring_id, symmetric_key_id): key = update_key_add_rotation(project_id, location_id, key_ring_id, symmetric_key_id) assert key.rotation_period == datetime.timedelta(seconds=60*60*24*30) @@ -461,6 +505,16 @@ def test_verify_asymmetric_rsa(client, project_id, location_id, key_ring_id, asy assert verified +def test_verify_mac(client, project_id, location_id, key_ring_id, hmac_key_id): + data = 'my data' + + key_version_name = client.crypto_key_version_path(project_id, location_id, key_ring_id, hmac_key_id, '1') + sign_response = client.mac_sign(request={'name': key_version_name, 'data': data.encode('utf-8')}) + + verify_response = verify_mac(project_id, location_id, key_ring_id, hmac_key_id, '1', data, sign_response.mac) + assert verify_response.success + + def test_quickstart(project_id, location_id): key_rings = quickstart(project_id, location_id) assert key_rings diff --git a/kms/snippets/verify_mac.py b/kms/snippets/verify_mac.py new file mode 100644 index 000000000000..6fbcc73bdc3b --- /dev/null +++ b/kms/snippets/verify_mac.py @@ -0,0 +1,51 @@ +# Copyright 2021 Google LLC +# +# 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 + + +# [START kms_verify_mac] +def verify_mac(project_id, location_id, key_ring_id, key_id, version_id, data, signature): + """ + Verify the signature of data from an HMAC key. + + Args: + project_id (string): Google Cloud project ID (e.g. 'my-project'). + location_id (string): Cloud KMS location (e.g. 'us-east1'). + key_ring_id (string): ID of the Cloud KMS key ring (e.g. 'my-key-ring'). + key_id (string): ID of the key to use (e.g. 'my-key'). + version_id (string): Version to use (e.g. '1'). + data (string): Data that was signed. + signature (bytes): Signature bytes. + + Returns: + MacVerifyResponse: Success. + """ + + # Import the client library. + from google.cloud import kms + + # Create the client. + client = kms.KeyManagementServiceClient() + + # Build the key version name. + key_version_name = client.crypto_key_version_path(project_id, location_id, key_ring_id, key_id, version_id) + + # Convert the message to bytes. + data_bytes = data.encode('utf-8') + + # Call the API + verify_response = client.mac_verify( + request={'name': key_version_name, 'data': data_bytes, 'mac': signature}) + + print('Verified: {}'.format(verify_response.success)) + return verify_response +# [END kms_verify_mac] From d52bbd8f129d14a44eb480c0728444785038f179 Mon Sep 17 00:00:00 2001 From: WhiteSource Renovate Date: Wed, 25 Aug 2021 15:24:19 +0200 Subject: [PATCH 088/136] chore(deps): update dependency cryptography to v3.4.8 (#164) --- kms/attestations/requirements.txt | 2 +- kms/snippets/requirements.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/kms/attestations/requirements.txt b/kms/attestations/requirements.txt index 3f688a1c2cf6..c4de97d06531 100644 --- a/kms/attestations/requirements.txt +++ b/kms/attestations/requirements.txt @@ -1,2 +1,2 @@ -cryptography==3.4.7 +cryptography==3.4.8 pem==21.2.0 diff --git a/kms/snippets/requirements.txt b/kms/snippets/requirements.txt index 4b1e1e1fa615..bcd11836dce3 100644 --- a/kms/snippets/requirements.txt +++ b/kms/snippets/requirements.txt @@ -1,3 +1,3 @@ google-cloud-kms==2.5.0 -cryptography==3.4.7 +cryptography==3.4.8 crcmod==1.7 From 802d4c0e310cd5cd686ef3145a37d479216998ac Mon Sep 17 00:00:00 2001 From: WhiteSource Renovate Date: Mon, 30 Aug 2021 22:54:15 +0200 Subject: [PATCH 089/136] chore(deps): update dependency pytest to v6.2.5 (#169) --- kms/attestations/requirements-test.txt | 2 +- kms/snippets/requirements-test.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/kms/attestations/requirements-test.txt b/kms/attestations/requirements-test.txt index 95ea1e6a02b0..927094516e65 100644 --- a/kms/attestations/requirements-test.txt +++ b/kms/attestations/requirements-test.txt @@ -1 +1 @@ -pytest==6.2.4 +pytest==6.2.5 diff --git a/kms/snippets/requirements-test.txt b/kms/snippets/requirements-test.txt index 95ea1e6a02b0..927094516e65 100644 --- a/kms/snippets/requirements-test.txt +++ b/kms/snippets/requirements-test.txt @@ -1 +1 @@ -pytest==6.2.4 +pytest==6.2.5 From 53783709528098d2d7daa8695d9c656916756dfd Mon Sep 17 00:00:00 2001 From: WhiteSource Renovate Date: Tue, 31 Aug 2021 00:45:19 +0200 Subject: [PATCH 090/136] chore(deps): update dependency google-cloud-kms to v2.6.0 (#171) --- kms/snippets/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kms/snippets/requirements.txt b/kms/snippets/requirements.txt index bcd11836dce3..25f8cee04311 100644 --- a/kms/snippets/requirements.txt +++ b/kms/snippets/requirements.txt @@ -1,3 +1,3 @@ -google-cloud-kms==2.5.0 +google-cloud-kms==2.6.0 cryptography==3.4.8 crcmod==1.7 From 06dbf90b58415398706e2f26634f7f33bb20f304 Mon Sep 17 00:00:00 2001 From: "gcf-owl-bot[bot]" <78513119+gcf-owl-bot[bot]@users.noreply.github.com> Date: Wed, 15 Sep 2021 12:27:20 -0400 Subject: [PATCH 091/136] chore: google-cloud-python now uses 'main' for default branch (#175) Source-Link: https://github.com/googleapis/synthtool/commit/a6032ae644beb190b0fc2be74a8f6a967e6f2489 Post-Processor: gcr.io/repo-automation-bots/owlbot-python:latest@sha256:b14b898b4f896205957ca3adb6941abf99e3cc404c07a4760655801b68ce688f Co-authored-by: Owl Bot --- kms/snippets/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kms/snippets/README.md b/kms/snippets/README.md index 56715580b612..4056cf8a9338 100644 --- a/kms/snippets/README.md +++ b/kms/snippets/README.md @@ -47,7 +47,7 @@ View the [contributing guidelines][contrib_guide], the [Python style guide][py_s [enable_billing]:https://cloud.google.com/apis/docs/getting-started#enabling_billing [client_library_python]: https://googlecloudplatform.github.io/google-cloud-python/ [issues]: https://github.com/GoogleCloudPlatform/google-cloud-python/issues -[contrib_guide]: https://github.com/googleapis/google-cloud-python/blob/master/CONTRIBUTING.rst +[contrib_guide]: https://github.com/googleapis/google-cloud-python/blob/main/CONTRIBUTING.rst [py_style]: http://google.github.io/styleguide/pyguide.html [cloud_sdk]: https://cloud.google.com/sdk/docs [gcloud_shell]: https://cloud.google.com/shell/docs From dec3cc3562074f6a4e01b8d33cc8ebaade1e1248 Mon Sep 17 00:00:00 2001 From: WhiteSource Renovate Date: Mon, 27 Sep 2021 19:51:12 +0200 Subject: [PATCH 092/136] chore(deps): update dependency google-cloud-kms to v2.6.1 (#180) --- kms/snippets/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kms/snippets/requirements.txt b/kms/snippets/requirements.txt index 25f8cee04311..4a564824236a 100644 --- a/kms/snippets/requirements.txt +++ b/kms/snippets/requirements.txt @@ -1,3 +1,3 @@ -google-cloud-kms==2.6.0 +google-cloud-kms==2.6.1 cryptography==3.4.8 crcmod==1.7 From 89a6f2e03ed8ffad1d79ac2675d928af46c21730 Mon Sep 17 00:00:00 2001 From: WhiteSource Renovate Date: Thu, 30 Sep 2021 11:29:49 +0200 Subject: [PATCH 093/136] chore(deps): update dependency cryptography to v35 (#182) --- kms/attestations/requirements.txt | 2 +- kms/snippets/requirements.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/kms/attestations/requirements.txt b/kms/attestations/requirements.txt index c4de97d06531..5b16bed42918 100644 --- a/kms/attestations/requirements.txt +++ b/kms/attestations/requirements.txt @@ -1,2 +1,2 @@ -cryptography==3.4.8 +cryptography==35.0.0 pem==21.2.0 diff --git a/kms/snippets/requirements.txt b/kms/snippets/requirements.txt index 4a564824236a..4c762c5964c1 100644 --- a/kms/snippets/requirements.txt +++ b/kms/snippets/requirements.txt @@ -1,3 +1,3 @@ google-cloud-kms==2.6.1 -cryptography==3.4.8 +cryptography==35.0.0 crcmod==1.7 From 8121d9dc047ee3c1cfa4a55636f11d6d3a18c2b4 Mon Sep 17 00:00:00 2001 From: WhiteSource Renovate Date: Thu, 30 Sep 2021 19:34:50 +0200 Subject: [PATCH 094/136] chore(deps): update dependency google-cloud-kms to v2.7.0 (#185) --- kms/snippets/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kms/snippets/requirements.txt b/kms/snippets/requirements.txt index 4c762c5964c1..ad7756cbd1b2 100644 --- a/kms/snippets/requirements.txt +++ b/kms/snippets/requirements.txt @@ -1,3 +1,3 @@ -google-cloud-kms==2.6.1 +google-cloud-kms==2.7.0 cryptography==35.0.0 crcmod==1.7 From 7944d96906cf3096f64e3a22b62f192eeebd747f Mon Sep 17 00:00:00 2001 From: WhiteSource Renovate Date: Fri, 1 Oct 2021 01:19:55 +0200 Subject: [PATCH 095/136] chore(deps): update dependency google-cloud-kms to v2.8.0 (#188) --- kms/snippets/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kms/snippets/requirements.txt b/kms/snippets/requirements.txt index ad7756cbd1b2..c430d4bc90b2 100644 --- a/kms/snippets/requirements.txt +++ b/kms/snippets/requirements.txt @@ -1,3 +1,3 @@ -google-cloud-kms==2.7.0 +google-cloud-kms==2.8.0 cryptography==35.0.0 crcmod==1.7 From 5005d26d17f1db7f6796ad48de7e599dcb01a755 Mon Sep 17 00:00:00 2001 From: WhiteSource Renovate Date: Fri, 29 Oct 2021 17:49:42 +0200 Subject: [PATCH 096/136] chore(deps): update dependency google-cloud-kms to v2.9.0 (#194) * chore(deps): update dependency google-cloud-kms to v2.9.0 * chore: remove replacements in owlbot.py * test: increase code coverage Co-authored-by: Bu Sun Kim Co-authored-by: Anthonios Partheniou --- kms/attestations/noxfile.py | 104 ++++++++++++++++++++++++---------- kms/snippets/noxfile.py | 104 ++++++++++++++++++++++++---------- kms/snippets/requirements.txt | 2 +- 3 files changed, 151 insertions(+), 59 deletions(-) diff --git a/kms/attestations/noxfile.py b/kms/attestations/noxfile.py index ba55d7ce53ca..93a9122cc457 100644 --- a/kms/attestations/noxfile.py +++ b/kms/attestations/noxfile.py @@ -17,6 +17,7 @@ import os from pathlib import Path import sys +from typing import Callable, Dict, List, Optional import nox @@ -27,8 +28,9 @@ # WARNING - WARNING - WARNING - WARNING - WARNING # WARNING - WARNING - WARNING - WARNING - WARNING -# Copy `noxfile_config.py` to your directory and modify it instead. +BLACK_VERSION = "black==19.10b0" +# Copy `noxfile_config.py` to your directory and modify it instead. # `TEST_CONFIG` dict is a configuration hook that allows users to # modify the test configurations. The values here should be in sync @@ -37,24 +39,29 @@ TEST_CONFIG = { # You can opt out from the test for specific Python versions. - 'ignored_versions': ["2.7"], - + "ignored_versions": [], + # Old samples are opted out of enforcing Python type hints + # All new samples should feature them + "enforce_type_hints": False, # An envvar key for determining the project id to use. Change it # to 'BUILD_SPECIFIC_GCLOUD_PROJECT' if you want to opt in using a # build specific Cloud project. You can also use your own string # to use your own Cloud project. - 'gcloud_project_env': 'GOOGLE_CLOUD_PROJECT', + "gcloud_project_env": "GOOGLE_CLOUD_PROJECT", # 'gcloud_project_env': 'BUILD_SPECIFIC_GCLOUD_PROJECT', - + # If you need to use a specific version of pip, + # change pip_version_override to the string representation + # of the version number, for example, "20.2.4" + "pip_version_override": None, # A dictionary you want to inject into your test. Don't put any # secrets here. These values will override predefined values. - 'envs': {}, + "envs": {}, } try: # Ensure we can import noxfile_config in the project's directory. - sys.path.append('.') + sys.path.append(".") from noxfile_config import TEST_CONFIG_OVERRIDE except ImportError as e: print("No user noxfile_config found: detail: {}".format(e)) @@ -64,36 +71,43 @@ TEST_CONFIG.update(TEST_CONFIG_OVERRIDE) -def get_pytest_env_vars(): +def get_pytest_env_vars() -> Dict[str, str]: """Returns a dict for pytest invocation.""" ret = {} # Override the GCLOUD_PROJECT and the alias. - env_key = TEST_CONFIG['gcloud_project_env'] + env_key = TEST_CONFIG["gcloud_project_env"] # This should error out if not set. - ret['GOOGLE_CLOUD_PROJECT'] = os.environ[env_key] + ret["GOOGLE_CLOUD_PROJECT"] = os.environ[env_key] # Apply user supplied envs. - ret.update(TEST_CONFIG['envs']) + ret.update(TEST_CONFIG["envs"]) return ret # DO NOT EDIT - automatically generated. -# All versions used to tested samples. -ALL_VERSIONS = ["2.7", "3.6", "3.7", "3.8"] +# All versions used to test samples. +ALL_VERSIONS = ["3.6", "3.7", "3.8", "3.9", "3.10"] # Any default versions that should be ignored. -IGNORED_VERSIONS = TEST_CONFIG['ignored_versions'] +IGNORED_VERSIONS = TEST_CONFIG["ignored_versions"] TESTED_VERSIONS = sorted([v for v in ALL_VERSIONS if v not in IGNORED_VERSIONS]) -INSTALL_LIBRARY_FROM_SOURCE = bool(os.environ.get("INSTALL_LIBRARY_FROM_SOURCE", False)) +INSTALL_LIBRARY_FROM_SOURCE = os.environ.get("INSTALL_LIBRARY_FROM_SOURCE", False) in ( + "True", + "true", +) + +# Error if a python version is missing +nox.options.error_on_missing_interpreters = True + # # Style Checks # -def _determine_local_import_names(start_dir): +def _determine_local_import_names(start_dir: str) -> List[str]: """Determines all import names that should be considered "local". This is used when running the linter to insure that import order is @@ -131,18 +145,34 @@ def _determine_local_import_names(start_dir): @nox.session -def lint(session): - session.install("flake8", "flake8-import-order") +def lint(session: nox.sessions.Session) -> None: + if not TEST_CONFIG["enforce_type_hints"]: + session.install("flake8", "flake8-import-order") + else: + session.install("flake8", "flake8-import-order", "flake8-annotations") local_names = _determine_local_import_names(".") args = FLAKE8_COMMON_ARGS + [ "--application-import-names", ",".join(local_names), - "." + ".", ] session.run("flake8", *args) +# +# Black +# + + +@nox.session +def blacken(session: nox.sessions.Session) -> None: + session.install(BLACK_VERSION) + python_files = [path for path in os.listdir(".") if path.endswith(".py")] + + session.run("black", *python_files) + + # # Sample Tests # @@ -151,13 +181,24 @@ def lint(session): PYTEST_COMMON_ARGS = ["--junitxml=sponge_log.xml"] -def _session_tests(session, post_install=None): +def _session_tests( + session: nox.sessions.Session, post_install: Callable = None +) -> None: + if TEST_CONFIG["pip_version_override"]: + pip_version = TEST_CONFIG["pip_version_override"] + session.install(f"pip=={pip_version}") """Runs py.test for a particular project.""" if os.path.exists("requirements.txt"): - session.install("-r", "requirements.txt") + if os.path.exists("constraints.txt"): + session.install("-r", "requirements.txt", "-c", "constraints.txt") + else: + session.install("-r", "requirements.txt") if os.path.exists("requirements-test.txt"): - session.install("-r", "requirements-test.txt") + if os.path.exists("constraints-test.txt"): + session.install("-r", "requirements-test.txt", "-c", "constraints-test.txt") + else: + session.install("-r", "requirements-test.txt") if INSTALL_LIBRARY_FROM_SOURCE: session.install("-e", _get_repo_root()) @@ -172,19 +213,19 @@ def _session_tests(session, post_install=None): # on travis where slow and flaky tests are excluded. # See http://doc.pytest.org/en/latest/_modules/_pytest/main.html success_codes=[0, 5], - env=get_pytest_env_vars() + env=get_pytest_env_vars(), ) @nox.session(python=ALL_VERSIONS) -def py(session): +def py(session: nox.sessions.Session) -> None: """Runs py.test for a sample using the specified version of Python.""" if session.python in TESTED_VERSIONS: _session_tests(session) else: - session.skip("SKIPPED: {} tests are disabled for this sample.".format( - session.python - )) + session.skip( + "SKIPPED: {} tests are disabled for this sample.".format(session.python) + ) # @@ -192,7 +233,7 @@ def py(session): # -def _get_repo_root(): +def _get_repo_root() -> Optional[str]: """ Returns the root folder of the project. """ # Get root of this repository. Assume we don't have directories nested deeper than 10 items. p = Path(os.getcwd()) @@ -201,6 +242,11 @@ def _get_repo_root(): break if Path(p / ".git").exists(): return str(p) + # .git is not available in repos cloned via Cloud Build + # setup.py is always in the library's root, so use that instead + # https://github.com/googleapis/synthtool/issues/792 + if Path(p / "setup.py").exists(): + return str(p) p = p.parent raise Exception("Unable to detect repository root.") @@ -210,7 +256,7 @@ def _get_repo_root(): @nox.session @nox.parametrize("path", GENERATED_READMES) -def readmegen(session, path): +def readmegen(session: nox.sessions.Session, path: str) -> None: """(Re-)generates the readme for a sample.""" session.install("jinja2", "pyyaml") dir_ = os.path.dirname(path) diff --git a/kms/snippets/noxfile.py b/kms/snippets/noxfile.py index ba55d7ce53ca..93a9122cc457 100644 --- a/kms/snippets/noxfile.py +++ b/kms/snippets/noxfile.py @@ -17,6 +17,7 @@ import os from pathlib import Path import sys +from typing import Callable, Dict, List, Optional import nox @@ -27,8 +28,9 @@ # WARNING - WARNING - WARNING - WARNING - WARNING # WARNING - WARNING - WARNING - WARNING - WARNING -# Copy `noxfile_config.py` to your directory and modify it instead. +BLACK_VERSION = "black==19.10b0" +# Copy `noxfile_config.py` to your directory and modify it instead. # `TEST_CONFIG` dict is a configuration hook that allows users to # modify the test configurations. The values here should be in sync @@ -37,24 +39,29 @@ TEST_CONFIG = { # You can opt out from the test for specific Python versions. - 'ignored_versions': ["2.7"], - + "ignored_versions": [], + # Old samples are opted out of enforcing Python type hints + # All new samples should feature them + "enforce_type_hints": False, # An envvar key for determining the project id to use. Change it # to 'BUILD_SPECIFIC_GCLOUD_PROJECT' if you want to opt in using a # build specific Cloud project. You can also use your own string # to use your own Cloud project. - 'gcloud_project_env': 'GOOGLE_CLOUD_PROJECT', + "gcloud_project_env": "GOOGLE_CLOUD_PROJECT", # 'gcloud_project_env': 'BUILD_SPECIFIC_GCLOUD_PROJECT', - + # If you need to use a specific version of pip, + # change pip_version_override to the string representation + # of the version number, for example, "20.2.4" + "pip_version_override": None, # A dictionary you want to inject into your test. Don't put any # secrets here. These values will override predefined values. - 'envs': {}, + "envs": {}, } try: # Ensure we can import noxfile_config in the project's directory. - sys.path.append('.') + sys.path.append(".") from noxfile_config import TEST_CONFIG_OVERRIDE except ImportError as e: print("No user noxfile_config found: detail: {}".format(e)) @@ -64,36 +71,43 @@ TEST_CONFIG.update(TEST_CONFIG_OVERRIDE) -def get_pytest_env_vars(): +def get_pytest_env_vars() -> Dict[str, str]: """Returns a dict for pytest invocation.""" ret = {} # Override the GCLOUD_PROJECT and the alias. - env_key = TEST_CONFIG['gcloud_project_env'] + env_key = TEST_CONFIG["gcloud_project_env"] # This should error out if not set. - ret['GOOGLE_CLOUD_PROJECT'] = os.environ[env_key] + ret["GOOGLE_CLOUD_PROJECT"] = os.environ[env_key] # Apply user supplied envs. - ret.update(TEST_CONFIG['envs']) + ret.update(TEST_CONFIG["envs"]) return ret # DO NOT EDIT - automatically generated. -# All versions used to tested samples. -ALL_VERSIONS = ["2.7", "3.6", "3.7", "3.8"] +# All versions used to test samples. +ALL_VERSIONS = ["3.6", "3.7", "3.8", "3.9", "3.10"] # Any default versions that should be ignored. -IGNORED_VERSIONS = TEST_CONFIG['ignored_versions'] +IGNORED_VERSIONS = TEST_CONFIG["ignored_versions"] TESTED_VERSIONS = sorted([v for v in ALL_VERSIONS if v not in IGNORED_VERSIONS]) -INSTALL_LIBRARY_FROM_SOURCE = bool(os.environ.get("INSTALL_LIBRARY_FROM_SOURCE", False)) +INSTALL_LIBRARY_FROM_SOURCE = os.environ.get("INSTALL_LIBRARY_FROM_SOURCE", False) in ( + "True", + "true", +) + +# Error if a python version is missing +nox.options.error_on_missing_interpreters = True + # # Style Checks # -def _determine_local_import_names(start_dir): +def _determine_local_import_names(start_dir: str) -> List[str]: """Determines all import names that should be considered "local". This is used when running the linter to insure that import order is @@ -131,18 +145,34 @@ def _determine_local_import_names(start_dir): @nox.session -def lint(session): - session.install("flake8", "flake8-import-order") +def lint(session: nox.sessions.Session) -> None: + if not TEST_CONFIG["enforce_type_hints"]: + session.install("flake8", "flake8-import-order") + else: + session.install("flake8", "flake8-import-order", "flake8-annotations") local_names = _determine_local_import_names(".") args = FLAKE8_COMMON_ARGS + [ "--application-import-names", ",".join(local_names), - "." + ".", ] session.run("flake8", *args) +# +# Black +# + + +@nox.session +def blacken(session: nox.sessions.Session) -> None: + session.install(BLACK_VERSION) + python_files = [path for path in os.listdir(".") if path.endswith(".py")] + + session.run("black", *python_files) + + # # Sample Tests # @@ -151,13 +181,24 @@ def lint(session): PYTEST_COMMON_ARGS = ["--junitxml=sponge_log.xml"] -def _session_tests(session, post_install=None): +def _session_tests( + session: nox.sessions.Session, post_install: Callable = None +) -> None: + if TEST_CONFIG["pip_version_override"]: + pip_version = TEST_CONFIG["pip_version_override"] + session.install(f"pip=={pip_version}") """Runs py.test for a particular project.""" if os.path.exists("requirements.txt"): - session.install("-r", "requirements.txt") + if os.path.exists("constraints.txt"): + session.install("-r", "requirements.txt", "-c", "constraints.txt") + else: + session.install("-r", "requirements.txt") if os.path.exists("requirements-test.txt"): - session.install("-r", "requirements-test.txt") + if os.path.exists("constraints-test.txt"): + session.install("-r", "requirements-test.txt", "-c", "constraints-test.txt") + else: + session.install("-r", "requirements-test.txt") if INSTALL_LIBRARY_FROM_SOURCE: session.install("-e", _get_repo_root()) @@ -172,19 +213,19 @@ def _session_tests(session, post_install=None): # on travis where slow and flaky tests are excluded. # See http://doc.pytest.org/en/latest/_modules/_pytest/main.html success_codes=[0, 5], - env=get_pytest_env_vars() + env=get_pytest_env_vars(), ) @nox.session(python=ALL_VERSIONS) -def py(session): +def py(session: nox.sessions.Session) -> None: """Runs py.test for a sample using the specified version of Python.""" if session.python in TESTED_VERSIONS: _session_tests(session) else: - session.skip("SKIPPED: {} tests are disabled for this sample.".format( - session.python - )) + session.skip( + "SKIPPED: {} tests are disabled for this sample.".format(session.python) + ) # @@ -192,7 +233,7 @@ def py(session): # -def _get_repo_root(): +def _get_repo_root() -> Optional[str]: """ Returns the root folder of the project. """ # Get root of this repository. Assume we don't have directories nested deeper than 10 items. p = Path(os.getcwd()) @@ -201,6 +242,11 @@ def _get_repo_root(): break if Path(p / ".git").exists(): return str(p) + # .git is not available in repos cloned via Cloud Build + # setup.py is always in the library's root, so use that instead + # https://github.com/googleapis/synthtool/issues/792 + if Path(p / "setup.py").exists(): + return str(p) p = p.parent raise Exception("Unable to detect repository root.") @@ -210,7 +256,7 @@ def _get_repo_root(): @nox.session @nox.parametrize("path", GENERATED_READMES) -def readmegen(session, path): +def readmegen(session: nox.sessions.Session, path: str) -> None: """(Re-)generates the readme for a sample.""" session.install("jinja2", "pyyaml") dir_ = os.path.dirname(path) diff --git a/kms/snippets/requirements.txt b/kms/snippets/requirements.txt index c430d4bc90b2..0dbf4d63fea7 100644 --- a/kms/snippets/requirements.txt +++ b/kms/snippets/requirements.txt @@ -1,3 +1,3 @@ -google-cloud-kms==2.8.0 +google-cloud-kms==2.9.0 cryptography==35.0.0 crcmod==1.7 From f0c5cb5688d680e784ed3d8cf7f39c97910213fe Mon Sep 17 00:00:00 2001 From: WhiteSource Renovate Date: Fri, 29 Oct 2021 20:00:27 +0200 Subject: [PATCH 097/136] chore(deps): update dependency google-cloud-kms to v2.10.0 (#199) --- kms/snippets/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kms/snippets/requirements.txt b/kms/snippets/requirements.txt index 0dbf4d63fea7..ae8481750971 100644 --- a/kms/snippets/requirements.txt +++ b/kms/snippets/requirements.txt @@ -1,3 +1,3 @@ -google-cloud-kms==2.9.0 +google-cloud-kms==2.10.0 cryptography==35.0.0 crcmod==1.7 From 4b8836d7fcd9d22da5e0960cc7c0ad94a84e4937 Mon Sep 17 00:00:00 2001 From: WhiteSource Renovate Date: Tue, 2 Nov 2021 18:37:43 +0100 Subject: [PATCH 098/136] chore(deps): update dependency google-cloud-kms to v2.10.1 (#202) --- kms/snippets/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kms/snippets/requirements.txt b/kms/snippets/requirements.txt index ae8481750971..25fbb41f9b71 100644 --- a/kms/snippets/requirements.txt +++ b/kms/snippets/requirements.txt @@ -1,3 +1,3 @@ -google-cloud-kms==2.10.0 +google-cloud-kms==2.10.1 cryptography==35.0.0 crcmod==1.7 From 804e44a627f8e908e8ed661c05a415fc9caeb02b Mon Sep 17 00:00:00 2001 From: Benson Kuang <3453547+bkuang@users.noreply.github.com> Date: Wed, 3 Nov 2021 18:51:29 -0400 Subject: [PATCH 099/136] chore: update README and fix typos in attestation scripts (#203) Remove the README.rst.in until the README gen templates have been updated Co-authored-by: Benson Kuang --- kms/attestations/README.rst | 15 +++++++++------ kms/attestations/README.rst.in | 23 ----------------------- kms/attestations/verify_attestation.py | 2 +- 3 files changed, 10 insertions(+), 30 deletions(-) delete mode 100644 kms/attestations/README.rst.in diff --git a/kms/attestations/README.rst b/kms/attestations/README.rst index 4a9ff7f74d72..de84a1537b37 100644 --- a/kms/attestations/README.rst +++ b/kms/attestations/README.rst @@ -1,5 +1,3 @@ -.. This file is automatically generated. Do not edit this file directly. - Google Cloud Key Management Service Python Samples =============================================================================== @@ -12,7 +10,7 @@ This directory contains samples for Google Cloud Key Management Service. The `Cl -.. _Google Cloud Key Management Service: https://cloud.google.com/kms/docs/ +.. _Cloud Key Management Service: https://cloud.google.com/kms/docs/ @@ -25,11 +23,11 @@ Setup Install Dependencies ++++++++++++++++++++ -#. Clone python-docs-samples and change directory to the sample directory you want to use. +#. Clone python-kms and change directory to the sample directory you want to use. .. code-block:: bash - $ git clone https://github.com/GoogleCloudPlatform/python-docs-samples.git + $ git clone https://github.com/googleapis/python-kms.git #. Install `pip`_ and `virtualenv`_ if you do not already have them. You may want to refer to the `Python Development Environment Setup Guide`_ for Google Cloud Platform for instructions. @@ -43,6 +41,11 @@ Install Dependencies $ virtualenv env $ source env/bin/activate +#. Install the dependencies needed to run the samples. + + .. code-block:: bash + + $ pip install -r requirements.txt .. _pip: https://pip.pypa.io/ .. _virtualenv: https://virtualenv.pypa.io/ @@ -86,7 +89,7 @@ Verify attestations for keys generated by Cloud HSM +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ .. image:: https://gstatic.com/cloudssh/images/open-btn.png - :target: https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/GoogleCloudPlatform/python-docs-samples&page=editor&open_in_editor=samples/attestations/verify_attestation.py,samples/attestations/README.rst + :target: https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/python-kms&page=editor&open_in_editor=samples/attestations/verify_attestation.py,samples/attestations/README.rst diff --git a/kms/attestations/README.rst.in b/kms/attestations/README.rst.in deleted file mode 100644 index 596ab5fe5b75..000000000000 --- a/kms/attestations/README.rst.in +++ /dev/null @@ -1,23 +0,0 @@ -# This file is used to generate README.rst - -product: - name: Google Cloud Key Management Service - short_name: Cloud Key Management Service - url: https://cloud.google.com/kms/docs/ - description: > - The `Cloud Key Management Service`_ allows you to create, import, and manage - cryptographic keys and perform cryptographic operations in a single centralized cloud service. - -setup: -- install_deps - -samples: -- name: Verify attestations and certificate chains for keys generated by Cloud HSM - file: verify_attestation_chains.py - show_help: True -- name: Verify attestations for keys generated by Cloud HSM - file: verify_attestation.py - show_help: True - -folder: samples/attestations - diff --git a/kms/attestations/verify_attestation.py b/kms/attestations/verify_attestation.py index e534ad9eecb4..090f6b81874e 100644 --- a/kms/attestations/verify_attestation.py +++ b/kms/attestations/verify_attestation.py @@ -56,7 +56,7 @@ def verify(attestation_file, bundle_file): cert_obj = x509.load_pem_x509_certificate( str(cert).encode('utf-8'), backends.default_backend()) try: - # Check if the data was signed by the private key assosicated + # Check if the data was signed by the private key associated # with the public key in the certificate. The data should have # been signed with PKCS1v15 padding. cert_obj.public_key().verify( From 1473fc68b31a64d531fba0980893abcebeef92f7 Mon Sep 17 00:00:00 2001 From: WhiteSource Renovate Date: Tue, 23 Nov 2021 16:29:34 +0100 Subject: [PATCH 100/136] chore(deps): update dependency cryptography to v36 (#210) --- kms/attestations/requirements.txt | 2 +- kms/snippets/requirements.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/kms/attestations/requirements.txt b/kms/attestations/requirements.txt index 5b16bed42918..0032a6fea526 100644 --- a/kms/attestations/requirements.txt +++ b/kms/attestations/requirements.txt @@ -1,2 +1,2 @@ -cryptography==35.0.0 +cryptography==36.0.0 pem==21.2.0 diff --git a/kms/snippets/requirements.txt b/kms/snippets/requirements.txt index 25fbb41f9b71..56a92969a37c 100644 --- a/kms/snippets/requirements.txt +++ b/kms/snippets/requirements.txt @@ -1,3 +1,3 @@ google-cloud-kms==2.10.1 -cryptography==35.0.0 +cryptography==36.0.0 crcmod==1.7 From 8b949e3dc3406901f5aae6f6342186fe81cc664a Mon Sep 17 00:00:00 2001 From: WhiteSource Renovate Date: Wed, 15 Dec 2021 12:11:57 +0100 Subject: [PATCH 101/136] chore(deps): update dependency cryptography to v36.0.1 (#216) --- kms/attestations/requirements.txt | 2 +- kms/snippets/requirements.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/kms/attestations/requirements.txt b/kms/attestations/requirements.txt index 0032a6fea526..86e5361ffdb2 100644 --- a/kms/attestations/requirements.txt +++ b/kms/attestations/requirements.txt @@ -1,2 +1,2 @@ -cryptography==36.0.0 +cryptography==36.0.1 pem==21.2.0 diff --git a/kms/snippets/requirements.txt b/kms/snippets/requirements.txt index 56a92969a37c..e59bb1db32ce 100644 --- a/kms/snippets/requirements.txt +++ b/kms/snippets/requirements.txt @@ -1,3 +1,3 @@ google-cloud-kms==2.10.1 -cryptography==36.0.0 +cryptography==36.0.1 crcmod==1.7 From 29c75d7eab83aab4f6a963e1837a7b714e4e8459 Mon Sep 17 00:00:00 2001 From: "gcf-owl-bot[bot]" <78513119+gcf-owl-bot[bot]@users.noreply.github.com> Date: Tue, 11 Jan 2022 07:43:31 -0500 Subject: [PATCH 102/136] chore(samples): Add check for tests in directory (#221) Source-Link: https://github.com/googleapis/synthtool/commit/52aef91f8d25223d9dbdb4aebd94ba8eea2101f3 Post-Processor: gcr.io/cloud-devrel-public-resources/owlbot-python:latest@sha256:36a95b8f494e4674dc9eee9af98961293b51b86b3649942aac800ae6c1f796d4 Co-authored-by: Owl Bot --- kms/attestations/noxfile.py | 70 +++++++++++++++++++++---------------- kms/snippets/noxfile.py | 70 +++++++++++++++++++++---------------- 2 files changed, 78 insertions(+), 62 deletions(-) diff --git a/kms/attestations/noxfile.py b/kms/attestations/noxfile.py index 93a9122cc457..3bbef5d54f44 100644 --- a/kms/attestations/noxfile.py +++ b/kms/attestations/noxfile.py @@ -14,6 +14,7 @@ from __future__ import print_function +import glob import os from pathlib import Path import sys @@ -184,37 +185,44 @@ def blacken(session: nox.sessions.Session) -> None: def _session_tests( session: nox.sessions.Session, post_install: Callable = None ) -> None: - if TEST_CONFIG["pip_version_override"]: - pip_version = TEST_CONFIG["pip_version_override"] - session.install(f"pip=={pip_version}") - """Runs py.test for a particular project.""" - if os.path.exists("requirements.txt"): - if os.path.exists("constraints.txt"): - session.install("-r", "requirements.txt", "-c", "constraints.txt") - else: - session.install("-r", "requirements.txt") - - if os.path.exists("requirements-test.txt"): - if os.path.exists("constraints-test.txt"): - session.install("-r", "requirements-test.txt", "-c", "constraints-test.txt") - else: - session.install("-r", "requirements-test.txt") - - if INSTALL_LIBRARY_FROM_SOURCE: - session.install("-e", _get_repo_root()) - - if post_install: - post_install(session) - - session.run( - "pytest", - *(PYTEST_COMMON_ARGS + session.posargs), - # Pytest will return 5 when no tests are collected. This can happen - # on travis where slow and flaky tests are excluded. - # See http://doc.pytest.org/en/latest/_modules/_pytest/main.html - success_codes=[0, 5], - env=get_pytest_env_vars(), - ) + # check for presence of tests + test_list = glob.glob("*_test.py") + glob.glob("test_*.py") + if len(test_list) == 0: + print("No tests found, skipping directory.") + else: + if TEST_CONFIG["pip_version_override"]: + pip_version = TEST_CONFIG["pip_version_override"] + session.install(f"pip=={pip_version}") + """Runs py.test for a particular project.""" + if os.path.exists("requirements.txt"): + if os.path.exists("constraints.txt"): + session.install("-r", "requirements.txt", "-c", "constraints.txt") + else: + session.install("-r", "requirements.txt") + + if os.path.exists("requirements-test.txt"): + if os.path.exists("constraints-test.txt"): + session.install( + "-r", "requirements-test.txt", "-c", "constraints-test.txt" + ) + else: + session.install("-r", "requirements-test.txt") + + if INSTALL_LIBRARY_FROM_SOURCE: + session.install("-e", _get_repo_root()) + + if post_install: + post_install(session) + + session.run( + "pytest", + *(PYTEST_COMMON_ARGS + session.posargs), + # Pytest will return 5 when no tests are collected. This can happen + # on travis where slow and flaky tests are excluded. + # See http://doc.pytest.org/en/latest/_modules/_pytest/main.html + success_codes=[0, 5], + env=get_pytest_env_vars(), + ) @nox.session(python=ALL_VERSIONS) diff --git a/kms/snippets/noxfile.py b/kms/snippets/noxfile.py index 93a9122cc457..3bbef5d54f44 100644 --- a/kms/snippets/noxfile.py +++ b/kms/snippets/noxfile.py @@ -14,6 +14,7 @@ from __future__ import print_function +import glob import os from pathlib import Path import sys @@ -184,37 +185,44 @@ def blacken(session: nox.sessions.Session) -> None: def _session_tests( session: nox.sessions.Session, post_install: Callable = None ) -> None: - if TEST_CONFIG["pip_version_override"]: - pip_version = TEST_CONFIG["pip_version_override"] - session.install(f"pip=={pip_version}") - """Runs py.test for a particular project.""" - if os.path.exists("requirements.txt"): - if os.path.exists("constraints.txt"): - session.install("-r", "requirements.txt", "-c", "constraints.txt") - else: - session.install("-r", "requirements.txt") - - if os.path.exists("requirements-test.txt"): - if os.path.exists("constraints-test.txt"): - session.install("-r", "requirements-test.txt", "-c", "constraints-test.txt") - else: - session.install("-r", "requirements-test.txt") - - if INSTALL_LIBRARY_FROM_SOURCE: - session.install("-e", _get_repo_root()) - - if post_install: - post_install(session) - - session.run( - "pytest", - *(PYTEST_COMMON_ARGS + session.posargs), - # Pytest will return 5 when no tests are collected. This can happen - # on travis where slow and flaky tests are excluded. - # See http://doc.pytest.org/en/latest/_modules/_pytest/main.html - success_codes=[0, 5], - env=get_pytest_env_vars(), - ) + # check for presence of tests + test_list = glob.glob("*_test.py") + glob.glob("test_*.py") + if len(test_list) == 0: + print("No tests found, skipping directory.") + else: + if TEST_CONFIG["pip_version_override"]: + pip_version = TEST_CONFIG["pip_version_override"] + session.install(f"pip=={pip_version}") + """Runs py.test for a particular project.""" + if os.path.exists("requirements.txt"): + if os.path.exists("constraints.txt"): + session.install("-r", "requirements.txt", "-c", "constraints.txt") + else: + session.install("-r", "requirements.txt") + + if os.path.exists("requirements-test.txt"): + if os.path.exists("constraints-test.txt"): + session.install( + "-r", "requirements-test.txt", "-c", "constraints-test.txt" + ) + else: + session.install("-r", "requirements-test.txt") + + if INSTALL_LIBRARY_FROM_SOURCE: + session.install("-e", _get_repo_root()) + + if post_install: + post_install(session) + + session.run( + "pytest", + *(PYTEST_COMMON_ARGS + session.posargs), + # Pytest will return 5 when no tests are collected. This can happen + # on travis where slow and flaky tests are excluded. + # See http://doc.pytest.org/en/latest/_modules/_pytest/main.html + success_codes=[0, 5], + env=get_pytest_env_vars(), + ) @nox.session(python=ALL_VERSIONS) From df10185ef5fb65019cfa1581da20e8b857e3e51a Mon Sep 17 00:00:00 2001 From: "gcf-owl-bot[bot]" <78513119+gcf-owl-bot[bot]@users.noreply.github.com> Date: Tue, 18 Jan 2022 20:27:24 -0500 Subject: [PATCH 103/136] chore(python): Noxfile recognizes that tests can live in a folder (#225) Source-Link: https://github.com/googleapis/synthtool/commit/4760d8dce1351d93658cb11d02a1b7ceb23ae5d7 Post-Processor: gcr.io/cloud-devrel-public-resources/owlbot-python:latest@sha256:f0e4b51deef56bed74d3e2359c583fc104a8d6367da3984fc5c66938db738828 Co-authored-by: Owl Bot --- kms/attestations/noxfile.py | 1 + kms/snippets/noxfile.py | 1 + 2 files changed, 2 insertions(+) diff --git a/kms/attestations/noxfile.py b/kms/attestations/noxfile.py index 3bbef5d54f44..20cdfc620138 100644 --- a/kms/attestations/noxfile.py +++ b/kms/attestations/noxfile.py @@ -187,6 +187,7 @@ def _session_tests( ) -> None: # check for presence of tests test_list = glob.glob("*_test.py") + glob.glob("test_*.py") + test_list.extend(glob.glob("tests")) if len(test_list) == 0: print("No tests found, skipping directory.") else: diff --git a/kms/snippets/noxfile.py b/kms/snippets/noxfile.py index 3bbef5d54f44..20cdfc620138 100644 --- a/kms/snippets/noxfile.py +++ b/kms/snippets/noxfile.py @@ -187,6 +187,7 @@ def _session_tests( ) -> None: # check for presence of tests test_list = glob.glob("*_test.py") + glob.glob("test_*.py") + test_list.extend(glob.glob("tests")) if len(test_list) == 0: print("No tests found, skipping directory.") else: From a0e8ddd459fb7fcfac7850704c95554a672f457c Mon Sep 17 00:00:00 2001 From: pedroysb Date: Fri, 21 Jan 2022 14:26:52 +0100 Subject: [PATCH 104/136] docs(samples): fix typo in verify_asymmetric_ec.py (#227) Co-authored-by: Anthonios Partheniou --- kms/snippets/verify_asymmetric_ec.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kms/snippets/verify_asymmetric_ec.py b/kms/snippets/verify_asymmetric_ec.py index d29128bd8aca..376f7507890a 100644 --- a/kms/snippets/verify_asymmetric_ec.py +++ b/kms/snippets/verify_asymmetric_ec.py @@ -55,7 +55,7 @@ def verify_asymmetric_ec(project_id, location_id, key_ring_id, key_id, version_i # Get the public key. public_key = client.get_public_key(request={'name': key_version_name}) - # Extract and parse the public key as a PEM-encoded RSA key. + # Extract and parse the public key as a PEM-encoded EC key. pem = public_key.pem.encode('utf-8') ec_key = serialization.load_pem_public_key(pem, default_backend()) hash_ = hashlib.sha256(message_bytes).digest() From 221607b2f8ac09b9b29e644f61c13807b9264a5c Mon Sep 17 00:00:00 2001 From: Sita Lakshmi Sangameswaran Date: Wed, 16 Feb 2022 10:40:33 +0530 Subject: [PATCH 105/136] docs(samples): updated var name to avoid shadowing built-in (#238) --- kms/snippets/create_key_asymmetric_decrypt.py | 7 ++++--- kms/snippets/create_key_asymmetric_sign.py | 7 ++++--- kms/snippets/create_key_hsm.py | 7 ++++--- kms/snippets/create_key_labels.py | 7 ++++--- kms/snippets/create_key_mac.py | 7 ++++--- kms/snippets/create_key_ring.py | 7 ++++--- kms/snippets/create_key_rotation_schedule.py | 11 ++++++----- kms/snippets/create_key_symmetric_encrypt_decrypt.py | 9 +++++---- 8 files changed, 35 insertions(+), 27 deletions(-) diff --git a/kms/snippets/create_key_asymmetric_decrypt.py b/kms/snippets/create_key_asymmetric_decrypt.py index 993d6840a2df..5d0e64a0754e 100644 --- a/kms/snippets/create_key_asymmetric_decrypt.py +++ b/kms/snippets/create_key_asymmetric_decrypt.py @@ -13,7 +13,7 @@ # [START kms_create_key_asymmetric_decrypt] -def create_key_asymmetric_decrypt(project_id, location_id, key_ring_id, id): +def create_key_asymmetric_decrypt(project_id, location_id, key_ring_id, key_id): """ Creates a new asymmetric decryption key in Cloud KMS. @@ -21,7 +21,7 @@ def create_key_asymmetric_decrypt(project_id, location_id, key_ring_id, id): project_id (string): Google Cloud project ID (e.g. 'my-project'). location_id (string): Cloud KMS location (e.g. 'us-east1'). key_ring_id (string): ID of the Cloud KMS key ring (e.g. 'my-key-ring'). - id (string): ID of the key to create (e.g. 'my-asymmetric-decrypt-key'). + key_id (string): ID of the key to create (e.g. 'my-asymmetric-decrypt-key'). Returns: CryptoKey: Cloud KMS key. @@ -54,7 +54,8 @@ def create_key_asymmetric_decrypt(project_id, location_id, key_ring_id, id): } # Call the API. - created_key = client.create_crypto_key(request={'parent': key_ring_name, 'crypto_key_id': id, 'crypto_key': key}) + created_key = client.create_crypto_key( + request={'parent': key_ring_name, 'crypto_key_id': key_id, 'crypto_key': key}) print('Created asymmetric decrypt key: {}'.format(created_key.name)) return created_key # [END kms_create_key_asymmetric_decrypt] diff --git a/kms/snippets/create_key_asymmetric_sign.py b/kms/snippets/create_key_asymmetric_sign.py index b3fbaa9e2fd2..0422508ceb21 100644 --- a/kms/snippets/create_key_asymmetric_sign.py +++ b/kms/snippets/create_key_asymmetric_sign.py @@ -13,7 +13,7 @@ # [START kms_create_key_asymmetric_sign] -def create_key_asymmetric_sign(project_id, location_id, key_ring_id, id): +def create_key_asymmetric_sign(project_id, location_id, key_ring_id, key_id): """ Creates a new asymmetric signing key in Cloud KMS. @@ -21,7 +21,7 @@ def create_key_asymmetric_sign(project_id, location_id, key_ring_id, id): project_id (string): Google Cloud project ID (e.g. 'my-project'). location_id (string): Cloud KMS location (e.g. 'us-east1'). key_ring_id (string): ID of the Cloud KMS key ring (e.g. 'my-key-ring'). - id (string): ID of the key to create (e.g. 'my-asymmetric-signing-key'). + key_id (string): ID of the key to create (e.g. 'my-asymmetric-signing-key'). Returns: CryptoKey: Cloud KMS key. @@ -54,7 +54,8 @@ def create_key_asymmetric_sign(project_id, location_id, key_ring_id, id): } # Call the API. - created_key = client.create_crypto_key(request={'parent': key_ring_name, 'crypto_key_id': id, 'crypto_key': key}) + created_key = client.create_crypto_key( + request={'parent': key_ring_name, 'crypto_key_id': key_id, 'crypto_key': key}) print('Created asymmetric signing key: {}'.format(created_key.name)) return created_key # [END kms_create_key_asymmetric_sign] diff --git a/kms/snippets/create_key_hsm.py b/kms/snippets/create_key_hsm.py index a850391a3eb7..6e95e68c9275 100644 --- a/kms/snippets/create_key_hsm.py +++ b/kms/snippets/create_key_hsm.py @@ -13,7 +13,7 @@ # [START kms_create_key_hsm] -def create_key_hsm(project_id, location_id, key_ring_id, id): +def create_key_hsm(project_id, location_id, key_ring_id, key_id): """ Creates a new key in Cloud KMS backed by Cloud HSM. @@ -21,7 +21,7 @@ def create_key_hsm(project_id, location_id, key_ring_id, id): project_id (string): Google Cloud project ID (e.g. 'my-project'). location_id (string): Cloud KMS location (e.g. 'us-east1'). key_ring_id (string): ID of the Cloud KMS key ring (e.g. 'my-key-ring'). - id (string): ID of the key to create (e.g. 'my-hsm-key'). + key_id (string): ID of the key to create (e.g. 'my-hsm-key'). Returns: CryptoKey: Cloud KMS key. @@ -56,7 +56,8 @@ def create_key_hsm(project_id, location_id, key_ring_id, id): } # Call the API. - created_key = client.create_crypto_key(request={'parent': key_ring_name, 'crypto_key_id': id, 'crypto_key': key}) + created_key = client.create_crypto_key( + request={'parent': key_ring_name, 'crypto_key_id': key_id, 'crypto_key': key}) print('Created hsm key: {}'.format(created_key.name)) return created_key # [END kms_create_key_hsm] diff --git a/kms/snippets/create_key_labels.py b/kms/snippets/create_key_labels.py index 1bef62ebfb24..cf84265a704e 100644 --- a/kms/snippets/create_key_labels.py +++ b/kms/snippets/create_key_labels.py @@ -13,7 +13,7 @@ # [START kms_create_key_labels] -def create_key_labels(project_id, location_id, key_ring_id, id): +def create_key_labels(project_id, location_id, key_ring_id, key_id): """ Creates a new key in Cloud KMS with labels. @@ -21,7 +21,7 @@ def create_key_labels(project_id, location_id, key_ring_id, id): project_id (string): Google Cloud project ID (e.g. 'my-project'). location_id (string): Cloud KMS location (e.g. 'us-east1'). key_ring_id (string): ID of the Cloud KMS key ring (e.g. 'my-key-ring'). - id (string): ID of the key to create (e.g. 'my-labeled-key'). + key_id (string): ID of the key to create (e.g. 'my-labeled-key'). Returns: CryptoKey: Cloud KMS key. @@ -52,7 +52,8 @@ def create_key_labels(project_id, location_id, key_ring_id, id): } # Call the API. - created_key = client.create_crypto_key(request={'parent': key_ring_name, 'crypto_key_id': id, 'crypto_key': key}) + created_key = client.create_crypto_key( + request={'parent': key_ring_name, 'crypto_key_id': key_id, 'crypto_key': key}) print('Created labeled key: {}'.format(created_key.name)) return created_key # [END kms_create_key_labels] diff --git a/kms/snippets/create_key_mac.py b/kms/snippets/create_key_mac.py index db8d086eded6..7c4c86755843 100644 --- a/kms/snippets/create_key_mac.py +++ b/kms/snippets/create_key_mac.py @@ -13,7 +13,7 @@ # [START kms_create_key_mac] -def create_key_mac(project_id, location_id, key_ring_id, id): +def create_key_mac(project_id, location_id, key_ring_id, key_id): """ Creates a new key in Cloud KMS for HMAC operations. @@ -21,7 +21,7 @@ def create_key_mac(project_id, location_id, key_ring_id, id): project_id (string): Google Cloud project ID (e.g. 'my-project'). location_id (string): Cloud KMS location (e.g. 'us-east1'). key_ring_id (string): ID of the Cloud KMS key ring (e.g. 'my-key-ring'). - id (string): ID of the key to create (e.g. 'my-mac-key'). + key_id (string): ID of the key to create (e.g. 'my-mac-key'). Returns: CryptoKey: Cloud KMS key. @@ -54,7 +54,8 @@ def create_key_mac(project_id, location_id, key_ring_id, id): } # Call the API. - created_key = client.create_crypto_key(request={'parent': key_ring_name, 'crypto_key_id': id, 'crypto_key': key}) + created_key = client.create_crypto_key( + request={'parent': key_ring_name, 'crypto_key_id': key_id, 'crypto_key': key}) print('Created mac key: {}'.format(created_key.name)) return created_key # [END kms_create_key_mac] diff --git a/kms/snippets/create_key_ring.py b/kms/snippets/create_key_ring.py index 49348aa9a20d..89e914e54268 100644 --- a/kms/snippets/create_key_ring.py +++ b/kms/snippets/create_key_ring.py @@ -13,14 +13,14 @@ # [START kms_create_key_ring] -def create_key_ring(project_id, location_id, id): +def create_key_ring(project_id, location_id, key_ring_id): """ Creates a new key ring in Cloud KMS Args: project_id (string): Google Cloud project ID (e.g. 'my-project'). location_id (string): Cloud KMS location (e.g. 'us-east1'). - id (string): ID of the key ring to create (e.g. 'my-key-ring'). + key_ring_id (string): ID of the key ring to create (e.g. 'my-key-ring'). Returns: KeyRing: Cloud KMS key ring. @@ -40,7 +40,8 @@ def create_key_ring(project_id, location_id, id): key_ring = {} # Call the API. - created_key_ring = client.create_key_ring(request={'parent': location_name, 'key_ring_id': id, 'key_ring': key_ring}) + created_key_ring = client.create_key_ring( + request={'parent': location_name, 'key_ring_id': key_ring_id, 'key_ring': key_ring}) print('Created key ring: {}'.format(created_key_ring.name)) return created_key_ring # [END kms_create_key_ring] diff --git a/kms/snippets/create_key_rotation_schedule.py b/kms/snippets/create_key_rotation_schedule.py index 02e323345e6f..ce450dea8334 100644 --- a/kms/snippets/create_key_rotation_schedule.py +++ b/kms/snippets/create_key_rotation_schedule.py @@ -13,7 +13,7 @@ # [START kms_create_key_rotation_schedule] -def create_key_rotation_schedule(project_id, location_id, key_ring_id, id): +def create_key_rotation_schedule(project_id, location_id, key_ring_id, key_id): """ Creates a new key in Cloud KMS that automatically rotates. @@ -21,7 +21,7 @@ def create_key_rotation_schedule(project_id, location_id, key_ring_id, id): project_id (string): Google Cloud project ID (e.g. 'my-project'). location_id (string): Cloud KMS location (e.g. 'us-east1'). key_ring_id (string): ID of the Cloud KMS key ring (e.g. 'my-key-ring'). - id (string): ID of the key to create (e.g. 'my-rotating-key'). + key_id (string): ID of the key to create (e.g. 'my-rotating-key'). Returns: CryptoKey: Cloud KMS key. @@ -51,17 +51,18 @@ def create_key_rotation_schedule(project_id, location_id, key_ring_id, id): # Rotate the key every 30 days. 'rotation_period': { - 'seconds': 60*60*24*30 + 'seconds': 60 * 60 * 24 * 30 }, # Start the first rotation in 24 hours. 'next_rotation_time': { - 'seconds': int(time.time()) + 60*60*24 + 'seconds': int(time.time()) + 60 * 60 * 24 } } # Call the API. - created_key = client.create_crypto_key(request={'parent': key_ring_name, 'crypto_key_id': id, 'crypto_key': key}) + created_key = client.create_crypto_key( + request={'parent': key_ring_name, 'crypto_key_id': key_id, 'crypto_key': key}) print('Created labeled key: {}'.format(created_key.name)) return created_key # [END kms_create_key_rotation_schedule] diff --git a/kms/snippets/create_key_symmetric_encrypt_decrypt.py b/kms/snippets/create_key_symmetric_encrypt_decrypt.py index 1b6b88c5cf50..abc4eae2b787 100644 --- a/kms/snippets/create_key_symmetric_encrypt_decrypt.py +++ b/kms/snippets/create_key_symmetric_encrypt_decrypt.py @@ -13,7 +13,7 @@ # [START kms_create_key_symmetric_encrypt_decrypt] -def create_key_symmetric_encrypt_decrypt(project_id, location_id, key_ring_id, id): +def create_key_symmetric_encrypt_decrypt(project_id, location_id, key_ring_id, key_id): """ Creates a new symmetric encryption/decryption key in Cloud KMS. @@ -21,7 +21,7 @@ def create_key_symmetric_encrypt_decrypt(project_id, location_id, key_ring_id, i project_id (string): Google Cloud project ID (e.g. 'my-project'). location_id (string): Cloud KMS location (e.g. 'us-east1'). key_ring_id (string): ID of the Cloud KMS key ring (e.g. 'my-key-ring'). - id (string): ID of the key to create (e.g. 'my-symmetric-key'). + key_id (string): ID of the key to create (e.g. 'my-symmetric-key'). Returns: CryptoKey: Cloud KMS key. @@ -43,12 +43,13 @@ def create_key_symmetric_encrypt_decrypt(project_id, location_id, key_ring_id, i key = { 'purpose': purpose, 'version_template': { - 'algorithm': algorithm, + 'algorithm': algorithm, } } # Call the API. - created_key = client.create_crypto_key(request={'parent': key_ring_name, 'crypto_key_id': id, 'crypto_key': key}) + created_key = client.create_crypto_key( + request={'parent': key_ring_name, 'crypto_key_id': key_id, 'crypto_key': key}) print('Created symmetric key: {}'.format(created_key.name)) return created_key # [END kms_create_key_symmetric_encrypt_decrypt] From c34019dc2d1f80e79e05c8c61427804b31d2c433 Mon Sep 17 00:00:00 2001 From: WhiteSource Renovate Date: Tue, 1 Mar 2022 00:07:57 +0100 Subject: [PATCH 106/136] chore(deps): update all dependencies (#234) Co-authored-by: Anthonios Partheniou --- kms/attestations/requirements-test.txt | 2 +- kms/snippets/requirements-test.txt | 2 +- kms/snippets/requirements.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/kms/attestations/requirements-test.txt b/kms/attestations/requirements-test.txt index 927094516e65..c2845bffbe89 100644 --- a/kms/attestations/requirements-test.txt +++ b/kms/attestations/requirements-test.txt @@ -1 +1 @@ -pytest==6.2.5 +pytest==7.0.1 diff --git a/kms/snippets/requirements-test.txt b/kms/snippets/requirements-test.txt index 927094516e65..c2845bffbe89 100644 --- a/kms/snippets/requirements-test.txt +++ b/kms/snippets/requirements-test.txt @@ -1 +1 @@ -pytest==6.2.5 +pytest==7.0.1 diff --git a/kms/snippets/requirements.txt b/kms/snippets/requirements.txt index e59bb1db32ce..e9c5773aab84 100644 --- a/kms/snippets/requirements.txt +++ b/kms/snippets/requirements.txt @@ -1,3 +1,3 @@ -google-cloud-kms==2.10.1 +google-cloud-kms==2.11.0 cryptography==36.0.1 crcmod==1.7 From 55042fe480174ba002d2731b0e4c64d47439ea70 Mon Sep 17 00:00:00 2001 From: "gcf-owl-bot[bot]" <78513119+gcf-owl-bot[bot]@users.noreply.github.com> Date: Fri, 4 Mar 2022 16:55:45 -0500 Subject: [PATCH 107/136] chore: Adding support for pytest-xdist and pytest-parallel (#248) Source-Link: https://github.com/googleapis/synthtool/commit/82f5cb283efffe96e1b6cd634738e0e7de2cd90a Post-Processor: gcr.io/cloud-devrel-public-resources/owlbot-python:latest@sha256:5d8da01438ece4021d135433f2cf3227aa39ef0eaccc941d62aa35e6902832ae Co-authored-by: Owl Bot Co-authored-by: Anthonios Partheniou --- kms/attestations/noxfile.py | 80 +++++++++++++++++++++---------------- kms/snippets/noxfile.py | 80 +++++++++++++++++++++---------------- 2 files changed, 92 insertions(+), 68 deletions(-) diff --git a/kms/attestations/noxfile.py b/kms/attestations/noxfile.py index 20cdfc620138..4c808af73ea2 100644 --- a/kms/attestations/noxfile.py +++ b/kms/attestations/noxfile.py @@ -188,42 +188,54 @@ def _session_tests( # check for presence of tests test_list = glob.glob("*_test.py") + glob.glob("test_*.py") test_list.extend(glob.glob("tests")) + if len(test_list) == 0: print("No tests found, skipping directory.") - else: - if TEST_CONFIG["pip_version_override"]: - pip_version = TEST_CONFIG["pip_version_override"] - session.install(f"pip=={pip_version}") - """Runs py.test for a particular project.""" - if os.path.exists("requirements.txt"): - if os.path.exists("constraints.txt"): - session.install("-r", "requirements.txt", "-c", "constraints.txt") - else: - session.install("-r", "requirements.txt") - - if os.path.exists("requirements-test.txt"): - if os.path.exists("constraints-test.txt"): - session.install( - "-r", "requirements-test.txt", "-c", "constraints-test.txt" - ) - else: - session.install("-r", "requirements-test.txt") - - if INSTALL_LIBRARY_FROM_SOURCE: - session.install("-e", _get_repo_root()) - - if post_install: - post_install(session) - - session.run( - "pytest", - *(PYTEST_COMMON_ARGS + session.posargs), - # Pytest will return 5 when no tests are collected. This can happen - # on travis where slow and flaky tests are excluded. - # See http://doc.pytest.org/en/latest/_modules/_pytest/main.html - success_codes=[0, 5], - env=get_pytest_env_vars(), - ) + return + + if TEST_CONFIG["pip_version_override"]: + pip_version = TEST_CONFIG["pip_version_override"] + session.install(f"pip=={pip_version}") + """Runs py.test for a particular project.""" + concurrent_args = [] + if os.path.exists("requirements.txt"): + if os.path.exists("constraints.txt"): + session.install("-r", "requirements.txt", "-c", "constraints.txt") + else: + session.install("-r", "requirements.txt") + with open("requirements.txt") as rfile: + packages = rfile.read() + + if os.path.exists("requirements-test.txt"): + if os.path.exists("constraints-test.txt"): + session.install( + "-r", "requirements-test.txt", "-c", "constraints-test.txt" + ) + else: + session.install("-r", "requirements-test.txt") + with open("requirements-test.txt") as rtfile: + packages += rtfile.read() + + if INSTALL_LIBRARY_FROM_SOURCE: + session.install("-e", _get_repo_root()) + + if post_install: + post_install(session) + + if "pytest-parallel" in packages: + concurrent_args.extend(['--workers', 'auto', '--tests-per-worker', 'auto']) + elif "pytest-xdist" in packages: + concurrent_args.extend(['-n', 'auto']) + + session.run( + "pytest", + *(PYTEST_COMMON_ARGS + session.posargs + concurrent_args), + # Pytest will return 5 when no tests are collected. This can happen + # on travis where slow and flaky tests are excluded. + # See http://doc.pytest.org/en/latest/_modules/_pytest/main.html + success_codes=[0, 5], + env=get_pytest_env_vars(), + ) @nox.session(python=ALL_VERSIONS) diff --git a/kms/snippets/noxfile.py b/kms/snippets/noxfile.py index 20cdfc620138..4c808af73ea2 100644 --- a/kms/snippets/noxfile.py +++ b/kms/snippets/noxfile.py @@ -188,42 +188,54 @@ def _session_tests( # check for presence of tests test_list = glob.glob("*_test.py") + glob.glob("test_*.py") test_list.extend(glob.glob("tests")) + if len(test_list) == 0: print("No tests found, skipping directory.") - else: - if TEST_CONFIG["pip_version_override"]: - pip_version = TEST_CONFIG["pip_version_override"] - session.install(f"pip=={pip_version}") - """Runs py.test for a particular project.""" - if os.path.exists("requirements.txt"): - if os.path.exists("constraints.txt"): - session.install("-r", "requirements.txt", "-c", "constraints.txt") - else: - session.install("-r", "requirements.txt") - - if os.path.exists("requirements-test.txt"): - if os.path.exists("constraints-test.txt"): - session.install( - "-r", "requirements-test.txt", "-c", "constraints-test.txt" - ) - else: - session.install("-r", "requirements-test.txt") - - if INSTALL_LIBRARY_FROM_SOURCE: - session.install("-e", _get_repo_root()) - - if post_install: - post_install(session) - - session.run( - "pytest", - *(PYTEST_COMMON_ARGS + session.posargs), - # Pytest will return 5 when no tests are collected. This can happen - # on travis where slow and flaky tests are excluded. - # See http://doc.pytest.org/en/latest/_modules/_pytest/main.html - success_codes=[0, 5], - env=get_pytest_env_vars(), - ) + return + + if TEST_CONFIG["pip_version_override"]: + pip_version = TEST_CONFIG["pip_version_override"] + session.install(f"pip=={pip_version}") + """Runs py.test for a particular project.""" + concurrent_args = [] + if os.path.exists("requirements.txt"): + if os.path.exists("constraints.txt"): + session.install("-r", "requirements.txt", "-c", "constraints.txt") + else: + session.install("-r", "requirements.txt") + with open("requirements.txt") as rfile: + packages = rfile.read() + + if os.path.exists("requirements-test.txt"): + if os.path.exists("constraints-test.txt"): + session.install( + "-r", "requirements-test.txt", "-c", "constraints-test.txt" + ) + else: + session.install("-r", "requirements-test.txt") + with open("requirements-test.txt") as rtfile: + packages += rtfile.read() + + if INSTALL_LIBRARY_FROM_SOURCE: + session.install("-e", _get_repo_root()) + + if post_install: + post_install(session) + + if "pytest-parallel" in packages: + concurrent_args.extend(['--workers', 'auto', '--tests-per-worker', 'auto']) + elif "pytest-xdist" in packages: + concurrent_args.extend(['-n', 'auto']) + + session.run( + "pytest", + *(PYTEST_COMMON_ARGS + session.posargs + concurrent_args), + # Pytest will return 5 when no tests are collected. This can happen + # on travis where slow and flaky tests are excluded. + # See http://doc.pytest.org/en/latest/_modules/_pytest/main.html + success_codes=[0, 5], + env=get_pytest_env_vars(), + ) @nox.session(python=ALL_VERSIONS) From c943350e263df665322578d3906b8036d51b4f93 Mon Sep 17 00:00:00 2001 From: WhiteSource Renovate Date: Tue, 8 Mar 2022 02:02:01 +0100 Subject: [PATCH 108/136] chore(deps): update dependency google-cloud-kms to v2.11.1 (#250) --- kms/snippets/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kms/snippets/requirements.txt b/kms/snippets/requirements.txt index e9c5773aab84..08d5a50687e7 100644 --- a/kms/snippets/requirements.txt +++ b/kms/snippets/requirements.txt @@ -1,3 +1,3 @@ -google-cloud-kms==2.11.0 +google-cloud-kms==2.11.1 cryptography==36.0.1 crcmod==1.7 From 4d1ac920ac8d3c85e4c0c7bd7e8c857da7d2fd4d Mon Sep 17 00:00:00 2001 From: WhiteSource Renovate Date: Sun, 13 Mar 2022 23:11:56 +0100 Subject: [PATCH 109/136] chore(deps): update dependency pytest to v7.1.0 (#252) --- kms/attestations/requirements-test.txt | 2 +- kms/snippets/requirements-test.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/kms/attestations/requirements-test.txt b/kms/attestations/requirements-test.txt index c2845bffbe89..824a8a7a0ce6 100644 --- a/kms/attestations/requirements-test.txt +++ b/kms/attestations/requirements-test.txt @@ -1 +1 @@ -pytest==7.0.1 +pytest==7.1.0 diff --git a/kms/snippets/requirements-test.txt b/kms/snippets/requirements-test.txt index c2845bffbe89..824a8a7a0ce6 100644 --- a/kms/snippets/requirements-test.txt +++ b/kms/snippets/requirements-test.txt @@ -1 +1 @@ -pytest==7.0.1 +pytest==7.1.0 From 7b81f6ab3130bd8a62c961a56df20ec2691d5225 Mon Sep 17 00:00:00 2001 From: WhiteSource Renovate Date: Sat, 19 Mar 2022 11:14:16 +0100 Subject: [PATCH 110/136] chore(deps): update all dependencies (#253) --- kms/attestations/requirements-test.txt | 2 +- kms/attestations/requirements.txt | 2 +- kms/snippets/requirements-test.txt | 2 +- kms/snippets/requirements.txt | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/kms/attestations/requirements-test.txt b/kms/attestations/requirements-test.txt index 824a8a7a0ce6..4f6bf643fc5e 100644 --- a/kms/attestations/requirements-test.txt +++ b/kms/attestations/requirements-test.txt @@ -1 +1 @@ -pytest==7.1.0 +pytest==7.1.1 diff --git a/kms/attestations/requirements.txt b/kms/attestations/requirements.txt index 86e5361ffdb2..57be798d4266 100644 --- a/kms/attestations/requirements.txt +++ b/kms/attestations/requirements.txt @@ -1,2 +1,2 @@ -cryptography==36.0.1 +cryptography==36.0.2 pem==21.2.0 diff --git a/kms/snippets/requirements-test.txt b/kms/snippets/requirements-test.txt index 824a8a7a0ce6..4f6bf643fc5e 100644 --- a/kms/snippets/requirements-test.txt +++ b/kms/snippets/requirements-test.txt @@ -1 +1 @@ -pytest==7.1.0 +pytest==7.1.1 diff --git a/kms/snippets/requirements.txt b/kms/snippets/requirements.txt index 08d5a50687e7..e19dbdb95ce0 100644 --- a/kms/snippets/requirements.txt +++ b/kms/snippets/requirements.txt @@ -1,3 +1,3 @@ google-cloud-kms==2.11.1 -cryptography==36.0.1 +cryptography==36.0.2 crcmod==1.7 From 077451514fe8a6308bcbe16cac46893ceffa719b Mon Sep 17 00:00:00 2001 From: "gcf-owl-bot[bot]" <78513119+gcf-owl-bot[bot]@users.noreply.github.com> Date: Tue, 29 Mar 2022 00:02:19 +0000 Subject: [PATCH 111/136] chore(python): use black==22.3.0 (#256) Source-Link: https://github.com/googleapis/synthtool/commit/6fab84af09f2cf89a031fd8671d1def6b2931b11 Post-Processor: gcr.io/cloud-devrel-public-resources/owlbot-python:latest@sha256:7cffbc10910c3ab1b852c05114a08d374c195a81cdec1d4a67a1d129331d0bfe --- kms/attestations/noxfile.py | 2 +- kms/snippets/noxfile.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/kms/attestations/noxfile.py b/kms/attestations/noxfile.py index 4c808af73ea2..949e0fde9ae1 100644 --- a/kms/attestations/noxfile.py +++ b/kms/attestations/noxfile.py @@ -29,7 +29,7 @@ # WARNING - WARNING - WARNING - WARNING - WARNING # WARNING - WARNING - WARNING - WARNING - WARNING -BLACK_VERSION = "black==19.10b0" +BLACK_VERSION = "black==22.3.0" # Copy `noxfile_config.py` to your directory and modify it instead. diff --git a/kms/snippets/noxfile.py b/kms/snippets/noxfile.py index 4c808af73ea2..949e0fde9ae1 100644 --- a/kms/snippets/noxfile.py +++ b/kms/snippets/noxfile.py @@ -29,7 +29,7 @@ # WARNING - WARNING - WARNING - WARNING - WARNING # WARNING - WARNING - WARNING - WARNING - WARNING -BLACK_VERSION = "black==19.10b0" +BLACK_VERSION = "black==22.3.0" # Copy `noxfile_config.py` to your directory and modify it instead. From 62646ba5ebef22cc50f10e91d6903cb596f9521f Mon Sep 17 00:00:00 2001 From: "gcf-owl-bot[bot]" <78513119+gcf-owl-bot[bot]@users.noreply.github.com> Date: Wed, 20 Apr 2022 20:51:14 -0400 Subject: [PATCH 112/136] chore(python): add nox session to sort python imports (#267) Source-Link: https://github.com/googleapis/synthtool/commit/1b71c10e20de7ed3f97f692f99a0e3399b67049f Post-Processor: gcr.io/cloud-devrel-public-resources/owlbot-python:latest@sha256:00c9d764fd1cd56265f12a5ef4b99a0c9e87cf261018099141e2ca5158890416 Co-authored-by: Owl Bot --- kms/attestations/noxfile.py | 21 +++++++++++++++++++++ kms/snippets/noxfile.py | 21 +++++++++++++++++++++ 2 files changed, 42 insertions(+) diff --git a/kms/attestations/noxfile.py b/kms/attestations/noxfile.py index 949e0fde9ae1..38bb0a572b81 100644 --- a/kms/attestations/noxfile.py +++ b/kms/attestations/noxfile.py @@ -30,6 +30,7 @@ # WARNING - WARNING - WARNING - WARNING - WARNING BLACK_VERSION = "black==22.3.0" +ISORT_VERSION = "isort==5.10.1" # Copy `noxfile_config.py` to your directory and modify it instead. @@ -168,12 +169,32 @@ def lint(session: nox.sessions.Session) -> None: @nox.session def blacken(session: nox.sessions.Session) -> None: + """Run black. Format code to uniform standard.""" session.install(BLACK_VERSION) python_files = [path for path in os.listdir(".") if path.endswith(".py")] session.run("black", *python_files) +# +# format = isort + black +# + +@nox.session +def format(session: nox.sessions.Session) -> None: + """ + Run isort to sort imports. Then run black + to format code to uniform standard. + """ + session.install(BLACK_VERSION, ISORT_VERSION) + python_files = [path for path in os.listdir(".") if path.endswith(".py")] + + # Use the --fss option to sort imports using strict alphabetical order. + # See https://pycqa.github.io/isort/docs/configuration/options.html#force-sort-within-sections + session.run("isort", "--fss", *python_files) + session.run("black", *python_files) + + # # Sample Tests # diff --git a/kms/snippets/noxfile.py b/kms/snippets/noxfile.py index 949e0fde9ae1..38bb0a572b81 100644 --- a/kms/snippets/noxfile.py +++ b/kms/snippets/noxfile.py @@ -30,6 +30,7 @@ # WARNING - WARNING - WARNING - WARNING - WARNING BLACK_VERSION = "black==22.3.0" +ISORT_VERSION = "isort==5.10.1" # Copy `noxfile_config.py` to your directory and modify it instead. @@ -168,12 +169,32 @@ def lint(session: nox.sessions.Session) -> None: @nox.session def blacken(session: nox.sessions.Session) -> None: + """Run black. Format code to uniform standard.""" session.install(BLACK_VERSION) python_files = [path for path in os.listdir(".") if path.endswith(".py")] session.run("black", *python_files) +# +# format = isort + black +# + +@nox.session +def format(session: nox.sessions.Session) -> None: + """ + Run isort to sort imports. Then run black + to format code to uniform standard. + """ + session.install(BLACK_VERSION, ISORT_VERSION) + python_files = [path for path in os.listdir(".") if path.endswith(".py")] + + # Use the --fss option to sort imports using strict alphabetical order. + # See https://pycqa.github.io/isort/docs/configuration/options.html#force-sort-within-sections + session.run("isort", "--fss", *python_files) + session.run("black", *python_files) + + # # Sample Tests # From 4589f95f55540107753ac4a209a905ab1aea2c7b Mon Sep 17 00:00:00 2001 From: WhiteSource Renovate Date: Mon, 25 Apr 2022 17:17:31 +0200 Subject: [PATCH 113/136] chore(deps): update dependency pytest to v7.1.2 (#270) --- kms/attestations/requirements-test.txt | 2 +- kms/snippets/requirements-test.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/kms/attestations/requirements-test.txt b/kms/attestations/requirements-test.txt index 4f6bf643fc5e..d00689e0623a 100644 --- a/kms/attestations/requirements-test.txt +++ b/kms/attestations/requirements-test.txt @@ -1 +1 @@ -pytest==7.1.1 +pytest==7.1.2 diff --git a/kms/snippets/requirements-test.txt b/kms/snippets/requirements-test.txt index 4f6bf643fc5e..d00689e0623a 100644 --- a/kms/snippets/requirements-test.txt +++ b/kms/snippets/requirements-test.txt @@ -1 +1 @@ -pytest==7.1.1 +pytest==7.1.2 From d52681bda415e46c49976a651c657229f773ee8f Mon Sep 17 00:00:00 2001 From: WhiteSource Renovate Date: Tue, 26 Apr 2022 18:00:52 +0200 Subject: [PATCH 114/136] chore(deps): update dependency cryptography to v37 (#271) --- kms/attestations/requirements.txt | 2 +- kms/snippets/requirements.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/kms/attestations/requirements.txt b/kms/attestations/requirements.txt index 57be798d4266..61f3d69baba0 100644 --- a/kms/attestations/requirements.txt +++ b/kms/attestations/requirements.txt @@ -1,2 +1,2 @@ -cryptography==36.0.2 +cryptography==37.0.0 pem==21.2.0 diff --git a/kms/snippets/requirements.txt b/kms/snippets/requirements.txt index e19dbdb95ce0..3125f9c3d644 100644 --- a/kms/snippets/requirements.txt +++ b/kms/snippets/requirements.txt @@ -1,3 +1,3 @@ google-cloud-kms==2.11.1 -cryptography==36.0.2 +cryptography==37.0.0 crcmod==1.7 From e897dade4184b58b65228c821f983b8680b52c83 Mon Sep 17 00:00:00 2001 From: WhiteSource Renovate Date: Thu, 28 Apr 2022 13:20:45 +0200 Subject: [PATCH 115/136] chore(deps): update dependency cryptography to v37.0.1 (#273) --- kms/attestations/requirements.txt | 2 +- kms/snippets/requirements.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/kms/attestations/requirements.txt b/kms/attestations/requirements.txt index 61f3d69baba0..8af689331424 100644 --- a/kms/attestations/requirements.txt +++ b/kms/attestations/requirements.txt @@ -1,2 +1,2 @@ -cryptography==37.0.0 +cryptography==37.0.1 pem==21.2.0 diff --git a/kms/snippets/requirements.txt b/kms/snippets/requirements.txt index 3125f9c3d644..80bd3fba2062 100644 --- a/kms/snippets/requirements.txt +++ b/kms/snippets/requirements.txt @@ -1,3 +1,3 @@ google-cloud-kms==2.11.1 -cryptography==37.0.0 +cryptography==37.0.1 crcmod==1.7 From 1ae0ad372ca1c81bf1806ce2542a16c84ddd6a43 Mon Sep 17 00:00:00 2001 From: WhiteSource Renovate Date: Thu, 5 May 2022 02:43:45 +0200 Subject: [PATCH 116/136] chore(deps): update dependency cryptography to v37.0.2 (#274) --- kms/attestations/requirements.txt | 2 +- kms/snippets/requirements.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/kms/attestations/requirements.txt b/kms/attestations/requirements.txt index 8af689331424..db98eb48bb22 100644 --- a/kms/attestations/requirements.txt +++ b/kms/attestations/requirements.txt @@ -1,2 +1,2 @@ -cryptography==37.0.1 +cryptography==37.0.2 pem==21.2.0 diff --git a/kms/snippets/requirements.txt b/kms/snippets/requirements.txt index 80bd3fba2062..b9cee652f95c 100644 --- a/kms/snippets/requirements.txt +++ b/kms/snippets/requirements.txt @@ -1,3 +1,3 @@ google-cloud-kms==2.11.1 -cryptography==37.0.1 +cryptography==37.0.2 crcmod==1.7 From f392f41241e95720041b4060f57985f2a00edf84 Mon Sep 17 00:00:00 2001 From: "gcf-owl-bot[bot]" <78513119+gcf-owl-bot[bot]@users.noreply.github.com> Date: Thu, 7 Jul 2022 12:04:49 -0400 Subject: [PATCH 117/136] fix: require python 3.7+ (#313) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * chore(python): drop python 3.6 Source-Link: https://github.com/googleapis/synthtool/commit/4f89b13af10d086458f9b379e56a614f9d6dab7b Post-Processor: gcr.io/cloud-devrel-public-resources/owlbot-python:latest@sha256:e7bb19d47c13839fe8c147e50e02e8b6cf5da8edd1af8b82208cd6f66cc2829c * add api_description to .repo-metadata.json * require python 3.7+ in setup.py * remove python 3.6 sample configs * 🦉 Updates from OwlBot post-processor See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md Co-authored-by: Owl Bot Co-authored-by: Anthonios Partheniou --- kms/attestations/noxfile.py | 2 +- kms/snippets/noxfile.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/kms/attestations/noxfile.py b/kms/attestations/noxfile.py index 38bb0a572b81..5fcb9d7461f2 100644 --- a/kms/attestations/noxfile.py +++ b/kms/attestations/noxfile.py @@ -89,7 +89,7 @@ def get_pytest_env_vars() -> Dict[str, str]: # DO NOT EDIT - automatically generated. # All versions used to test samples. -ALL_VERSIONS = ["3.6", "3.7", "3.8", "3.9", "3.10"] +ALL_VERSIONS = ["3.7", "3.8", "3.9", "3.10"] # Any default versions that should be ignored. IGNORED_VERSIONS = TEST_CONFIG["ignored_versions"] diff --git a/kms/snippets/noxfile.py b/kms/snippets/noxfile.py index 38bb0a572b81..5fcb9d7461f2 100644 --- a/kms/snippets/noxfile.py +++ b/kms/snippets/noxfile.py @@ -89,7 +89,7 @@ def get_pytest_env_vars() -> Dict[str, str]: # DO NOT EDIT - automatically generated. # All versions used to test samples. -ALL_VERSIONS = ["3.6", "3.7", "3.8", "3.9", "3.10"] +ALL_VERSIONS = ["3.7", "3.8", "3.9", "3.10"] # Any default versions that should be ignored. IGNORED_VERSIONS = TEST_CONFIG["ignored_versions"] From d5a2f11ce9b10962b9e43f4c7bfe9e76f8135659 Mon Sep 17 00:00:00 2001 From: WhiteSource Renovate Date: Tue, 12 Jul 2022 17:35:50 +0200 Subject: [PATCH 118/136] chore(deps): update all dependencies (#303) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * chore(deps): update all dependencies * 🦉 Updates from OwlBot post-processor See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md * revert Co-authored-by: Owl Bot Co-authored-by: Anthonios Partheniou --- kms/snippets/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kms/snippets/requirements.txt b/kms/snippets/requirements.txt index b9cee652f95c..c135b5121b20 100644 --- a/kms/snippets/requirements.txt +++ b/kms/snippets/requirements.txt @@ -1,3 +1,3 @@ -google-cloud-kms==2.11.1 +google-cloud-kms==2.11.2 cryptography==37.0.2 crcmod==1.7 From a91c0cf6c33d740f8830a314d22563d6931bd89d Mon Sep 17 00:00:00 2001 From: WhiteSource Renovate Date: Tue, 2 Aug 2022 16:08:04 +0200 Subject: [PATCH 119/136] chore(deps): update all dependencies (#319) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * chore(deps): update all dependencies * 🦉 Updates from OwlBot post-processor See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md * revert Co-authored-by: Owl Bot Co-authored-by: Anthonios Partheniou --- kms/attestations/requirements.txt | 2 +- kms/snippets/requirements.txt | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/kms/attestations/requirements.txt b/kms/attestations/requirements.txt index db98eb48bb22..4e32d02c3dd3 100644 --- a/kms/attestations/requirements.txt +++ b/kms/attestations/requirements.txt @@ -1,2 +1,2 @@ -cryptography==37.0.2 +cryptography==37.0.4 pem==21.2.0 diff --git a/kms/snippets/requirements.txt b/kms/snippets/requirements.txt index c135b5121b20..a9ffeb7df15f 100644 --- a/kms/snippets/requirements.txt +++ b/kms/snippets/requirements.txt @@ -1,3 +1,3 @@ -google-cloud-kms==2.11.2 -cryptography==37.0.2 +google-cloud-kms==2.12.0 +cryptography==37.0.4 crcmod==1.7 From 955d67e232271d1d3aab368bc6c0e7f17ba18bf6 Mon Sep 17 00:00:00 2001 From: WhiteSource Renovate Date: Fri, 19 Aug 2022 18:35:10 +0200 Subject: [PATCH 120/136] chore(deps): update dependency google-cloud-kms to v2.12.1 (#326) --- kms/snippets/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kms/snippets/requirements.txt b/kms/snippets/requirements.txt index a9ffeb7df15f..9e64e9ade459 100644 --- a/kms/snippets/requirements.txt +++ b/kms/snippets/requirements.txt @@ -1,3 +1,3 @@ -google-cloud-kms==2.12.0 +google-cloud-kms==2.12.1 cryptography==37.0.4 crcmod==1.7 From f9e23a08c8aa5446a023da854bcb49d4d2c13f97 Mon Sep 17 00:00:00 2001 From: WhiteSource Renovate Date: Tue, 6 Sep 2022 18:14:30 +0200 Subject: [PATCH 121/136] chore(deps): update dependency pytest to v7.1.3 (#338) --- kms/attestations/requirements-test.txt | 2 +- kms/snippets/requirements-test.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/kms/attestations/requirements-test.txt b/kms/attestations/requirements-test.txt index d00689e0623a..e07168502ea9 100644 --- a/kms/attestations/requirements-test.txt +++ b/kms/attestations/requirements-test.txt @@ -1 +1 @@ -pytest==7.1.2 +pytest==7.1.3 diff --git a/kms/snippets/requirements-test.txt b/kms/snippets/requirements-test.txt index d00689e0623a..e07168502ea9 100644 --- a/kms/snippets/requirements-test.txt +++ b/kms/snippets/requirements-test.txt @@ -1 +1 @@ -pytest==7.1.2 +pytest==7.1.3 From ba0fe230dbe5d567da713a4bfef00225344d8780 Mon Sep 17 00:00:00 2001 From: WhiteSource Renovate Date: Wed, 7 Sep 2022 15:44:23 +0200 Subject: [PATCH 122/136] chore(deps): update dependency cryptography to v38 (#339) --- kms/attestations/requirements.txt | 2 +- kms/snippets/requirements.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/kms/attestations/requirements.txt b/kms/attestations/requirements.txt index 4e32d02c3dd3..fe31154378ee 100644 --- a/kms/attestations/requirements.txt +++ b/kms/attestations/requirements.txt @@ -1,2 +1,2 @@ -cryptography==37.0.4 +cryptography==38.0.0 pem==21.2.0 diff --git a/kms/snippets/requirements.txt b/kms/snippets/requirements.txt index 9e64e9ade459..911f106acd95 100644 --- a/kms/snippets/requirements.txt +++ b/kms/snippets/requirements.txt @@ -1,3 +1,3 @@ google-cloud-kms==2.12.1 -cryptography==37.0.4 +cryptography==38.0.0 crcmod==1.7 From 040450deba6d1026f9d9a97472e0fc2246304b1c Mon Sep 17 00:00:00 2001 From: WhiteSource Renovate Date: Wed, 7 Sep 2022 16:44:46 +0200 Subject: [PATCH 123/136] chore(deps): update dependency cryptography to v38.0.1 (#341) --- kms/attestations/requirements.txt | 2 +- kms/snippets/requirements.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/kms/attestations/requirements.txt b/kms/attestations/requirements.txt index fe31154378ee..0ed3ae6b375b 100644 --- a/kms/attestations/requirements.txt +++ b/kms/attestations/requirements.txt @@ -1,2 +1,2 @@ -cryptography==38.0.0 +cryptography==38.0.1 pem==21.2.0 diff --git a/kms/snippets/requirements.txt b/kms/snippets/requirements.txt index 911f106acd95..b67ae931633e 100644 --- a/kms/snippets/requirements.txt +++ b/kms/snippets/requirements.txt @@ -1,3 +1,3 @@ google-cloud-kms==2.12.1 -cryptography==38.0.0 +cryptography==38.0.1 crcmod==1.7 From 181e085003e55a4b42b09ed747c98b489eb8955a Mon Sep 17 00:00:00 2001 From: "gcf-owl-bot[bot]" <78513119+gcf-owl-bot[bot]@users.noreply.github.com> Date: Tue, 13 Sep 2022 16:22:22 +0000 Subject: [PATCH 124/136] chore: detect samples tests in nested directories (#345) Source-Link: https://github.com/googleapis/synthtool/commit/50db768f450a50d7c1fd62513c113c9bb96fd434 Post-Processor: gcr.io/cloud-devrel-public-resources/owlbot-python:latest@sha256:e09366bdf0fd9c8976592988390b24d53583dd9f002d476934da43725adbb978 --- kms/attestations/noxfile.py | 4 ++-- kms/snippets/noxfile.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/kms/attestations/noxfile.py b/kms/attestations/noxfile.py index 5fcb9d7461f2..0398d72ff690 100644 --- a/kms/attestations/noxfile.py +++ b/kms/attestations/noxfile.py @@ -207,8 +207,8 @@ def _session_tests( session: nox.sessions.Session, post_install: Callable = None ) -> None: # check for presence of tests - test_list = glob.glob("*_test.py") + glob.glob("test_*.py") - test_list.extend(glob.glob("tests")) + test_list = glob.glob("**/*_test.py", recursive=True) + glob.glob("**/test_*.py", recursive=True) + test_list.extend(glob.glob("**/tests", recursive=True)) if len(test_list) == 0: print("No tests found, skipping directory.") diff --git a/kms/snippets/noxfile.py b/kms/snippets/noxfile.py index 5fcb9d7461f2..0398d72ff690 100644 --- a/kms/snippets/noxfile.py +++ b/kms/snippets/noxfile.py @@ -207,8 +207,8 @@ def _session_tests( session: nox.sessions.Session, post_install: Callable = None ) -> None: # check for presence of tests - test_list = glob.glob("*_test.py") + glob.glob("test_*.py") - test_list.extend(glob.glob("tests")) + test_list = glob.glob("**/*_test.py", recursive=True) + glob.glob("**/test_*.py", recursive=True) + test_list.extend(glob.glob("**/tests", recursive=True)) if len(test_list) == 0: print("No tests found, skipping directory.") From 74d51f2be34480a87207491b20a28a825de985a1 Mon Sep 17 00:00:00 2001 From: WhiteSource Renovate Date: Tue, 4 Oct 2022 15:44:35 +0200 Subject: [PATCH 125/136] chore(deps): update dependency google-cloud-kms to v2.12.2 (#349) --- kms/snippets/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kms/snippets/requirements.txt b/kms/snippets/requirements.txt index b67ae931633e..78ea091148ac 100644 --- a/kms/snippets/requirements.txt +++ b/kms/snippets/requirements.txt @@ -1,3 +1,3 @@ -google-cloud-kms==2.12.1 +google-cloud-kms==2.12.2 cryptography==38.0.1 crcmod==1.7 From b9d6082787f7b75213e352bb16318f1da5950bd0 Mon Sep 17 00:00:00 2001 From: WhiteSource Renovate Date: Tue, 18 Oct 2022 15:17:40 +0200 Subject: [PATCH 126/136] chore(deps): update all dependencies (#352) --- kms/attestations/requirements.txt | 2 +- kms/snippets/requirements.txt | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/kms/attestations/requirements.txt b/kms/attestations/requirements.txt index 0ed3ae6b375b..668c0b584326 100644 --- a/kms/attestations/requirements.txt +++ b/kms/attestations/requirements.txt @@ -1,2 +1,2 @@ -cryptography==38.0.1 +cryptography==38.0.2 pem==21.2.0 diff --git a/kms/snippets/requirements.txt b/kms/snippets/requirements.txt index 78ea091148ac..2dbb88fd37d0 100644 --- a/kms/snippets/requirements.txt +++ b/kms/snippets/requirements.txt @@ -1,3 +1,3 @@ -google-cloud-kms==2.12.2 -cryptography==38.0.1 +google-cloud-kms==2.12.3 +cryptography==38.0.2 crcmod==1.7 From e1e35bf8af37b3d85a2214d2b2384a9ee47d8cc0 Mon Sep 17 00:00:00 2001 From: WhiteSource Renovate Date: Wed, 26 Oct 2022 12:55:21 +0200 Subject: [PATCH 127/136] chore(deps): update dependency pytest to v7.2.0 (#353) --- kms/attestations/requirements-test.txt | 2 +- kms/snippets/requirements-test.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/kms/attestations/requirements-test.txt b/kms/attestations/requirements-test.txt index e07168502ea9..49780e035690 100644 --- a/kms/attestations/requirements-test.txt +++ b/kms/attestations/requirements-test.txt @@ -1 +1 @@ -pytest==7.1.3 +pytest==7.2.0 diff --git a/kms/snippets/requirements-test.txt b/kms/snippets/requirements-test.txt index e07168502ea9..49780e035690 100644 --- a/kms/snippets/requirements-test.txt +++ b/kms/snippets/requirements-test.txt @@ -1 +1 @@ -pytest==7.1.3 +pytest==7.2.0 From 40dfca1a3d21f73a3a2452808c1074d38a556bd6 Mon Sep 17 00:00:00 2001 From: rsamborski Date: Tue, 8 Nov 2022 16:10:11 +0100 Subject: [PATCH 128/136] Updates to READMEs and CODEOWNERS --- .github/CODEOWNERS | 1 + kms/README.rst | 3 --- kms/attestations/README.rst | 8 ++++---- kms/snippets/README.md | 4 ++-- 4 files changed, 7 insertions(+), 9 deletions(-) delete mode 100644 kms/README.rst diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 5cf115a2a35e..fc5ded97e8c2 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -69,3 +69,4 @@ /trace/**/* @ymotongpoo @GoogleCloudPlatform/python-samples-reviewers /translate/**/* @nicain @GoogleCloudPlatform/python-samples-reviewers /workflows/**/* @GoogleCloudPlatform/python-samples-reviewers +/kms/**/** @GoogleCloudPlatform/dee-infra @GoogleCloudPlatform/python-samples-reviewers \ No newline at end of file diff --git a/kms/README.rst b/kms/README.rst deleted file mode 100644 index 63f6e5c37482..000000000000 --- a/kms/README.rst +++ /dev/null @@ -1,3 +0,0 @@ -These samples have been moved. - -https://github.com/googleapis/python-kms/tree/main/samples diff --git a/kms/attestations/README.rst b/kms/attestations/README.rst index de84a1537b37..0dce20a99c4e 100644 --- a/kms/attestations/README.rst +++ b/kms/attestations/README.rst @@ -2,7 +2,7 @@ Google Cloud Key Management Service Python Samples =============================================================================== .. image:: https://gstatic.com/cloudssh/images/open-btn.png - :target: https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/python-kms&page=editor&open_in_editor=samples/attestations/README.rst + :target: https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/GoogleCloudPlatform/python-docs-samples&page=editor&open_in_editor=kms/attestations/README.rst This directory contains samples for Google Cloud Key Management Service. The `Cloud Key Management Service`_ allows you to create, import, and manage cryptographic keys and perform cryptographic operations in a single centralized cloud service. @@ -27,7 +27,7 @@ Install Dependencies .. code-block:: bash - $ git clone https://github.com/googleapis/python-kms.git + $ git clone https://github.com/GoogleCloudPlatform/python-docs-samples.git #. Install `pip`_ and `virtualenv`_ if you do not already have them. You may want to refer to the `Python Development Environment Setup Guide`_ for Google Cloud Platform for instructions. @@ -57,7 +57,7 @@ Verify attestations and certificate chains for keys generated by Cloud HSM +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ .. image:: https://gstatic.com/cloudssh/images/open-btn.png - :target: https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/python-kms&page=editor&open_in_editor=samples/attestations/verify_attestation_chains.py,samples/attestations/README.rst + :target: https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/GoogleCloudPlatform/python-docs-samples&page=editor&open_in_editor=kms/attestations/verify_attestation_chains.py,kms/attestations/README.rst @@ -89,7 +89,7 @@ Verify attestations for keys generated by Cloud HSM +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ .. image:: https://gstatic.com/cloudssh/images/open-btn.png - :target: https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/python-kms&page=editor&open_in_editor=samples/attestations/verify_attestation.py,samples/attestations/README.rst + :target: https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/GoogleCloudPlatform/python-docs-samples&page=editor&open_in_editor=kms/attestations/verify_attestation.py,kms/attestations/README.rst diff --git a/kms/snippets/README.md b/kms/snippets/README.md index 4056cf8a9338..503f62c91e60 100644 --- a/kms/snippets/README.md +++ b/kms/snippets/README.md @@ -13,7 +13,7 @@ Samples, quickstarts, and other documentation are available at Open in Cloud Shell +Open in Cloud Shell To run this sample: @@ -38,7 +38,7 @@ More information about the Cloud KMS quickstart is available at https://cloud.go These samples use the [Google Cloud Client Library for Python][client_library_python]. You can read the documentation for more details on API usage and use GitHub -to browse the source and [report issues][issues]. +to browse the source and [report issues][issues]. ### Contributing View the [contributing guidelines][contrib_guide], the [Python style guide][py_style] for more information. From 81dd63a4c68721f75b0fb5adaa310664764155f2 Mon Sep 17 00:00:00 2001 From: rsamborski Date: Tue, 8 Nov 2022 23:12:54 +0100 Subject: [PATCH 129/136] Update requirements.txt to include requests module --- kms/attestations/requirements.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/kms/attestations/requirements.txt b/kms/attestations/requirements.txt index 668c0b584326..cf5cffd011cf 100644 --- a/kms/attestations/requirements.txt +++ b/kms/attestations/requirements.txt @@ -1,2 +1,3 @@ cryptography==38.0.2 pem==21.2.0 +requests==2.28.1 \ No newline at end of file From 73b0204081e8fda59f0a4a854fb2000788c5f351 Mon Sep 17 00:00:00 2001 From: rsamborski Date: Tue, 8 Nov 2022 23:41:01 +0100 Subject: [PATCH 130/136] License header updates and region tag rename --- kms/attestations/verify_attestation.py | 6 +++--- kms/attestations/verify_attestation_chains.py | 2 +- kms/attestations/verify_attestation_chains_test.py | 2 +- kms/attestations/verify_attestation_test.py | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/kms/attestations/verify_attestation.py b/kms/attestations/verify_attestation.py index 090f6b81874e..d56242b0194b 100644 --- a/kms/attestations/verify_attestation.py +++ b/kms/attestations/verify_attestation.py @@ -1,6 +1,6 @@ #!/usr/bin/env python -# Copyright 2020 Google, LLC. +# Copyright 2020 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -20,7 +20,7 @@ For more information, visit https://cloud.google.com/kms/docs/attest-key. """ -# [START verify_attestations] +# [START kms_verify_attestations] import argparse import gzip @@ -69,7 +69,7 @@ def verify(attestation_file, bundle_file): # errors can be ignored. continue return False -# [END verify_attestations] +# [END kms_verify_attestations] if __name__ == '__main__': diff --git a/kms/attestations/verify_attestation_chains.py b/kms/attestations/verify_attestation_chains.py index 3fddd8600973..d50173dbe07d 100644 --- a/kms/attestations/verify_attestation_chains.py +++ b/kms/attestations/verify_attestation_chains.py @@ -1,6 +1,6 @@ #!/usr/bin/env python -# Copyright 2021 Google, LLC. +# Copyright 2021 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/kms/attestations/verify_attestation_chains_test.py b/kms/attestations/verify_attestation_chains_test.py index 480fe318c067..7435737c3263 100644 --- a/kms/attestations/verify_attestation_chains_test.py +++ b/kms/attestations/verify_attestation_chains_test.py @@ -1,4 +1,4 @@ -# Copyright 2021 Google, LLC. +# Copyright 2021 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/kms/attestations/verify_attestation_test.py b/kms/attestations/verify_attestation_test.py index 5cdc5ef2deef..2d373b54436e 100644 --- a/kms/attestations/verify_attestation_test.py +++ b/kms/attestations/verify_attestation_test.py @@ -1,4 +1,4 @@ -# Copyright 2020 Google, LLC. +# Copyright 2020 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. From 062ea7c61fbcd8591844779a68948aeff5e26380 Mon Sep 17 00:00:00 2001 From: rsamborski Date: Wed, 9 Nov 2022 00:17:05 +0100 Subject: [PATCH 131/136] Fix CODEOWNERS newline at the end of file --- .github/CODEOWNERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index fc5ded97e8c2..48ce7b4e382c 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -69,4 +69,4 @@ /trace/**/* @ymotongpoo @GoogleCloudPlatform/python-samples-reviewers /translate/**/* @nicain @GoogleCloudPlatform/python-samples-reviewers /workflows/**/* @GoogleCloudPlatform/python-samples-reviewers -/kms/**/** @GoogleCloudPlatform/dee-infra @GoogleCloudPlatform/python-samples-reviewers \ No newline at end of file +/kms/**/** @GoogleCloudPlatform/dee-infra @GoogleCloudPlatform/python-samples-reviewers From b735728971d76a1f717ac57ad020a6e2810977b1 Mon Sep 17 00:00:00 2001 From: rsamborski Date: Wed, 9 Nov 2022 10:00:55 +0100 Subject: [PATCH 132/136] Removed noxfile.py and added noxfile_config.py --- kms/attestations/noxfile.py | 312 ----------------------------- kms/attestations/noxfile_config.py | 42 ++++ kms/snippets/noxfile.py | 312 ----------------------------- kms/snippets/noxfile_config.py | 42 ++++ 4 files changed, 84 insertions(+), 624 deletions(-) delete mode 100644 kms/attestations/noxfile.py create mode 100644 kms/attestations/noxfile_config.py delete mode 100644 kms/snippets/noxfile.py create mode 100644 kms/snippets/noxfile_config.py diff --git a/kms/attestations/noxfile.py b/kms/attestations/noxfile.py deleted file mode 100644 index 0398d72ff690..000000000000 --- a/kms/attestations/noxfile.py +++ /dev/null @@ -1,312 +0,0 @@ -# Copyright 2019 Google LLC -# -# 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. - -from __future__ import print_function - -import glob -import os -from pathlib import Path -import sys -from typing import Callable, Dict, List, Optional - -import nox - - -# WARNING - WARNING - WARNING - WARNING - WARNING -# WARNING - WARNING - WARNING - WARNING - WARNING -# DO NOT EDIT THIS FILE EVER! -# WARNING - WARNING - WARNING - WARNING - WARNING -# WARNING - WARNING - WARNING - WARNING - WARNING - -BLACK_VERSION = "black==22.3.0" -ISORT_VERSION = "isort==5.10.1" - -# Copy `noxfile_config.py` to your directory and modify it instead. - -# `TEST_CONFIG` dict is a configuration hook that allows users to -# modify the test configurations. The values here should be in sync -# with `noxfile_config.py`. Users will copy `noxfile_config.py` into -# their directory and modify it. - -TEST_CONFIG = { - # You can opt out from the test for specific Python versions. - "ignored_versions": [], - # Old samples are opted out of enforcing Python type hints - # All new samples should feature them - "enforce_type_hints": False, - # An envvar key for determining the project id to use. Change it - # to 'BUILD_SPECIFIC_GCLOUD_PROJECT' if you want to opt in using a - # build specific Cloud project. You can also use your own string - # to use your own Cloud project. - "gcloud_project_env": "GOOGLE_CLOUD_PROJECT", - # 'gcloud_project_env': 'BUILD_SPECIFIC_GCLOUD_PROJECT', - # If you need to use a specific version of pip, - # change pip_version_override to the string representation - # of the version number, for example, "20.2.4" - "pip_version_override": None, - # A dictionary you want to inject into your test. Don't put any - # secrets here. These values will override predefined values. - "envs": {}, -} - - -try: - # Ensure we can import noxfile_config in the project's directory. - sys.path.append(".") - from noxfile_config import TEST_CONFIG_OVERRIDE -except ImportError as e: - print("No user noxfile_config found: detail: {}".format(e)) - TEST_CONFIG_OVERRIDE = {} - -# Update the TEST_CONFIG with the user supplied values. -TEST_CONFIG.update(TEST_CONFIG_OVERRIDE) - - -def get_pytest_env_vars() -> Dict[str, str]: - """Returns a dict for pytest invocation.""" - ret = {} - - # Override the GCLOUD_PROJECT and the alias. - env_key = TEST_CONFIG["gcloud_project_env"] - # This should error out if not set. - ret["GOOGLE_CLOUD_PROJECT"] = os.environ[env_key] - - # Apply user supplied envs. - ret.update(TEST_CONFIG["envs"]) - return ret - - -# DO NOT EDIT - automatically generated. -# All versions used to test samples. -ALL_VERSIONS = ["3.7", "3.8", "3.9", "3.10"] - -# Any default versions that should be ignored. -IGNORED_VERSIONS = TEST_CONFIG["ignored_versions"] - -TESTED_VERSIONS = sorted([v for v in ALL_VERSIONS if v not in IGNORED_VERSIONS]) - -INSTALL_LIBRARY_FROM_SOURCE = os.environ.get("INSTALL_LIBRARY_FROM_SOURCE", False) in ( - "True", - "true", -) - -# Error if a python version is missing -nox.options.error_on_missing_interpreters = True - -# -# Style Checks -# - - -def _determine_local_import_names(start_dir: str) -> List[str]: - """Determines all import names that should be considered "local". - - This is used when running the linter to insure that import order is - properly checked. - """ - file_ext_pairs = [os.path.splitext(path) for path in os.listdir(start_dir)] - return [ - basename - for basename, extension in file_ext_pairs - if extension == ".py" - or os.path.isdir(os.path.join(start_dir, basename)) - and basename not in ("__pycache__") - ] - - -# Linting with flake8. -# -# We ignore the following rules: -# E203: whitespace before ‘:’ -# E266: too many leading ‘#’ for block comment -# E501: line too long -# I202: Additional newline in a section of imports -# -# We also need to specify the rules which are ignored by default: -# ['E226', 'W504', 'E126', 'E123', 'W503', 'E24', 'E704', 'E121'] -FLAKE8_COMMON_ARGS = [ - "--show-source", - "--builtin=gettext", - "--max-complexity=20", - "--import-order-style=google", - "--exclude=.nox,.cache,env,lib,generated_pb2,*_pb2.py,*_pb2_grpc.py", - "--ignore=E121,E123,E126,E203,E226,E24,E266,E501,E704,W503,W504,I202", - "--max-line-length=88", -] - - -@nox.session -def lint(session: nox.sessions.Session) -> None: - if not TEST_CONFIG["enforce_type_hints"]: - session.install("flake8", "flake8-import-order") - else: - session.install("flake8", "flake8-import-order", "flake8-annotations") - - local_names = _determine_local_import_names(".") - args = FLAKE8_COMMON_ARGS + [ - "--application-import-names", - ",".join(local_names), - ".", - ] - session.run("flake8", *args) - - -# -# Black -# - - -@nox.session -def blacken(session: nox.sessions.Session) -> None: - """Run black. Format code to uniform standard.""" - session.install(BLACK_VERSION) - python_files = [path for path in os.listdir(".") if path.endswith(".py")] - - session.run("black", *python_files) - - -# -# format = isort + black -# - -@nox.session -def format(session: nox.sessions.Session) -> None: - """ - Run isort to sort imports. Then run black - to format code to uniform standard. - """ - session.install(BLACK_VERSION, ISORT_VERSION) - python_files = [path for path in os.listdir(".") if path.endswith(".py")] - - # Use the --fss option to sort imports using strict alphabetical order. - # See https://pycqa.github.io/isort/docs/configuration/options.html#force-sort-within-sections - session.run("isort", "--fss", *python_files) - session.run("black", *python_files) - - -# -# Sample Tests -# - - -PYTEST_COMMON_ARGS = ["--junitxml=sponge_log.xml"] - - -def _session_tests( - session: nox.sessions.Session, post_install: Callable = None -) -> None: - # check for presence of tests - test_list = glob.glob("**/*_test.py", recursive=True) + glob.glob("**/test_*.py", recursive=True) - test_list.extend(glob.glob("**/tests", recursive=True)) - - if len(test_list) == 0: - print("No tests found, skipping directory.") - return - - if TEST_CONFIG["pip_version_override"]: - pip_version = TEST_CONFIG["pip_version_override"] - session.install(f"pip=={pip_version}") - """Runs py.test for a particular project.""" - concurrent_args = [] - if os.path.exists("requirements.txt"): - if os.path.exists("constraints.txt"): - session.install("-r", "requirements.txt", "-c", "constraints.txt") - else: - session.install("-r", "requirements.txt") - with open("requirements.txt") as rfile: - packages = rfile.read() - - if os.path.exists("requirements-test.txt"): - if os.path.exists("constraints-test.txt"): - session.install( - "-r", "requirements-test.txt", "-c", "constraints-test.txt" - ) - else: - session.install("-r", "requirements-test.txt") - with open("requirements-test.txt") as rtfile: - packages += rtfile.read() - - if INSTALL_LIBRARY_FROM_SOURCE: - session.install("-e", _get_repo_root()) - - if post_install: - post_install(session) - - if "pytest-parallel" in packages: - concurrent_args.extend(['--workers', 'auto', '--tests-per-worker', 'auto']) - elif "pytest-xdist" in packages: - concurrent_args.extend(['-n', 'auto']) - - session.run( - "pytest", - *(PYTEST_COMMON_ARGS + session.posargs + concurrent_args), - # Pytest will return 5 when no tests are collected. This can happen - # on travis where slow and flaky tests are excluded. - # See http://doc.pytest.org/en/latest/_modules/_pytest/main.html - success_codes=[0, 5], - env=get_pytest_env_vars(), - ) - - -@nox.session(python=ALL_VERSIONS) -def py(session: nox.sessions.Session) -> None: - """Runs py.test for a sample using the specified version of Python.""" - if session.python in TESTED_VERSIONS: - _session_tests(session) - else: - session.skip( - "SKIPPED: {} tests are disabled for this sample.".format(session.python) - ) - - -# -# Readmegen -# - - -def _get_repo_root() -> Optional[str]: - """ Returns the root folder of the project. """ - # Get root of this repository. Assume we don't have directories nested deeper than 10 items. - p = Path(os.getcwd()) - for i in range(10): - if p is None: - break - if Path(p / ".git").exists(): - return str(p) - # .git is not available in repos cloned via Cloud Build - # setup.py is always in the library's root, so use that instead - # https://github.com/googleapis/synthtool/issues/792 - if Path(p / "setup.py").exists(): - return str(p) - p = p.parent - raise Exception("Unable to detect repository root.") - - -GENERATED_READMES = sorted([x for x in Path(".").rglob("*.rst.in")]) - - -@nox.session -@nox.parametrize("path", GENERATED_READMES) -def readmegen(session: nox.sessions.Session, path: str) -> None: - """(Re-)generates the readme for a sample.""" - session.install("jinja2", "pyyaml") - dir_ = os.path.dirname(path) - - if os.path.exists(os.path.join(dir_, "requirements.txt")): - session.install("-r", os.path.join(dir_, "requirements.txt")) - - in_file = os.path.join(dir_, "README.rst.in") - session.run( - "python", _get_repo_root() + "/scripts/readme-gen/readme_gen.py", in_file - ) diff --git a/kms/attestations/noxfile_config.py b/kms/attestations/noxfile_config.py new file mode 100644 index 000000000000..f1fa9e5618b0 --- /dev/null +++ b/kms/attestations/noxfile_config.py @@ -0,0 +1,42 @@ +# Copyright 2021 Google LLC +# +# 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. + +# Default TEST_CONFIG_OVERRIDE for python repos. + +# You can copy this file into your directory, then it will be imported from +# the noxfile.py. + +# The source of truth: +# https://github.com/GoogleCloudPlatform/python-docs-samples/blob/main/noxfile_config.py + +TEST_CONFIG_OVERRIDE = { + # You can opt out from the test for specific Python versions. + "ignored_versions": ["2.7"], + # Old samples are opted out of enforcing Python type hints + # All new samples should feature them + "enforce_type_hints": True, + # An envvar key for determining the project id to use. Change it + # to 'BUILD_SPECIFIC_GCLOUD_PROJECT' if you want to opt in using a + # build specific Cloud project. You can also use your own string + # to use your own Cloud project. + "gcloud_project_env": "GOOGLE_CLOUD_PROJECT", + # 'gcloud_project_env': 'BUILD_SPECIFIC_GCLOUD_PROJECT', + # If you need to use a specific version of pip, + # change pip_version_override to the string representation + # of the version number, for example, "20.2.4" + "pip_version_override": None, + # A dictionary you want to inject into your test. Don't put any + # secrets here. These values will override predefined values. + "envs": {}, +} diff --git a/kms/snippets/noxfile.py b/kms/snippets/noxfile.py deleted file mode 100644 index 0398d72ff690..000000000000 --- a/kms/snippets/noxfile.py +++ /dev/null @@ -1,312 +0,0 @@ -# Copyright 2019 Google LLC -# -# 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. - -from __future__ import print_function - -import glob -import os -from pathlib import Path -import sys -from typing import Callable, Dict, List, Optional - -import nox - - -# WARNING - WARNING - WARNING - WARNING - WARNING -# WARNING - WARNING - WARNING - WARNING - WARNING -# DO NOT EDIT THIS FILE EVER! -# WARNING - WARNING - WARNING - WARNING - WARNING -# WARNING - WARNING - WARNING - WARNING - WARNING - -BLACK_VERSION = "black==22.3.0" -ISORT_VERSION = "isort==5.10.1" - -# Copy `noxfile_config.py` to your directory and modify it instead. - -# `TEST_CONFIG` dict is a configuration hook that allows users to -# modify the test configurations. The values here should be in sync -# with `noxfile_config.py`. Users will copy `noxfile_config.py` into -# their directory and modify it. - -TEST_CONFIG = { - # You can opt out from the test for specific Python versions. - "ignored_versions": [], - # Old samples are opted out of enforcing Python type hints - # All new samples should feature them - "enforce_type_hints": False, - # An envvar key for determining the project id to use. Change it - # to 'BUILD_SPECIFIC_GCLOUD_PROJECT' if you want to opt in using a - # build specific Cloud project. You can also use your own string - # to use your own Cloud project. - "gcloud_project_env": "GOOGLE_CLOUD_PROJECT", - # 'gcloud_project_env': 'BUILD_SPECIFIC_GCLOUD_PROJECT', - # If you need to use a specific version of pip, - # change pip_version_override to the string representation - # of the version number, for example, "20.2.4" - "pip_version_override": None, - # A dictionary you want to inject into your test. Don't put any - # secrets here. These values will override predefined values. - "envs": {}, -} - - -try: - # Ensure we can import noxfile_config in the project's directory. - sys.path.append(".") - from noxfile_config import TEST_CONFIG_OVERRIDE -except ImportError as e: - print("No user noxfile_config found: detail: {}".format(e)) - TEST_CONFIG_OVERRIDE = {} - -# Update the TEST_CONFIG with the user supplied values. -TEST_CONFIG.update(TEST_CONFIG_OVERRIDE) - - -def get_pytest_env_vars() -> Dict[str, str]: - """Returns a dict for pytest invocation.""" - ret = {} - - # Override the GCLOUD_PROJECT and the alias. - env_key = TEST_CONFIG["gcloud_project_env"] - # This should error out if not set. - ret["GOOGLE_CLOUD_PROJECT"] = os.environ[env_key] - - # Apply user supplied envs. - ret.update(TEST_CONFIG["envs"]) - return ret - - -# DO NOT EDIT - automatically generated. -# All versions used to test samples. -ALL_VERSIONS = ["3.7", "3.8", "3.9", "3.10"] - -# Any default versions that should be ignored. -IGNORED_VERSIONS = TEST_CONFIG["ignored_versions"] - -TESTED_VERSIONS = sorted([v for v in ALL_VERSIONS if v not in IGNORED_VERSIONS]) - -INSTALL_LIBRARY_FROM_SOURCE = os.environ.get("INSTALL_LIBRARY_FROM_SOURCE", False) in ( - "True", - "true", -) - -# Error if a python version is missing -nox.options.error_on_missing_interpreters = True - -# -# Style Checks -# - - -def _determine_local_import_names(start_dir: str) -> List[str]: - """Determines all import names that should be considered "local". - - This is used when running the linter to insure that import order is - properly checked. - """ - file_ext_pairs = [os.path.splitext(path) for path in os.listdir(start_dir)] - return [ - basename - for basename, extension in file_ext_pairs - if extension == ".py" - or os.path.isdir(os.path.join(start_dir, basename)) - and basename not in ("__pycache__") - ] - - -# Linting with flake8. -# -# We ignore the following rules: -# E203: whitespace before ‘:’ -# E266: too many leading ‘#’ for block comment -# E501: line too long -# I202: Additional newline in a section of imports -# -# We also need to specify the rules which are ignored by default: -# ['E226', 'W504', 'E126', 'E123', 'W503', 'E24', 'E704', 'E121'] -FLAKE8_COMMON_ARGS = [ - "--show-source", - "--builtin=gettext", - "--max-complexity=20", - "--import-order-style=google", - "--exclude=.nox,.cache,env,lib,generated_pb2,*_pb2.py,*_pb2_grpc.py", - "--ignore=E121,E123,E126,E203,E226,E24,E266,E501,E704,W503,W504,I202", - "--max-line-length=88", -] - - -@nox.session -def lint(session: nox.sessions.Session) -> None: - if not TEST_CONFIG["enforce_type_hints"]: - session.install("flake8", "flake8-import-order") - else: - session.install("flake8", "flake8-import-order", "flake8-annotations") - - local_names = _determine_local_import_names(".") - args = FLAKE8_COMMON_ARGS + [ - "--application-import-names", - ",".join(local_names), - ".", - ] - session.run("flake8", *args) - - -# -# Black -# - - -@nox.session -def blacken(session: nox.sessions.Session) -> None: - """Run black. Format code to uniform standard.""" - session.install(BLACK_VERSION) - python_files = [path for path in os.listdir(".") if path.endswith(".py")] - - session.run("black", *python_files) - - -# -# format = isort + black -# - -@nox.session -def format(session: nox.sessions.Session) -> None: - """ - Run isort to sort imports. Then run black - to format code to uniform standard. - """ - session.install(BLACK_VERSION, ISORT_VERSION) - python_files = [path for path in os.listdir(".") if path.endswith(".py")] - - # Use the --fss option to sort imports using strict alphabetical order. - # See https://pycqa.github.io/isort/docs/configuration/options.html#force-sort-within-sections - session.run("isort", "--fss", *python_files) - session.run("black", *python_files) - - -# -# Sample Tests -# - - -PYTEST_COMMON_ARGS = ["--junitxml=sponge_log.xml"] - - -def _session_tests( - session: nox.sessions.Session, post_install: Callable = None -) -> None: - # check for presence of tests - test_list = glob.glob("**/*_test.py", recursive=True) + glob.glob("**/test_*.py", recursive=True) - test_list.extend(glob.glob("**/tests", recursive=True)) - - if len(test_list) == 0: - print("No tests found, skipping directory.") - return - - if TEST_CONFIG["pip_version_override"]: - pip_version = TEST_CONFIG["pip_version_override"] - session.install(f"pip=={pip_version}") - """Runs py.test for a particular project.""" - concurrent_args = [] - if os.path.exists("requirements.txt"): - if os.path.exists("constraints.txt"): - session.install("-r", "requirements.txt", "-c", "constraints.txt") - else: - session.install("-r", "requirements.txt") - with open("requirements.txt") as rfile: - packages = rfile.read() - - if os.path.exists("requirements-test.txt"): - if os.path.exists("constraints-test.txt"): - session.install( - "-r", "requirements-test.txt", "-c", "constraints-test.txt" - ) - else: - session.install("-r", "requirements-test.txt") - with open("requirements-test.txt") as rtfile: - packages += rtfile.read() - - if INSTALL_LIBRARY_FROM_SOURCE: - session.install("-e", _get_repo_root()) - - if post_install: - post_install(session) - - if "pytest-parallel" in packages: - concurrent_args.extend(['--workers', 'auto', '--tests-per-worker', 'auto']) - elif "pytest-xdist" in packages: - concurrent_args.extend(['-n', 'auto']) - - session.run( - "pytest", - *(PYTEST_COMMON_ARGS + session.posargs + concurrent_args), - # Pytest will return 5 when no tests are collected. This can happen - # on travis where slow and flaky tests are excluded. - # See http://doc.pytest.org/en/latest/_modules/_pytest/main.html - success_codes=[0, 5], - env=get_pytest_env_vars(), - ) - - -@nox.session(python=ALL_VERSIONS) -def py(session: nox.sessions.Session) -> None: - """Runs py.test for a sample using the specified version of Python.""" - if session.python in TESTED_VERSIONS: - _session_tests(session) - else: - session.skip( - "SKIPPED: {} tests are disabled for this sample.".format(session.python) - ) - - -# -# Readmegen -# - - -def _get_repo_root() -> Optional[str]: - """ Returns the root folder of the project. """ - # Get root of this repository. Assume we don't have directories nested deeper than 10 items. - p = Path(os.getcwd()) - for i in range(10): - if p is None: - break - if Path(p / ".git").exists(): - return str(p) - # .git is not available in repos cloned via Cloud Build - # setup.py is always in the library's root, so use that instead - # https://github.com/googleapis/synthtool/issues/792 - if Path(p / "setup.py").exists(): - return str(p) - p = p.parent - raise Exception("Unable to detect repository root.") - - -GENERATED_READMES = sorted([x for x in Path(".").rglob("*.rst.in")]) - - -@nox.session -@nox.parametrize("path", GENERATED_READMES) -def readmegen(session: nox.sessions.Session, path: str) -> None: - """(Re-)generates the readme for a sample.""" - session.install("jinja2", "pyyaml") - dir_ = os.path.dirname(path) - - if os.path.exists(os.path.join(dir_, "requirements.txt")): - session.install("-r", os.path.join(dir_, "requirements.txt")) - - in_file = os.path.join(dir_, "README.rst.in") - session.run( - "python", _get_repo_root() + "/scripts/readme-gen/readme_gen.py", in_file - ) diff --git a/kms/snippets/noxfile_config.py b/kms/snippets/noxfile_config.py new file mode 100644 index 000000000000..f1fa9e5618b0 --- /dev/null +++ b/kms/snippets/noxfile_config.py @@ -0,0 +1,42 @@ +# Copyright 2021 Google LLC +# +# 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. + +# Default TEST_CONFIG_OVERRIDE for python repos. + +# You can copy this file into your directory, then it will be imported from +# the noxfile.py. + +# The source of truth: +# https://github.com/GoogleCloudPlatform/python-docs-samples/blob/main/noxfile_config.py + +TEST_CONFIG_OVERRIDE = { + # You can opt out from the test for specific Python versions. + "ignored_versions": ["2.7"], + # Old samples are opted out of enforcing Python type hints + # All new samples should feature them + "enforce_type_hints": True, + # An envvar key for determining the project id to use. Change it + # to 'BUILD_SPECIFIC_GCLOUD_PROJECT' if you want to opt in using a + # build specific Cloud project. You can also use your own string + # to use your own Cloud project. + "gcloud_project_env": "GOOGLE_CLOUD_PROJECT", + # 'gcloud_project_env': 'BUILD_SPECIFIC_GCLOUD_PROJECT', + # If you need to use a specific version of pip, + # change pip_version_override to the string representation + # of the version number, for example, "20.2.4" + "pip_version_override": None, + # A dictionary you want to inject into your test. Don't put any + # secrets here. These values will override predefined values. + "envs": {}, +} From 0fa2468bb43fa6b1a86bbf6f1e3aacddd89b178f Mon Sep 17 00:00:00 2001 From: rsamborski Date: Wed, 9 Nov 2022 10:45:33 +0100 Subject: [PATCH 133/136] Turn off type hints enforcing for old samples --- kms/attestations/verify_attestation.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kms/attestations/verify_attestation.py b/kms/attestations/verify_attestation.py index d56242b0194b..cb296712f730 100644 --- a/kms/attestations/verify_attestation.py +++ b/kms/attestations/verify_attestation.py @@ -31,7 +31,7 @@ import pem -def verify(attestation_file, bundle_file): +def verify(attestation_file: str, bundle_file: str):bool """Verifies an attestation using a bundle of certificates. Args: From 5b8496ce7bb0b999321b2e2928bcb6dbae266753 Mon Sep 17 00:00:00 2001 From: rsamborski Date: Wed, 9 Nov 2022 10:48:57 +0100 Subject: [PATCH 134/136] Turn off type hints enforcing for old samples --- kms/attestations/noxfile_config.py | 2 +- kms/attestations/verify_attestation.py | 2 +- kms/snippets/noxfile_config.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/kms/attestations/noxfile_config.py b/kms/attestations/noxfile_config.py index f1fa9e5618b0..34d0d0b1bb8a 100644 --- a/kms/attestations/noxfile_config.py +++ b/kms/attestations/noxfile_config.py @@ -25,7 +25,7 @@ "ignored_versions": ["2.7"], # Old samples are opted out of enforcing Python type hints # All new samples should feature them - "enforce_type_hints": True, + "enforce_type_hints": False, # An envvar key for determining the project id to use. Change it # to 'BUILD_SPECIFIC_GCLOUD_PROJECT' if you want to opt in using a # build specific Cloud project. You can also use your own string diff --git a/kms/attestations/verify_attestation.py b/kms/attestations/verify_attestation.py index cb296712f730..d56242b0194b 100644 --- a/kms/attestations/verify_attestation.py +++ b/kms/attestations/verify_attestation.py @@ -31,7 +31,7 @@ import pem -def verify(attestation_file: str, bundle_file: str):bool +def verify(attestation_file, bundle_file): """Verifies an attestation using a bundle of certificates. Args: diff --git a/kms/snippets/noxfile_config.py b/kms/snippets/noxfile_config.py index f1fa9e5618b0..34d0d0b1bb8a 100644 --- a/kms/snippets/noxfile_config.py +++ b/kms/snippets/noxfile_config.py @@ -25,7 +25,7 @@ "ignored_versions": ["2.7"], # Old samples are opted out of enforcing Python type hints # All new samples should feature them - "enforce_type_hints": True, + "enforce_type_hints": False, # An envvar key for determining the project id to use. Change it # to 'BUILD_SPECIFIC_GCLOUD_PROJECT' if you want to opt in using a # build specific Cloud project. You can also use your own string From 01ca2287f3a7b3d4adaa5007cf5de804b997da3f Mon Sep 17 00:00:00 2001 From: rsamborski Date: Mon, 14 Nov 2022 11:30:55 +0100 Subject: [PATCH 135/136] Added kms label to blunderbuss.yml --- .github/blunderbuss.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/blunderbuss.yml b/.github/blunderbuss.yml index 97e0b4b04893..b68bd162b9d9 100644 --- a/.github/blunderbuss.yml +++ b/.github/blunderbuss.yml @@ -126,6 +126,10 @@ assign_issues_by: - 'api: monitoring' to: - GoogleCloudPlatform/dee-observability +- labels: + - 'api: kms' + to: + - GoogleCloudPlatform/dee-infra assign_prs_by: - labels: From bb582917d4a6e352e2bed8d3d78b6ef291c7af86 Mon Sep 17 00:00:00 2001 From: rsamborski Date: Mon, 14 Nov 2022 12:17:44 +0100 Subject: [PATCH 136/136] Update blunderbuss.yml with cloudkms label --- .github/blunderbuss.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/blunderbuss.yml b/.github/blunderbuss.yml index b68bd162b9d9..170d4be5454a 100644 --- a/.github/blunderbuss.yml +++ b/.github/blunderbuss.yml @@ -128,6 +128,7 @@ assign_issues_by: - GoogleCloudPlatform/dee-observability - labels: - 'api: kms' + - 'api: cloudkms' to: - GoogleCloudPlatform/dee-infra