From 9f67a9983cca64002f70c621db443f74635f958e Mon Sep 17 00:00:00 2001 From: Ryan Matsumoto Date: Tue, 31 Jan 2017 00:52:39 -0800 Subject: [PATCH 01/16] Draft of first half of KMS samples --- kms/api/quickstart.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kms/api/quickstart.py b/kms/api/quickstart.py index 4e94a669118..725fb832836 100644 --- a/kms/api/quickstart.py +++ b/kms/api/quickstart.py @@ -20,7 +20,7 @@ def run_quickstart(): from googleapiclient import discovery # Your Google Cloud Platform project ID - project_id = 'YOUR_PROJECT_ID' + project_id = 'kms-testing' # Lists keys in the "global" location. location = 'global' From 6d8230908ecd318f9f847fc795c2407ad787f2c1 Mon Sep 17 00:00:00 2001 From: Ryan Matsumoto Date: Tue, 31 Jan 2017 00:53:58 -0800 Subject: [PATCH 02/16] reversed wrong change --- kms/api/quickstart.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kms/api/quickstart.py b/kms/api/quickstart.py index 725fb832836..4e94a669118 100644 --- a/kms/api/quickstart.py +++ b/kms/api/quickstart.py @@ -20,7 +20,7 @@ def run_quickstart(): from googleapiclient import discovery # Your Google Cloud Platform project ID - project_id = 'kms-testing' + project_id = 'YOUR_PROJECT_ID' # Lists keys in the "global" location. location = 'global' From 5529d409cdb9bbf5f7c0f4d9bf0e5753c62dcc14 Mon Sep 17 00:00:00 2001 From: Ryan Matsumoto Date: Wed, 1 Feb 2017 20:47:02 -0800 Subject: [PATCH 03/16] KMS Apiary Python samples - P1 --- kms/api/functions.py | 273 +++++++++++++++++++++++++++++++++++++ kms/api/functions_test.py | 172 +++++++++++++++++++++++ kms/api/infile.txt | 1 + kms/api/quickstart.py | 2 +- kms/api/quickstart_test.py | 1 + 5 files changed, 448 insertions(+), 1 deletion(-) create mode 100644 kms/api/functions.py create mode 100644 kms/api/functions_test.py create mode 100644 kms/api/infile.txt diff --git a/kms/api/functions.py b/kms/api/functions.py new file mode 100644 index 00000000000..14211dfac73 --- /dev/null +++ b/kms/api/functions.py @@ -0,0 +1,273 @@ +#!/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 + +# Imports the Google APIs client library +from googleapiclient import discovery + + +# [START kms_create_keyring] +def create_keyring(project_id, location, keyring): + + # 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 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, infile, outfile): + + # 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 input file. + i = open(infile, 'r') + text = i.read() + i.close() + encoded_text = base64.b64encode(text) + + # Use the KMS API to encrypt the text. + request = kms_client.projects().locations().keyRings().cryptoKeys().encrypt(name=name, body={"plaintext": encoded_text}) + response = request.execute() + + # Write the encrypted text to a file. + o = open(outfile, 'w') + o.write(response["ciphertext"]) + o.close() + + print 'Saved encrypted text to {}.'.format(outfile) +# [END kms_encrypt] + + +# [START kms_decrypt] +def decrypt(project_id, location, keyring, cryptokey, infile, outfile): + + # 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 input file. + i = open(infile, 'r') + cipher_text = i.read() + i.close() + + # Use the KMS API to decrypt the text. + request = kms_client.projects().locations().keyRings().cryptoKeys().decrypt(name=name, body={"ciphertext": cipher_text}) + response = request.execute() + + # Write the plain text to a file. + o = open(outfile, 'w') + plaintext_encoded = response["plaintext"] + plaintext_decoded = base64.b64decode(plaintext_encoded) + o.write(plaintext_decoded) + o.close() + + print 'Saved decrypted text to {}.'.format(outfile) +# [END kms_decrypt] + + +# [START kms_disable_cryptokey_version] +def disable_cryptokey_version(project_id, location, keyring, cryptokey, version): + # Creates an API client for the KMS API. + kms_client = discovery.build('cloudkms', 'v1beta1') + + # 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. + request = kms_client.projects().locations().keyRings().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): + # Creates an API client for the KMS API. + kms_client = discovery.build('cloudkms', 'v1beta1') + + # 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. + request = kms_client.projects().locations().keyRings().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): + # 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. + policy_request = kms_client.projects().locations().keyRings().cryptoKeys().getIamPolicy(resource=parent) + policy_response = policy_request.execute() + if 'bindings' in policy_response.keys(): + role_already_exists = False + for binding in policy_response['bindings']: + if binding['role'] == role: + role_already_exists = True + member_already_exists = False + for user in binding['members']: + if user == member: + member_already_exists = True + if not member_already_exists: + binding['members'].append(member) + if not role_already_exists: + members = [] + members.append(member) + binding = dict() + binding['role'] = role + binding['members'] = members + policy_response['bindings'].append(binding) + else: + members = [] + members.append(member) + binding = dict() + binding['role'] = role + binding['members'] = members + bindings = [] + bindings.append(binding) + policy_response['bindings'] = bindings + + # Set the new IAM Policy. + request = kms_client.projects().locations().keyRings().cryptoKeys().setIamPolicy(resource=parent, body={"policy": policy_response}) + request.execute() + + print 'Member {} added with role {} to policy for CryptoKey {} in KeyRing {}'.format(member, role, cryptokey, keyring) +# [END kms_add_member_to_cryptokey_policy] + + +# [START kms_get_keyring_policy] +def get_keyring_policy(project_id, location, keyring): + # 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') + + 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') + + other_parser = subparsers.add_parser('other') + + args = parser.parse_args() + + if 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) diff --git a/kms/api/functions_test.py b/kms/api/functions_test.py new file mode 100644 index 00000000000..f7e44947895 --- /dev/null +++ b/kms/api/functions_test.py @@ -0,0 +1,172 @@ +#!/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 subprocess + +from googleapiclient import discovery + +import functions + + +# Your Google Cloud Platform project ID +PROJECT_ID = 'your-project-id' + +# Your Google Cloud Platform Key Location +LOCATION = 'global' + +# Your Google Cloud Platform KeyRing name +KEYRING = 'sample-keyring-4' + +# Your Google Cloud Platform CryptoKey name +CRYPTOKEY = 'sample-key-4' + +# An infile for text to be encrypted +INFILE = 'infile.txt' + +# An outfile for text that has been encrypted +OUTFILE = 'outfile.txt' + +# An outfile for text that has been decrypted +DECRYPTEDFILE = 'outfile2.txt' + +# 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): + functions.create_keyring(PROJECT_ID, LOCATION, KEYRING) + out, _ = capsys.readouterr() + expected = 'Created KeyRing projects/{}/locations/{}/keyRings/{}.'.format( + PROJECT_ID, LOCATION, KEYRING) + assert expected in out + + +def test_create_cryptokey(capsys): + functions.create_cryptokey(PROJECT_ID, LOCATION, KEYRING, CRYPTOKEY) + out, _ = capsys.readouterr() + expected = 'Created CryptoKey projects/{}/locations/{}/keyRings/{}/cryptoKeys/{}.'.format(PROJECT_ID, LOCATION, KEYRING, CRYPTOKEY) + assert expected in out + + +def test_encrypt_decrypt(capsys): + # Read text from input file. + i = open(INFILE, 'r') + text = i.read() + i.close() + + # Encrypt text and then decrypt it. + functions.encrypt( + PROJECT_ID, LOCATION, KEYRING, CRYPTOKEY, INFILE, OUTFILE) + functions.decrypt( + PROJECT_ID, LOCATION, KEYRING, CRYPTOKEY, OUTFILE, DECRYPTEDFILE) + + # Make sure the decrypted text matches the original text + o = open(DECRYPTEDFILE, 'r') + decrypted_text = o.read() + assert decrypted_text == text + o.close() + + # Make sure other output is as expected. + out, _ = capsys.readouterr() + assert 'Saved encrypted text to {}.'.format(OUTFILE) in out + assert 'Saved decrypted text to {}.'.format(DECRYPTEDFILE) in out + + +def test_encrypt_decrypt_cli(capsys): + # Read text from input file. + i = open(INFILE, 'r') + text = i.read() + i.close() + + # Encrypt text and then decrypt it. + encrypt_output = subprocess.check_output( + "python functions.py encrypt {} {} {} {} {} {}".format( + PROJECT_ID, LOCATION, KEYRING, CRYPTOKEY, INFILE, OUTFILE), + shell=True) + decrypt_output = subprocess.check_output( + "python functions.py decrypt {} {} {} {} {} {}".format( + PROJECT_ID, LOCATION, KEYRING, CRYPTOKEY, OUTFILE, DECRYPTEDFILE), + shell=True) + + # Make sure the decrypted text matches the original text + o = open(DECRYPTEDFILE, 'r') + decrypted_text = o.read() + assert decrypted_text == text + o.close() + + # Make sure other output is as expected. + expected_encrypt_out = 'Saved encrypted text to {}.'.format(OUTFILE) + assert expected_encrypt_out in encrypt_output + expected_decrypt_out = 'Saved decrypted text to {}.'.format(DECRYPTEDFILE) + assert expected_decrypt_out in decrypt_output + + +def test_disable_cryptokey_version(capsys): + functions.disable_cryptokey_version( + PROJECT_ID, LOCATION, KEYRING, CRYPTOKEY, VERSION) + out, _ = capsys.readouterr() + expected = 'CryptoKeyVersion projects/{}/locations/{}/keyRings/{}/cryptoKeys/{}/cryptoKeyVersions/{}\'s state has been set to {}.'.format(PROJECT_ID, LOCATION, KEYRING, CRYPTOKEY, VERSION, 'DISABLED') + assert expected in out + + +def test_destroy_cryptokey_version(capsys): + functions.destroy_cryptokey_version( + PROJECT_ID, LOCATION, KEYRING, CRYPTOKEY, VERSION) + out, _ = capsys.readouterr() + expected = 'CryptoKeyVersion projects/{}/locations/{}/keyRings/{}/cryptoKeys/{}/cryptoKeyVersions/{}\'s state has been set to {}.'.format(PROJECT_ID, LOCATION, KEYRING, CRYPTOKEY, VERSION, 'DESTROY_SCHEDULED') + assert expected in out + + +def test_add_member_to_cryptokey_policy(capsys): + functions.add_member_to_cryptokey_policy( + PROJECT_ID, 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 + + # 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 verify that the new member has been added + # with the correct role. + policy_request = kms_client.projects().locations().keyRings().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): + functions.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) diff --git a/kms/api/infile.txt b/kms/api/infile.txt new file mode 100644 index 00000000000..83c076ecf6a --- /dev/null +++ b/kms/api/infile.txt @@ -0,0 +1 @@ +SampleText diff --git a/kms/api/quickstart.py b/kms/api/quickstart.py index 4e94a669118..5cd8aa4ee97 100644 --- a/kms/api/quickstart.py +++ b/kms/api/quickstart.py @@ -20,7 +20,7 @@ def run_quickstart(): from googleapiclient import discovery # Your Google Cloud Platform project ID - project_id = 'YOUR_PROJECT_ID' + project_id = 'your-project-id' # Lists keys in the "global" location. location = 'global' diff --git a/kms/api/quickstart_test.py b/kms/api/quickstart_test.py index d5a196eb395..cd5f9db511a 100644 --- a/kms/api/quickstart_test.py +++ b/kms/api/quickstart_test.py @@ -14,6 +14,7 @@ def test_quickstart(api_client_inject_project_id, capsys): + import quickstart quickstart.run_quickstart() From 491b6d9d5614fe6860937ebd29b29deb53615a5d Mon Sep 17 00:00:00 2001 From: Ryan Matsumoto Date: Wed, 1 Feb 2017 20:50:32 -0800 Subject: [PATCH 04/16] Few minor style issues --- kms/api/functions_test.py | 2 +- kms/api/quickstart.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/kms/api/functions_test.py b/kms/api/functions_test.py index f7e44947895..cbd709a49bc 100644 --- a/kms/api/functions_test.py +++ b/kms/api/functions_test.py @@ -21,7 +21,7 @@ # Your Google Cloud Platform project ID -PROJECT_ID = 'your-project-id' +PROJECT_ID = 'YOUR_PROJECT_ID' # Your Google Cloud Platform Key Location LOCATION = 'global' diff --git a/kms/api/quickstart.py b/kms/api/quickstart.py index 5cd8aa4ee97..4e94a669118 100644 --- a/kms/api/quickstart.py +++ b/kms/api/quickstart.py @@ -20,7 +20,7 @@ def run_quickstart(): from googleapiclient import discovery # Your Google Cloud Platform project ID - project_id = 'your-project-id' + project_id = 'YOUR_PROJECT_ID' # Lists keys in the "global" location. location = 'global' From 21f812cc5dc84373792ca7b9a33d0b9150cfe751 Mon Sep 17 00:00:00 2001 From: Ryan Matsumoto Date: Wed, 1 Feb 2017 20:51:13 -0800 Subject: [PATCH 05/16] Adding back in space i accidentally deleted --- kms/api/quickstart_test.py | 1 - 1 file changed, 1 deletion(-) diff --git a/kms/api/quickstart_test.py b/kms/api/quickstart_test.py index cd5f9db511a..d5a196eb395 100644 --- a/kms/api/quickstart_test.py +++ b/kms/api/quickstart_test.py @@ -14,7 +14,6 @@ def test_quickstart(api_client_inject_project_id, capsys): - import quickstart quickstart.run_quickstart() From 2a92880fb2ca6e5d8505c584823d0e97bce3689c Mon Sep 17 00:00:00 2001 From: Ryan Matsumoto Date: Fri, 3 Feb 2017 15:53:10 -0800 Subject: [PATCH 06/16] Addressed all code review comments --- kms/api/functions.py | 177 +++++++++++++++++++++----------------- kms/api/functions_test.py | 143 ++++++++++++++++-------------- kms/api/infile.txt | 1 - 3 files changed, 176 insertions(+), 145 deletions(-) delete mode 100644 kms/api/infile.txt diff --git a/kms/api/functions.py b/kms/api/functions.py index 14211dfac73..9dd2ac8f742 100644 --- a/kms/api/functions.py +++ b/kms/api/functions.py @@ -15,13 +15,15 @@ import argparse import base64 +import io -# Imports the Google APIs client library from googleapiclient import discovery # [START kms_create_keyring] def create_keyring(project_id, location, keyring): + """Creates a KeyRing in the given location. Potential locations include: + global, asia-east1, europe-west1, us-central1, and us-east1.""" # Creates an API client for the KMS API. kms_client = discovery.build('cloudkms', 'v1beta1') @@ -34,12 +36,13 @@ def create_keyring(project_id, location, keyring): parent=parent, body={}, keyRingId=keyring) response = request.execute() - print 'Created KeyRing {}.'.format(response["name"]) + print('Created KeyRing {}.'.format(response["name"])) # [END kms_create_keyring] # [START kms_create_cryptokey] def create_cryptokey(project_id, location, keyring, cryptokey): + """Creates a CrytoKey within a KeyRing in the given location.""" # Creates an API client for the KMS API. kms_client = discovery.build('cloudkms', 'v1beta1') @@ -54,12 +57,16 @@ def create_cryptokey(project_id, location, keyring, cryptokey): cryptoKeyId=cryptokey) response = request.execute() - print 'Created CryptoKey {}.'.format(response["name"]) + print('Created CryptoKey {}.'.format(response["name"])) # [END kms_create_cryptokey] # [START kms_encrypt] -def encrypt(project_id, location, keyring, cryptokey, infile, outfile): +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') @@ -68,27 +75,31 @@ def encrypt(project_id, location, keyring, cryptokey, infile, outfile): name = 'projects/{}/locations/{}/keyRings/{}/cryptoKeys/{}'.format( project_id, location, keyring, cryptokey) - # Read text from input file. - i = open(infile, 'r') - text = i.read() - i.close() - encoded_text = base64.b64encode(text) + # 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. - request = kms_client.projects().locations().keyRings().cryptoKeys().encrypt(name=name, body={"plaintext": encoded_text}) - response = request.execute() + # 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. - o = open(outfile, 'w') - o.write(response["ciphertext"]) - o.close() + # 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(outfile) + print('Saved encrypted text to {}.'.format(encrypted_file_name)) # [END kms_encrypt] # [START kms_decrypt] -def decrypt(project_id, location, keyring, cryptokey, infile, outfile): +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') @@ -97,64 +108,81 @@ def decrypt(project_id, location, keyring, cryptokey, infile, outfile): name = 'projects/{}/locations/{}/keyRings/{}/cryptoKeys/{}'.format( project_id, location, keyring, cryptokey) - # Read cipher text from input file. - i = open(infile, 'r') - cipher_text = i.read() - i.close() + # 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. - request = kms_client.projects().locations().keyRings().cryptoKeys().decrypt(name=name, body={"ciphertext": cipher_text}) - response = request.execute() + # 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. - o = open(outfile, 'w') - plaintext_encoded = response["plaintext"] - plaintext_decoded = base64.b64decode(plaintext_encoded) - o.write(plaintext_decoded) - o.close() + # 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(outfile) + 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): +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') - # The resource name of the CryptoKeyVersion. - name = 'projects/{}/locations/{}/keyRings/{}/cryptoKeys/{}/cryptoKeyVersions/{}'.format(project_id, location, keyring, cryptokey, version) + # Construct the resource name of the CryptoKeyVersion. + name = 'projects/{}/locations/{}/'.format(project_id, location) + name += 'keyRings/{}/cryptoKeys/{}/'.format(keyring, cryptokey) + name += 'cryptoKeyVersions/{}'.format(version) # Use the KMS API to disable the CryptoKeyVersion. - request = kms_client.projects().locations().keyRings().cryptoKeys().cryptoKeyVersions().patch(name=name, body={"state": 'DISABLED'}, updateMask="state") + 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"]) + 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') - # The resource name of the CryptoKeyVersion. - name = 'projects/{}/locations/{}/keyRings/{}/cryptoKeys/{}/cryptoKeyVersions/{}'.format(project_id, location, keyring, cryptokey, version) + # Construct the resource name of the CryptoKeyVersion. + name = 'projects/{}/locations/{}/'.format(project_id, location) + name += 'keyRings/{}/cryptoKeys/{}/'.format(keyring, cryptokey) + name += 'cryptoKeyVersions/{}'.format(version) # Use the KMS API to schedule the CryptoKeyVersion for destruction. - request = kms_client.projects().locations().keyRings().cryptoKeys().cryptoKeyVersions().destroy(name=name, body={}) + 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"]) + 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') @@ -163,46 +191,37 @@ def add_member_to_cryptokey_policy( project_id, location, keyring, cryptokey) # Get the current IAM policy and add the new member to it. - policy_request = kms_client.projects().locations().keyRings().cryptoKeys().getIamPolicy(resource=parent) + 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(): - role_already_exists = False - for binding in policy_response['bindings']: - if binding['role'] == role: - role_already_exists = True - member_already_exists = False - for user in binding['members']: - if user == member: - member_already_exists = True - if not member_already_exists: - binding['members'].append(member) - if not role_already_exists: - members = [] - members.append(member) - binding = dict() - binding['role'] = role - binding['members'] = members - policy_response['bindings'].append(binding) - else: - members = [] - members.append(member) - binding = dict() - binding['role'] = role - binding['members'] = members - bindings = [] - bindings.append(binding) - policy_response['bindings'] = bindings + 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. - request = kms_client.projects().locations().keyRings().cryptoKeys().setIamPolicy(resource=parent, body={"policy": policy_response}) + cryptokeys = kms_client.projects().locations().keyRings().cryptoKeys() + request = cryptokeys.setIamPolicy( + resource=parent, body={"policy": policy_response}) request.execute() - print 'Member {} added with role {} to policy for CryptoKey {} in KeyRing {}'.format(member, role, cryptokey, keyring) + print_msg = 'Member {} added with role {} to policy'.format(member, role) + print_msg += ' for CryptoKey {} in KeyRing {}'.format(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') @@ -216,16 +235,16 @@ def get_keyring_policy(project_id, location, keyring): response = request.execute() if 'bindings' in response.keys(): - print 'Printing IAM policy for resource {}:'.format(parent) + print('Printing IAM policy for resource {}:'.format(parent)) for binding in response['bindings']: - print '' - print 'Role: {}'.format(binding['role']) - print 'Members:' + print('') + print('Role: {}'.format(binding['role'])) + print('Members:') for member in binding['members']: - print member - print '' + print(member) + print('') else: - print 'No roles found for resource {}.'.format(parent) + print('No roles found for resource {}.'.format(parent)) # [END kms_get_keyring_policy] diff --git a/kms/api/functions_test.py b/kms/api/functions_test.py index cbd709a49bc..7d75bc4bc09 100644 --- a/kms/api/functions_test.py +++ b/kms/api/functions_test.py @@ -20,26 +20,14 @@ import functions -# Your Google Cloud Platform project ID -PROJECT_ID = 'YOUR_PROJECT_ID' - # Your Google Cloud Platform Key Location LOCATION = 'global' # Your Google Cloud Platform KeyRing name -KEYRING = 'sample-keyring-4' +KEYRING = 'sample-keyring-28' # Your Google Cloud Platform CryptoKey name -CRYPTOKEY = 'sample-key-4' - -# An infile for text to be encrypted -INFILE = 'infile.txt' - -# An outfile for text that has been encrypted -OUTFILE = 'outfile.txt' - -# An outfile for text that has been decrypted -DECRYPTEDFILE = 'outfile2.txt' +CRYPTOKEY = 'sample-key-28' # Your Google Cloud Platform CryptoKeyVersion name VERSION = 1 @@ -51,95 +39,114 @@ ROLE = 'roles/owner' -def test_create_keyring(capsys): - functions.create_keyring(PROJECT_ID, LOCATION, KEYRING) +def test_create_keyring(capsys, cloud_config): + functions.create_keyring(cloud_config.project, LOCATION, KEYRING) out, _ = capsys.readouterr() expected = 'Created KeyRing projects/{}/locations/{}/keyRings/{}.'.format( - PROJECT_ID, LOCATION, KEYRING) + cloud_config.project, LOCATION, KEYRING) assert expected in out -def test_create_cryptokey(capsys): - functions.create_cryptokey(PROJECT_ID, LOCATION, KEYRING, CRYPTOKEY) +def test_create_cryptokey(capsys, cloud_config): + functions.create_cryptokey( + cloud_config.project, LOCATION, KEYRING, CRYPTOKEY) out, _ = capsys.readouterr() - expected = 'Created CryptoKey projects/{}/locations/{}/keyRings/{}/cryptoKeys/{}.'.format(PROJECT_ID, LOCATION, KEYRING, CRYPTOKEY) + expected = 'Created CryptoKey projects/{}/'.format(cloud_config.project) + expected += 'locations/{}/keyRings/{}/'.format(LOCATION, KEYRING) + expected += 'cryptoKeys/{}.'.format(CRYPTOKEY) assert expected in out -def test_encrypt_decrypt(capsys): - # Read text from input file. - i = open(INFILE, 'r') - text = i.read() - i.close() +def test_encrypt_decrypt(capsys, cloud_config, tmpdir): + # Write to a plaintext file. + tmpdir.join("in.txt").write('SampleText') + + # Construct temporary file names. + plaintext_file_name = str(tmpdir.join("in.txt")) + encrypted_file_name = str(tmpdir.join("out.txt")) + decrypted_file_name = str(tmpdir.join("out2.txt")) # Encrypt text and then decrypt it. functions.encrypt( - PROJECT_ID, LOCATION, KEYRING, CRYPTOKEY, INFILE, OUTFILE) + cloud_config.project, LOCATION, KEYRING, CRYPTOKEY, + plaintext_file_name, encrypted_file_name) functions.decrypt( - PROJECT_ID, LOCATION, KEYRING, CRYPTOKEY, OUTFILE, DECRYPTEDFILE) + cloud_config.project, LOCATION, KEYRING, CRYPTOKEY, + encrypted_file_name, decrypted_file_name) - # Make sure the decrypted text matches the original text - o = open(DECRYPTEDFILE, 'r') - decrypted_text = o.read() - assert decrypted_text == text - o.close() + # Make sure the decrypted text matches the original text. + decrypted_text = open(decrypted_file_name).read() + assert decrypted_text == 'SampleText' # Make sure other output is as expected. out, _ = capsys.readouterr() - assert 'Saved encrypted text to {}.'.format(OUTFILE) in out - assert 'Saved decrypted text to {}.'.format(DECRYPTEDFILE) in out + assert 'Saved encrypted text to {}.'.format(encrypted_file_name) in out + assert 'Saved decrypted text to {}.'.format(decrypted_file_name) in out + +def test_encrypt_decrypt_cli(capsys, cloud_config, tmpdir): + # Write to a plaintext file. + tmpdir.join("in.txt").write('SampleText') -def test_encrypt_decrypt_cli(capsys): - # Read text from input file. - i = open(INFILE, 'r') - text = i.read() - i.close() + # Construct temporary file names. + plaintext_file_name = str(tmpdir.join("in.txt")) + encrypted_file_name = str(tmpdir.join("out.txt")) + decrypted_file_name = str(tmpdir.join("out2.txt")) # Encrypt text and then decrypt it. + project_id = cloud_config.project encrypt_output = subprocess.check_output( "python functions.py encrypt {} {} {} {} {} {}".format( - PROJECT_ID, LOCATION, KEYRING, CRYPTOKEY, INFILE, OUTFILE), + project_id, LOCATION, KEYRING, CRYPTOKEY, plaintext_file_name, + encrypted_file_name), shell=True) decrypt_output = subprocess.check_output( "python functions.py decrypt {} {} {} {} {} {}".format( - PROJECT_ID, LOCATION, KEYRING, CRYPTOKEY, OUTFILE, DECRYPTEDFILE), + project_id, LOCATION, KEYRING, CRYPTOKEY, encrypted_file_name, + decrypted_file_name), shell=True) - # Make sure the decrypted text matches the original text - o = open(DECRYPTEDFILE, 'r') - decrypted_text = o.read() - assert decrypted_text == text - o.close() + # Make sure the decrypted text matches the original text. + decrypted_text = open(decrypted_file_name).read() + assert decrypted_text == 'SampleText' # Make sure other output is as expected. - expected_encrypt_out = 'Saved encrypted text to {}.'.format(OUTFILE) - assert expected_encrypt_out in encrypt_output - expected_decrypt_out = 'Saved decrypted text to {}.'.format(DECRYPTEDFILE) - assert expected_decrypt_out in decrypt_output + expected_encrypt_out = 'Saved encrypted text to {}.'.format( + encrypted_file_name) + assert expected_encrypt_out in encrypt_output.decode('utf-8') + expected_decrypt_out = 'Saved decrypted text to {}.'.format( + decrypted_file_name) + assert expected_decrypt_out in decrypt_output.decode('utf-8') -def test_disable_cryptokey_version(capsys): +def test_disable_cryptokey_version(capsys, cloud_config): functions.disable_cryptokey_version( - PROJECT_ID, LOCATION, KEYRING, 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(PROJECT_ID, LOCATION, KEYRING, CRYPTOKEY, VERSION, 'DISABLED') + expected = 'CryptoKeyVersion projects/{}/'.format(cloud_config.project) + expected += 'locations/{}/keyRings/{}/'.format(LOCATION, KEYRING) + expected += 'cryptoKeys/{}/cryptoKeyVersions/{}'.format(CRYPTOKEY, VERSION) + expected += '\'s state has been set to {}.'.format('DISABLED') assert expected in out -def test_destroy_cryptokey_version(capsys): +def test_destroy_cryptokey_version(capsys, cloud_config): functions.destroy_cryptokey_version( - PROJECT_ID, LOCATION, KEYRING, 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(PROJECT_ID, LOCATION, KEYRING, CRYPTOKEY, VERSION, 'DESTROY_SCHEDULED') + expected = 'CryptoKeyVersion projects/{}/'.format(cloud_config.project) + expected += 'locations/{}/keyRings/{}/'.format(LOCATION, KEYRING) + expected += 'cryptoKeys/{}/cryptoKeyVersions/{}'.format(CRYPTOKEY, VERSION) + expected += '\'s state has been set to {}.'.format('DESTROY_SCHEDULED') assert expected in out -def test_add_member_to_cryptokey_policy(capsys): +def test_add_member_to_cryptokey_policy(capsys, cloud_config): functions.add_member_to_cryptokey_policy( - PROJECT_ID, LOCATION, KEYRING, CRYPTOKEY, MEMBER, ROLE) + 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) + expected = 'Member {} added with role {} to policy '.format(MEMBER, ROLE) + expected += 'for CryptoKey {} in KeyRing {}'.format(CRYPTOKEY, KEYRING) assert expected in out # Creates an API client for the KMS API. @@ -147,11 +154,12 @@ def test_add_member_to_cryptokey_policy(capsys): # The resource name of the CryptoKey. parent = 'projects/{}/locations/{}/keyRings/{}/cryptoKeys/{}'.format( - PROJECT_ID, LOCATION, KEYRING, CRYPTOKEY) + cloud_config.project, LOCATION, KEYRING, CRYPTOKEY) # Get the current IAM policy and verify that the new member has been added # with the correct role. - policy_request = kms_client.projects().locations().keyRings().cryptoKeys().getIamPolicy(resource=parent) + 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'] @@ -164,9 +172,14 @@ def test_add_member_to_cryptokey_policy(capsys): assert found_member_role_pair -def test_get_keyring_policy(capsys): - functions.get_keyring_policy(PROJECT_ID, LOCATION, KEYRING) +def test_get_keyring_policy(capsys, cloud_config): + project_id = cloud_config.project + functions.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) + expected_roles_exist = 'Printing IAM policy for resource projects/' + expected_roles_exist += '{}/locations/{}/'.format(project_id, LOCATION) + expected_roles_exist += 'keyRings/{}:'.format(KEYRING) + expected_no_roles = 'No roles found for resource projects/' + expected_no_roles += '{}/locations/{}/'.format(project_id, LOCATION) + expected_no_roles += 'keyRings/{}.'.format(KEYRING) assert (expected_roles_exist in out) or (expected_no_roles in out) diff --git a/kms/api/infile.txt b/kms/api/infile.txt deleted file mode 100644 index 83c076ecf6a..00000000000 --- a/kms/api/infile.txt +++ /dev/null @@ -1 +0,0 @@ -SampleText From 9cf08a470eec8ab7668ad8c727c9c96a0db3081d Mon Sep 17 00:00:00 2001 From: Ryan Matsumoto Date: Fri, 3 Feb 2017 15:57:30 -0800 Subject: [PATCH 07/16] Renamed api directory to api-client --- kms/{api => api-client}/README.rst.in | 0 kms/{api => api-client}/functions.py | 0 kms/{api => api-client}/functions_test.py | 0 kms/{api => api-client}/quickstart.py | 0 kms/{api => api-client}/quickstart_test.py | 0 kms/{api => api-client}/requirements.txt | 0 6 files changed, 0 insertions(+), 0 deletions(-) rename kms/{api => api-client}/README.rst.in (100%) rename kms/{api => api-client}/functions.py (100%) rename kms/{api => api-client}/functions_test.py (100%) rename kms/{api => api-client}/quickstart.py (100%) rename kms/{api => api-client}/quickstart_test.py (100%) rename kms/{api => api-client}/requirements.txt (100%) diff --git a/kms/api/README.rst.in b/kms/api-client/README.rst.in similarity index 100% rename from kms/api/README.rst.in rename to kms/api-client/README.rst.in diff --git a/kms/api/functions.py b/kms/api-client/functions.py similarity index 100% rename from kms/api/functions.py rename to kms/api-client/functions.py diff --git a/kms/api/functions_test.py b/kms/api-client/functions_test.py similarity index 100% rename from kms/api/functions_test.py rename to kms/api-client/functions_test.py diff --git a/kms/api/quickstart.py b/kms/api-client/quickstart.py similarity index 100% rename from kms/api/quickstart.py rename to kms/api-client/quickstart.py diff --git a/kms/api/quickstart_test.py b/kms/api-client/quickstart_test.py similarity index 100% rename from kms/api/quickstart_test.py rename to kms/api-client/quickstart_test.py diff --git a/kms/api/requirements.txt b/kms/api-client/requirements.txt similarity index 100% rename from kms/api/requirements.txt rename to kms/api-client/requirements.txt From 816877a83add9f430a680d9061b31cd320c1b421 Mon Sep 17 00:00:00 2001 From: Ryan Matsumoto Date: Mon, 6 Feb 2017 15:48:45 -0800 Subject: [PATCH 08/16] Addressed more code review comments --- kms/api-client/functions_test.py | 185 ------------------- kms/api-client/{functions.py => snippets.py} | 75 ++++---- kms/api-client/snippets_test.py | 147 +++++++++++++++ 3 files changed, 186 insertions(+), 221 deletions(-) delete mode 100644 kms/api-client/functions_test.py rename kms/api-client/{functions.py => snippets.py} (80%) create mode 100644 kms/api-client/snippets_test.py diff --git a/kms/api-client/functions_test.py b/kms/api-client/functions_test.py deleted file mode 100644 index 7d75bc4bc09..00000000000 --- a/kms/api-client/functions_test.py +++ /dev/null @@ -1,185 +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 - -import subprocess - -from googleapiclient import discovery - -import functions - - -# Your Google Cloud Platform Key Location -LOCATION = 'global' - -# Your Google Cloud Platform KeyRing name -KEYRING = 'sample-keyring-28' - -# Your Google Cloud Platform CryptoKey name -CRYPTOKEY = 'sample-key-28' - -# 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): - functions.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): - functions.create_cryptokey( - cloud_config.project, LOCATION, KEYRING, CRYPTOKEY) - out, _ = capsys.readouterr() - expected = 'Created CryptoKey projects/{}/'.format(cloud_config.project) - expected += 'locations/{}/keyRings/{}/'.format(LOCATION, KEYRING) - expected += 'cryptoKeys/{}.'.format(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 file names. - plaintext_file_name = str(tmpdir.join("in.txt")) - encrypted_file_name = str(tmpdir.join("out.txt")) - decrypted_file_name = str(tmpdir.join("out2.txt")) - - # Encrypt text and then decrypt it. - functions.encrypt( - cloud_config.project, LOCATION, KEYRING, CRYPTOKEY, - plaintext_file_name, encrypted_file_name) - functions.decrypt( - cloud_config.project, LOCATION, KEYRING, CRYPTOKEY, - encrypted_file_name, decrypted_file_name) - - # Make sure the decrypted text matches the original text. - decrypted_text = open(decrypted_file_name).read() - assert decrypted_text == 'SampleText' - - # Make sure other output is as expected. - out, _ = capsys.readouterr() - assert 'Saved encrypted text to {}.'.format(encrypted_file_name) in out - assert 'Saved decrypted text to {}.'.format(decrypted_file_name) in out - - -def test_encrypt_decrypt_cli(capsys, cloud_config, tmpdir): - # Write to a plaintext file. - tmpdir.join("in.txt").write('SampleText') - - # Construct temporary file names. - plaintext_file_name = str(tmpdir.join("in.txt")) - encrypted_file_name = str(tmpdir.join("out.txt")) - decrypted_file_name = str(tmpdir.join("out2.txt")) - - # Encrypt text and then decrypt it. - project_id = cloud_config.project - encrypt_output = subprocess.check_output( - "python functions.py encrypt {} {} {} {} {} {}".format( - project_id, LOCATION, KEYRING, CRYPTOKEY, plaintext_file_name, - encrypted_file_name), - shell=True) - decrypt_output = subprocess.check_output( - "python functions.py decrypt {} {} {} {} {} {}".format( - project_id, LOCATION, KEYRING, CRYPTOKEY, encrypted_file_name, - decrypted_file_name), - shell=True) - - # Make sure the decrypted text matches the original text. - decrypted_text = open(decrypted_file_name).read() - assert decrypted_text == 'SampleText' - - # Make sure other output is as expected. - expected_encrypt_out = 'Saved encrypted text to {}.'.format( - encrypted_file_name) - assert expected_encrypt_out in encrypt_output.decode('utf-8') - expected_decrypt_out = 'Saved decrypted text to {}.'.format( - decrypted_file_name) - assert expected_decrypt_out in decrypt_output.decode('utf-8') - - -def test_disable_cryptokey_version(capsys, cloud_config): - functions.disable_cryptokey_version( - cloud_config.project, LOCATION, KEYRING, CRYPTOKEY, VERSION) - out, _ = capsys.readouterr() - expected = 'CryptoKeyVersion projects/{}/'.format(cloud_config.project) - expected += 'locations/{}/keyRings/{}/'.format(LOCATION, KEYRING) - expected += 'cryptoKeys/{}/cryptoKeyVersions/{}'.format(CRYPTOKEY, VERSION) - expected += '\'s state has been set to {}.'.format('DISABLED') - assert expected in out - - -def test_destroy_cryptokey_version(capsys, cloud_config): - functions.destroy_cryptokey_version( - cloud_config.project, LOCATION, KEYRING, CRYPTOKEY, VERSION) - out, _ = capsys.readouterr() - expected = 'CryptoKeyVersion projects/{}/'.format(cloud_config.project) - expected += 'locations/{}/keyRings/{}/'.format(LOCATION, KEYRING) - expected += 'cryptoKeys/{}/cryptoKeyVersions/{}'.format(CRYPTOKEY, VERSION) - expected += '\'s state has been set to {}.'.format('DESTROY_SCHEDULED') - assert expected in out - - -def test_add_member_to_cryptokey_policy(capsys, cloud_config): - functions.add_member_to_cryptokey_policy( - cloud_config.project, LOCATION, KEYRING, CRYPTOKEY, MEMBER, ROLE) - out, _ = capsys.readouterr() - expected = 'Member {} added with role {} to policy '.format(MEMBER, ROLE) - expected += 'for CryptoKey {} in KeyRing {}'.format(CRYPTOKEY, KEYRING) - assert expected in out - - # 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( - cloud_config.project, LOCATION, KEYRING, CRYPTOKEY) - - # Get the current IAM policy and verify that the new member has been added - # with the correct role. - 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 - functions.get_keyring_policy(project_id, LOCATION, KEYRING) - out, _ = capsys.readouterr() - expected_roles_exist = 'Printing IAM policy for resource projects/' - expected_roles_exist += '{}/locations/{}/'.format(project_id, LOCATION) - expected_roles_exist += 'keyRings/{}:'.format(KEYRING) - expected_no_roles = 'No roles found for resource projects/' - expected_no_roles += '{}/locations/{}/'.format(project_id, LOCATION) - expected_no_roles += 'keyRings/{}.'.format(KEYRING) - assert (expected_roles_exist in out) or (expected_no_roles in out) diff --git a/kms/api-client/functions.py b/kms/api-client/snippets.py similarity index 80% rename from kms/api-client/functions.py rename to kms/api-client/snippets.py index 9dd2ac8f742..8d5a8cfcb50 100644 --- a/kms/api-client/functions.py +++ b/kms/api-client/snippets.py @@ -22,8 +22,7 @@ # [START kms_create_keyring] def create_keyring(project_id, location, keyring): - """Creates a KeyRing in the given location. Potential locations include: - global, asia-east1, europe-west1, us-central1, and us-east1.""" + """Creates a KeyRing in the given location (e.g. global).""" # Creates an API client for the KMS API. kms_client = discovery.build('cloudkms', 'v1beta1') @@ -36,7 +35,7 @@ def create_keyring(project_id, location, keyring): parent=parent, body={}, keyRingId=keyring) response = request.execute() - print('Created KeyRing {}.'.format(response["name"])) + print('Created KeyRing {}.'.format(response['name'])) # [END kms_create_keyring] @@ -53,11 +52,11 @@ def create_cryptokey(project_id, location, keyring, cryptokey): # Create a CryptoKey for the given KeyRing. request = kms_client.projects().locations().keyRings().cryptoKeys().create( - parent=parent, body={"purpose": 'ENCRYPT_DECRYPT'}, + parent=parent, body={'purpose': 'ENCRYPT_DECRYPT'}, cryptoKeyId=cryptokey) response = request.execute() - print('Created CryptoKey {}.'.format(response["name"])) + print('Created CryptoKey {}.'.format(response['name'])) # [END kms_create_cryptokey] @@ -78,17 +77,17 @@ 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) + 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() + # 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')) + # 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] @@ -112,17 +111,17 @@ def decrypt(project_id, location, keyring, cryptokey, encrypted_file_name, 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() + # 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) + # 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] @@ -138,18 +137,19 @@ def disable_cryptokey_version(project_id, location, keyring, cryptokey, kms_client = discovery.build('cloudkms', 'v1beta1') # Construct the resource name of the CryptoKeyVersion. - name = 'projects/{}/locations/{}/'.format(project_id, location) - name += 'keyRings/{}/cryptoKeys/{}/'.format(keyring, cryptokey) - name += 'cryptoKeyVersions/{}'.format(version) + 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") + name=name, body={'state': 'DISABLED'}, updateMask='state') response = request.execute() print('CryptoKeyVersion {}\'s state has been set to {}.'.format( - name, response["state"])) + name, response['state'])) # [END kms_disable_cryptokey_version] @@ -163,9 +163,10 @@ def destroy_cryptokey_version( kms_client = discovery.build('cloudkms', 'v1beta1') # Construct the resource name of the CryptoKeyVersion. - name = 'projects/{}/locations/{}/'.format(project_id, location) - name += 'keyRings/{}/cryptoKeys/{}/'.format(keyring, cryptokey) - name += 'cryptoKeyVersions/{}'.format(version) + 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() @@ -173,7 +174,7 @@ def destroy_cryptokey_version( response = request.execute() print('CryptoKeyVersion {}\'s state has been set to {}.'.format( - name, response["state"])) + name, response['state'])) # [END kms_destroy_cryptokey_version] @@ -208,11 +209,13 @@ def add_member_to_cryptokey_policy( # Set the new IAM Policy. cryptokeys = kms_client.projects().locations().keyRings().cryptoKeys() request = cryptokeys.setIamPolicy( - resource=parent, body={"policy": policy_response}) + resource=parent, body={'policy': policy_response}) request.execute() - print_msg = 'Member {} added with role {} to policy'.format(member, role) - print_msg += ' for CryptoKey {} in KeyRing {}'.format(cryptokey, keyring) + 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] diff --git a/kms/api-client/snippets_test.py b/kms/api-client/snippets_test.py new file mode 100644 index 00000000000..a11eefa41d9 --- /dev/null +++ b/kms/api-client/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-40' + +# Your Google Cloud Platform CryptoKey name +CRYPTOKEY = 'sample-key-40' + +# 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 51ef3006b9b1066a601eb120ba1a4b70a034df38 Mon Sep 17 00:00:00 2001 From: Ryan Matsumoto Date: Mon, 6 Feb 2017 16:06:03 -0800 Subject: [PATCH 09/16] Formatting change --- kms/api-client/snippets.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/kms/api-client/snippets.py b/kms/api-client/snippets.py index 8d5a8cfcb50..6ac6197a7cc 100644 --- a/kms/api-client/snippets.py +++ b/kms/api-client/snippets.py @@ -213,8 +213,7 @@ def add_member_to_cryptokey_policy( request.execute() print_msg = ( - 'Member {} added with role {} to policy' - ' for CryptoKey {} in KeyRing {}' + '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] From 1be099cc9a6411ddcfe235dab540fedb2b1fbc50 Mon Sep 17 00:00:00 2001 From: Jon Wayne Parrott Date: Mon, 6 Feb 2017 16:19:10 -0800 Subject: [PATCH 10/16] Fix quickstart test Change-Id: Ib79dc1345c9c40547f3fd4e9c3c9a48963a3b399 --- conftest.py | 14 +++++++------- kms/api-client/quickstart_test.py | 4 +--- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/conftest.py b/conftest.py index c8ecd63d0c3..1a39069a5e1 100644 --- a/conftest.py +++ b/conftest.py @@ -80,13 +80,13 @@ def api_client_inject_project_id(cloud_config): the project ID from cloud_config.""" import googleapiclient.http - class ProjectIdInjectingHttpRequest(googleapiclient.http.HttpRequest): - def __init__(self, http, postproc, uri, *args, **kwargs): - uri = uri.replace('YOUR_PROJECT_ID', cloud_config.project) - super(ProjectIdInjectingHttpRequest, self).__init__( - http, postproc, uri, *args, **kwargs) + old_execute = googleapiclient.http.HttpRequest.execute + + def new_execute(self, http=None, num_retries=0): + self.uri = self.uri.replace('YOUR_PROJECT_ID', cloud_config.project) + return old_execute(self, http=http, num_retries=num_retries) with mock.patch( - 'googleapiclient.http.HttpRequest', - new=ProjectIdInjectingHttpRequest): + 'googleapiclient.http.HttpRequest.execute', + new=new_execute): yield diff --git a/kms/api-client/quickstart_test.py b/kms/api-client/quickstart_test.py index d5a196eb395..0db901e6bf3 100644 --- a/kms/api-client/quickstart_test.py +++ b/kms/api-client/quickstart_test.py @@ -13,9 +13,7 @@ # limitations under the License. -def test_quickstart(api_client_inject_project_id, capsys): +def test_quickstart(api_client_inject_project_id): import quickstart quickstart.run_quickstart() - out, _ = capsys.readouterr() - assert 'No key rings found' in out From 8e9f3d0d31a98e1ee58df8a96b116c61de3174f3 Mon Sep 17 00:00:00 2001 From: Jon Wayne Parrott Date: Mon, 6 Feb 2017 16:21:09 -0800 Subject: [PATCH 11/16] Update readme Change-Id: Icf4a66083f56d6f51be76ba1cf3b5dc8daf2c4c1 --- kms/api-client/README.rst.in | 3 +++ 1 file changed, 3 insertions(+) diff --git a/kms/api-client/README.rst.in b/kms/api-client/README.rst.in index 68901cf1154..9489051c2c6 100644 --- a/kms/api-client/README.rst.in +++ b/kms/api-client/README.rst.in @@ -15,3 +15,6 @@ setup: samples: - name: Quickstart file: quickstart.py +- name: Snippets + file: snippets.py + show_help: True From 14fb5c04cf0dbf7930d440ac1577623e24f9b3c5 Mon Sep 17 00:00:00 2001 From: Jon Wayne Parrott Date: Mon, 6 Feb 2017 16:21:26 -0800 Subject: [PATCH 12/16] Add readme Change-Id: I2fbaa55092ef8787f1423d499aa310cab258c0c1 --- kms/api-client/README.rst | 107 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 107 insertions(+) create mode 100644 kms/api-client/README.rst diff --git a/kms/api-client/README.rst b/kms/api-client/README.rst new file mode 100644 index 00000000000..b0d1856e141 --- /dev/null +++ b/kms/api-client/README.rst @@ -0,0 +1,107 @@ +.. 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] {encrypt,decrypt,other} ... + + positional arguments: + {encrypt,decrypt,other} + + optional arguments: + -h, --help show this help message and exit + + + + +.. _Google Cloud SDK: https://cloud.google.com/sdk/ \ No newline at end of file From b44fdfd0f9537b070f68ad6a7d8f7206cf3a98e5 Mon Sep 17 00:00:00 2001 From: Ryan Matsumoto Date: Mon, 6 Feb 2017 18:35:22 -0800 Subject: [PATCH 13/16] Added parsers --- kms/api-client/snippets.py | 81 +++++++++++++++++++++++++++++++++++++- 1 file changed, 79 insertions(+), 2 deletions(-) diff --git a/kms/api-client/snippets.py b/kms/api-client/snippets.py index 6ac6197a7cc..fbb8d94f038 100644 --- a/kms/api-client/snippets.py +++ b/kms/api-client/snippets.py @@ -256,6 +256,17 @@ 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_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') @@ -272,11 +283,50 @@ def get_keyring_policy(project_id, location, keyring): decrypt_parser.add_argument('infile') decrypt_parser.add_argument('outfile') - other_parser = subparsers.add_parser('other') + 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 == 'encrypt': + 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, @@ -292,3 +342,30 @@ def get_keyring_policy(project_id, location, keyring): args.cryptokey, args.infile, args.outfile) + elif args.command == 'disable_cryptokey_version': + disable_cryptokey_version( + args.project_id, + args.location, + args.keyring, + args.crpytoykey, + args.version) + elif args.command == 'destroy_cryptokey_version': + destroy_cryptokey_version( + args.project_id, + args.location, + args.keyring, + args.crpytoykey, + 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) From ce7541726da62a081c4030077f7c90782514326e Mon Sep 17 00:00:00 2001 From: Ryan Matsumoto Date: Mon, 6 Feb 2017 18:44:41 -0800 Subject: [PATCH 14/16] Final minor changes to parsers --- kms/api-client/snippets.py | 4 ++-- kms/api-client/snippets_test.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/kms/api-client/snippets.py b/kms/api-client/snippets.py index fbb8d94f038..6fdad382cf6 100644 --- a/kms/api-client/snippets.py +++ b/kms/api-client/snippets.py @@ -347,14 +347,14 @@ def get_keyring_policy(project_id, location, keyring): args.project_id, args.location, args.keyring, - args.crpytoykey, + args.cryptokey, args.version) elif args.command == 'destroy_cryptokey_version': destroy_cryptokey_version( args.project_id, args.location, args.keyring, - args.crpytoykey, + args.cryptokey, args.version) elif args.command == 'add_member_to_cryptokey_policy': add_member_to_cryptokey_policy( diff --git a/kms/api-client/snippets_test.py b/kms/api-client/snippets_test.py index a11eefa41d9..f66f2a9a6ae 100644 --- a/kms/api-client/snippets_test.py +++ b/kms/api-client/snippets_test.py @@ -22,10 +22,10 @@ LOCATION = 'global' # Your Google Cloud Platform KeyRing name -KEYRING = 'sample-keyring-40' +KEYRING = 'sample-keyring-42' # Your Google Cloud Platform CryptoKey name -CRYPTOKEY = 'sample-key-40' +CRYPTOKEY = 'sample-key-42' # Your Google Cloud Platform CryptoKeyVersion name VERSION = 1 From 842af60d9ff65592b70d545c5a294b20819bf879 Mon Sep 17 00:00:00 2001 From: Ryan Matsumoto Date: Tue, 7 Feb 2017 12:30:52 -0800 Subject: [PATCH 15/16] Added autogenerated README --- kms/api-client/README.rst | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/kms/api-client/README.rst b/kms/api-client/README.rst index b0d1856e141..4c660232385 100644 --- a/kms/api-client/README.rst +++ b/kms/api-client/README.rst @@ -93,10 +93,12 @@ To run this sample: $ python snippets.py - usage: snippets.py [-h] {encrypt,decrypt,other} ... + 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: - {encrypt,decrypt,other} + {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 From 1c5353336b436e30d4ac26004e825364398cbdbe Mon Sep 17 00:00:00 2001 From: Ryan Matsumoto Date: Tue, 7 Feb 2017 13:09:02 -0800 Subject: [PATCH 16/16] Changed snippets_test keyring name and cryptokey name --- kms/api-client/snippets.py | 2 +- kms/api-client/snippets_test.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/kms/api-client/snippets.py b/kms/api-client/snippets.py index 6fdad382cf6..9469b9398dd 100644 --- a/kms/api-client/snippets.py +++ b/kms/api-client/snippets.py @@ -41,7 +41,7 @@ def create_keyring(project_id, location, keyring): # [START kms_create_cryptokey] def create_cryptokey(project_id, location, keyring, cryptokey): - """Creates a CrytoKey within a KeyRing in the given location.""" + """Creates a CryptoKey within a KeyRing in the given location.""" # Creates an API client for the KMS API. kms_client = discovery.build('cloudkms', 'v1beta1') diff --git a/kms/api-client/snippets_test.py b/kms/api-client/snippets_test.py index f66f2a9a6ae..e4deda1c128 100644 --- a/kms/api-client/snippets_test.py +++ b/kms/api-client/snippets_test.py @@ -22,10 +22,10 @@ LOCATION = 'global' # Your Google Cloud Platform KeyRing name -KEYRING = 'sample-keyring-42' +KEYRING = 'sample-keyring-43' # Your Google Cloud Platform CryptoKey name -CRYPTOKEY = 'sample-key-42' +CRYPTOKEY = 'sample-key-43' # Your Google Cloud Platform CryptoKeyVersion name VERSION = 1