Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 84d43ad

Browse filesBrowse files
author
Jon Wayne Parrott
authored
Refactor cloud client storage samples. (GoogleCloudPlatform#421)
1 parent 848b086 commit 84d43ad
Copy full SHA for 84d43ad

File tree

Expand file treeCollapse file tree

6 files changed

+251
-147
lines changed
Filter options
Expand file treeCollapse file tree

6 files changed

+251
-147
lines changed

‎storage/cloud-client/customer_supplied_keys.py

Copy file name to clipboardExpand all lines: storage/cloud-client/customer_supplied_keys.py
-107Lines changed: 0 additions & 107 deletions
This file was deleted.

‎storage/cloud-client/customer_supplied_keys_test.py

Copy file name to clipboardExpand all lines: storage/cloud-client/customer_supplied_keys_test.py
-24Lines changed: 0 additions & 24 deletions
This file was deleted.

‎storage/cloud-client/encryption.py

Copy file name to clipboard
+161Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
#!/usr/bin/env python
2+
3+
# Copyright 2016 Google, Inc.
4+
#
5+
# Licensed under the Apache License, Version 2.0 (the "License");
6+
# you may not use this file except in compliance with the License.
7+
# You may obtain a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing, software
12+
# distributed under the License is distributed on an "AS IS" BASIS,
13+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
# See the License for the specific language governing permissions and
15+
# limitations under the License.
16+
17+
"""This application demonstrates how to upload and download encrypted blobs
18+
(objects) in Google Cloud Storage.
19+
20+
Use `generate-encryption-key` to generate an example key:
21+
22+
python encryption.py generate-encryption-key
23+
24+
Then use the key to upload and download files encrypted with a custom key.
25+
26+
For more information, see the README.md under /storage and the documentation
27+
at https://cloud.google.com/storage/docs/encryption.
28+
"""
29+
30+
import argparse
31+
import base64
32+
import os
33+
34+
from gcloud import storage
35+
36+
37+
def generate_encryption_key():
38+
"""Generates a 256 bit (32 byte) AES encryption key and prints the
39+
base64 representation.
40+
41+
This is included for demonstration purposes. You should generate your own
42+
key. Please remember that encryption keys should be handled with a
43+
comprehensive security policy.
44+
"""
45+
key = os.urandom(32)
46+
encoded_key = base64.b64encode(key).decode('utf-8')
47+
print('Base 64 encoded encryption key: {}'.format(encoded_key))
48+
49+
50+
def upload_encrypted_blob(bucket_name, source_file_name,
51+
destination_blob_name, base64_encryption_key):
52+
"""Uploads a file to a Google Cloud Storage bucket using a custom
53+
encryption key.
54+
55+
The file will be encrypted by Google Cloud Storage and only
56+
retrievable using the provided encryption key.
57+
"""
58+
storage_client = storage.Client()
59+
bucket = storage_client.get_bucket(bucket_name)
60+
blob = bucket.blob(destination_blob_name)
61+
62+
# Encryption key must be an AES256 key represented as a bytestring with
63+
# 32 bytes. Since it's passed in as a base64 encoded string, it needs
64+
# to be decoded.
65+
encryption_key = base64.b64decode(base64_encryption_key)
66+
67+
blob.upload_from_filename(
68+
source_file_name, encryption_key=encryption_key)
69+
70+
print('File {} uploaded to {}.'.format(
71+
source_file_name,
72+
destination_blob_name))
73+
74+
75+
def download_encrypted_blob(bucket_name, source_blob_name,
76+
destination_file_name, base64_encryption_key):
77+
"""Downloads a previously-encrypted blob from Google Cloud Storage.
78+
79+
The encryption key provided must be the same key provided when uploading
80+
the blob.
81+
"""
82+
storage_client = storage.Client()
83+
bucket = storage_client.get_bucket(bucket_name)
84+
blob = bucket.blob(source_blob_name)
85+
86+
# Encryption key must be an AES256 key represented as a bytestring with
87+
# 32 bytes. Since it's passed in as a base64 encoded string, it needs
88+
# to be decoded.
89+
encryption_key = base64.b64decode(base64_encryption_key)
90+
91+
blob.download_to_filename(
92+
destination_file_name, encryption_key=encryption_key)
93+
94+
print('Blob {} downloaded to {}.'.format(
95+
source_blob_name,
96+
destination_file_name))
97+
98+
99+
def rotate_encryption_key(bucket_name, blob_name, base64_encryption_key,
100+
base64_new_encryption_key):
101+
"""Performs a key rotation by re-writing an encrypted blob with a new
102+
encryption key."""
103+
raise NotImplementedError(
104+
'This is currently not available using the Cloud Client Library.')
105+
106+
107+
if __name__ == '__main__':
108+
parser = argparse.ArgumentParser(
109+
description=__doc__,
110+
formatter_class=argparse.RawDescriptionHelpFormatter)
111+
subparsers = parser.add_subparsers(dest='command')
112+
113+
subparsers.add_parser(
114+
'generate-encryption-key', help=generate_encryption_key.__doc__)
115+
116+
upload_parser = subparsers.add_parser(
117+
'upload', help=upload_encrypted_blob.__doc__)
118+
upload_parser.add_argument(
119+
'bucket_name', help='Your cloud storage bucket.')
120+
upload_parser.add_argument('source_file_name')
121+
upload_parser.add_argument('destination_blob_name')
122+
upload_parser.add_argument('base64_encryption_key')
123+
124+
download_parser = subparsers.add_parser(
125+
'download', help=download_encrypted_blob.__doc__)
126+
download_parser.add_argument(
127+
'bucket_name', help='Your cloud storage bucket.')
128+
download_parser.add_argument('source_blob_name')
129+
download_parser.add_argument('destination_file_name')
130+
download_parser.add_argument('base64_encryption_key')
131+
132+
rotate_parser = subparsers.add_parser(
133+
'rotate', help=rotate_encryption_key.__doc__)
134+
rotate_parser.add_argument(
135+
'bucket_name', help='Your cloud storage bucket.')
136+
download_parser.add_argument('blob_name')
137+
download_parser.add_argument('base64_encryption_key')
138+
download_parser.add_argument('base64_new_encryption_key')
139+
140+
args = parser.parse_args()
141+
142+
if args.command == 'generate-encryption-key':
143+
generate_encryption_key()
144+
elif args.command == 'upload':
145+
upload_encrypted_blob(
146+
args.bucket_name,
147+
args.source_file_name,
148+
args.destination_blob_name,
149+
args.base64_encryption_key)
150+
elif args.command == 'download':
151+
download_encrypted_blob(
152+
args.bucket_name,
153+
args.source_blob_name,
154+
args.destination_file_name,
155+
args.base64_encryption_key)
156+
elif args.command == 'rotate':
157+
rotate_encryption_key(
158+
args.bucket_name,
159+
args.blob_name,
160+
args.base64_encryption_key,
161+
args.base64_new_encryption_key)
+67Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
# Copyright 2016 Google, Inc.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
import base64
16+
import tempfile
17+
18+
import encryption
19+
from gcloud import storage
20+
import pytest
21+
22+
TEST_ENCRYPTION_KEY = 'brtJUWneL92g5q0N2gyDSnlPSYAiIVZ/cWgjyZNeMy0='
23+
TEST_ENCRYPTION_KEY_DECODED = base64.b64decode(TEST_ENCRYPTION_KEY)
24+
25+
26+
def test_generate_encryption_key(capsys):
27+
encryption.generate_encryption_key()
28+
out, _ = capsys.readouterr()
29+
encoded_key = out.split(':', 1).pop().strip()
30+
key = base64.b64decode(encoded_key)
31+
assert len(key) == 32, 'Returned key should be 32 bytes'
32+
33+
34+
def test_upload_encrypted_blob(cloud_config):
35+
with tempfile.NamedTemporaryFile() as source_file:
36+
source_file.write(b'test')
37+
38+
encryption.upload_encrypted_blob(
39+
cloud_config.storage_bucket,
40+
source_file.name,
41+
'test_encrypted_upload_blob',
42+
TEST_ENCRYPTION_KEY)
43+
44+
45+
@pytest.fixture
46+
def test_blob(cloud_config):
47+
"""Provides a pre-existing blob in the test bucket."""
48+
bucket = storage.Client().bucket(cloud_config.storage_bucket)
49+
blob = bucket.blob('encrption_test_sigil')
50+
content = 'Hello, is it me you\'re looking for?'
51+
blob.upload_from_string(
52+
content,
53+
encryption_key=TEST_ENCRYPTION_KEY_DECODED)
54+
return blob.name, content
55+
56+
57+
def test_download_blob(test_blob, cloud_config):
58+
test_blob_name, test_blob_content = test_blob
59+
with tempfile.NamedTemporaryFile() as dest_file:
60+
encryption.download_encrypted_blob(
61+
cloud_config.storage_bucket,
62+
test_blob_name,
63+
dest_file.name,
64+
TEST_ENCRYPTION_KEY)
65+
66+
downloaded_content = dest_file.read().decode('utf-8')
67+
assert downloaded_content == test_blob_content

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.