OLD | NEW |
(Empty) | |
| 1 # Copyright (c) 2014 Amazon.com, Inc. or its affiliates. All Rights Reserved |
| 2 # |
| 3 # Permission is hereby granted, free of charge, to any person obtaining a |
| 4 # copy of this software and associated documentation files (the |
| 5 # "Software"), to deal in the Software without restriction, including |
| 6 # without limitation the rights to use, copy, modify, merge, publish, dis- |
| 7 # tribute, sublicense, and/or sell copies of the Software, and to permit |
| 8 # persons to whom the Software is furnished to do so, subject to the fol- |
| 9 # lowing conditions: |
| 10 # |
| 11 # The above copyright notice and this permission notice shall be included |
| 12 # in all copies or substantial portions of the Software. |
| 13 # |
| 14 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS |
| 15 # OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL- |
| 16 # ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT |
| 17 # SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, |
| 18 # WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
| 19 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS |
| 20 # IN THE SOFTWARE. |
| 21 # |
| 22 |
| 23 import boto |
| 24 from boto.compat import json |
| 25 from boto.connection import AWSQueryConnection |
| 26 from boto.regioninfo import RegionInfo |
| 27 from boto.exception import JSONResponseError |
| 28 from boto.kms import exceptions |
| 29 from boto.compat import six |
| 30 import base64 |
| 31 |
| 32 |
| 33 class KMSConnection(AWSQueryConnection): |
| 34 """ |
| 35 AWS Key Management Service |
| 36 AWS Key Management Service (KMS) is an encryption and key |
| 37 management web service. This guide describes the KMS actions that |
| 38 you can call programmatically. For general information about KMS, |
| 39 see (need an address here). For the KMS developer guide, see (need |
| 40 address here). |
| 41 |
| 42 AWS provides SDKs that consist of libraries and sample code for |
| 43 various programming languages and platforms (Java, Ruby, .Net, |
| 44 iOS, Android, etc.). The SDKs provide a convenient way to create |
| 45 programmatic access to KMS and AWS. For example, the SDKs take |
| 46 care of tasks such as signing requests (see below), managing |
| 47 errors, and retrying requests automatically. For more information |
| 48 about the AWS SDKs, including how to download and install them, |
| 49 see `Tools for Amazon Web Services`_. |
| 50 |
| 51 We recommend that you use the AWS SDKs to make programmatic API |
| 52 calls to KMS. However, you can also use the KMS Query API to make |
| 53 to make direct calls to the KMS web service. |
| 54 |
| 55 **Signing Requests** |
| 56 |
| 57 Requests must be signed by using an access key ID and a secret |
| 58 access key. We strongly recommend that you do not use your AWS |
| 59 account access key ID and secret key for everyday work with KMS. |
| 60 Instead, use the access key ID and secret access key for an IAM |
| 61 user, or you can use the AWS Security Token Service to generate |
| 62 temporary security credentials that you can use to sign requests. |
| 63 |
| 64 All KMS operations require `Signature Version 4`_. |
| 65 |
| 66 **Recording API Requests** |
| 67 |
| 68 KMS supports AWS CloudTrail, a service that records AWS API calls |
| 69 and related events for your AWS account and delivers them to an |
| 70 Amazon S3 bucket that you specify. By using the information |
| 71 collected by CloudTrail, you can determine what requests were made |
| 72 to KMS, who made the request, when it was made, and so on. To |
| 73 learn more about CloudTrail, including how to turn it on and find |
| 74 your log files, see the `AWS CloudTrail User Guide`_ |
| 75 |
| 76 **Additional Resources** |
| 77 |
| 78 For more information about credentials and request signing, see |
| 79 the following: |
| 80 |
| 81 |
| 82 + `AWS Security Credentials`_. This topic provides general |
| 83 information about the types of credentials used for accessing AWS. |
| 84 + `AWS Security Token Service`_. This guide describes how to |
| 85 create and use temporary security credentials. |
| 86 + `Signing AWS API Requests`_. This set of topics walks you |
| 87 through the process of signing a request using an access key ID |
| 88 and a secret access key. |
| 89 """ |
| 90 APIVersion = "2014-11-01" |
| 91 DefaultRegionName = "us-east-1" |
| 92 DefaultRegionEndpoint = "kms.us-east-1.amazonaws.com" |
| 93 ServiceName = "KMS" |
| 94 TargetPrefix = "TrentService" |
| 95 ResponseError = JSONResponseError |
| 96 |
| 97 _faults = { |
| 98 "InvalidGrantTokenException": exceptions.InvalidGrantTokenException, |
| 99 "DisabledException": exceptions.DisabledException, |
| 100 "LimitExceededException": exceptions.LimitExceededException, |
| 101 "DependencyTimeoutException": exceptions.DependencyTimeoutException, |
| 102 "InvalidMarkerException": exceptions.InvalidMarkerException, |
| 103 "AlreadyExistsException": exceptions.AlreadyExistsException, |
| 104 "InvalidCiphertextException": exceptions.InvalidCiphertextException, |
| 105 "KeyUnavailableException": exceptions.KeyUnavailableException, |
| 106 "InvalidAliasNameException": exceptions.InvalidAliasNameException, |
| 107 "UnsupportedOperationException": exceptions.UnsupportedOperationExceptio
n, |
| 108 "InvalidArnException": exceptions.InvalidArnException, |
| 109 "KMSInternalException": exceptions.KMSInternalException, |
| 110 "InvalidKeyUsageException": exceptions.InvalidKeyUsageException, |
| 111 "MalformedPolicyDocumentException": exceptions.MalformedPolicyDocumentEx
ception, |
| 112 "NotFoundException": exceptions.NotFoundException, |
| 113 } |
| 114 |
| 115 |
| 116 def __init__(self, **kwargs): |
| 117 region = kwargs.pop('region', None) |
| 118 if not region: |
| 119 region = RegionInfo(self, self.DefaultRegionName, |
| 120 self.DefaultRegionEndpoint) |
| 121 |
| 122 if 'host' not in kwargs or kwargs['host'] is None: |
| 123 kwargs['host'] = region.endpoint |
| 124 |
| 125 super(KMSConnection, self).__init__(**kwargs) |
| 126 self.region = region |
| 127 |
| 128 def _required_auth_capability(self): |
| 129 return ['hmac-v4'] |
| 130 |
| 131 def create_alias(self, alias_name, target_key_id): |
| 132 """ |
| 133 Creates a display name for a customer master key. An alias can |
| 134 be used to identify a key and should be unique. The console |
| 135 enforces a one-to-one mapping between the alias and a key. An |
| 136 alias name can contain only alphanumeric characters, forward |
| 137 slashes (/), underscores (_), and dashes (-). An alias must |
| 138 start with the word "alias" followed by a forward slash |
| 139 (alias/). An alias that begins with "aws" after the forward |
| 140 slash (alias/aws...) is reserved by Amazon Web Services (AWS). |
| 141 |
| 142 :type alias_name: string |
| 143 :param alias_name: String that contains the display name. Aliases that |
| 144 begin with AWS are reserved. |
| 145 |
| 146 :type target_key_id: string |
| 147 :param target_key_id: An identifier of the key for which you are |
| 148 creating the alias. This value cannot be another alias. |
| 149 |
| 150 """ |
| 151 params = { |
| 152 'AliasName': alias_name, |
| 153 'TargetKeyId': target_key_id, |
| 154 } |
| 155 return self.make_request(action='CreateAlias', |
| 156 body=json.dumps(params)) |
| 157 |
| 158 def create_grant(self, key_id, grantee_principal, |
| 159 retiring_principal=None, operations=None, |
| 160 constraints=None, grant_tokens=None): |
| 161 """ |
| 162 Adds a grant to a key to specify who can access the key and |
| 163 under what conditions. Grants are alternate permission |
| 164 mechanisms to key policies. If absent, access to the key is |
| 165 evaluated based on IAM policies attached to the user. By |
| 166 default, grants do not expire. Grants can be listed, retired, |
| 167 or revoked as indicated by the following APIs. Typically, when |
| 168 you are finished using a grant, you retire it. When you want |
| 169 to end a grant immediately, revoke it. For more information |
| 170 about grants, see `Grants`_. |
| 171 |
| 172 #. ListGrants |
| 173 #. RetireGrant |
| 174 #. RevokeGrant |
| 175 |
| 176 :type key_id: string |
| 177 :param key_id: A unique key identifier for a customer master key. This |
| 178 value can be a globally unique identifier, an ARN, or an alias. |
| 179 |
| 180 :type grantee_principal: string |
| 181 :param grantee_principal: Principal given permission by the grant to |
| 182 use the key identified by the `keyId` parameter. |
| 183 |
| 184 :type retiring_principal: string |
| 185 :param retiring_principal: Principal given permission to retire the |
| 186 grant. For more information, see RetireGrant. |
| 187 |
| 188 :type operations: list |
| 189 :param operations: List of operations permitted by the grant. This can |
| 190 be any combination of one or more of the following values: |
| 191 |
| 192 #. Decrypt |
| 193 #. Encrypt |
| 194 #. GenerateDataKey |
| 195 #. GenerateDataKeyWithoutPlaintext |
| 196 #. ReEncryptFrom |
| 197 #. ReEncryptTo |
| 198 #. CreateGrant |
| 199 |
| 200 :type constraints: dict |
| 201 :param constraints: Specifies the conditions under which the actions |
| 202 specified by the `Operations` parameter are allowed. |
| 203 |
| 204 :type grant_tokens: list |
| 205 :param grant_tokens: List of grant tokens. |
| 206 |
| 207 """ |
| 208 params = { |
| 209 'KeyId': key_id, |
| 210 'GranteePrincipal': grantee_principal, |
| 211 } |
| 212 if retiring_principal is not None: |
| 213 params['RetiringPrincipal'] = retiring_principal |
| 214 if operations is not None: |
| 215 params['Operations'] = operations |
| 216 if constraints is not None: |
| 217 params['Constraints'] = constraints |
| 218 if grant_tokens is not None: |
| 219 params['GrantTokens'] = grant_tokens |
| 220 return self.make_request(action='CreateGrant', |
| 221 body=json.dumps(params)) |
| 222 |
| 223 def create_key(self, policy=None, description=None, key_usage=None): |
| 224 """ |
| 225 Creates a customer master key. Customer master keys can be |
| 226 used to encrypt small amounts of data (less than 4K) directly, |
| 227 but they are most commonly used to encrypt or envelope data |
| 228 keys that are then used to encrypt customer data. For more |
| 229 information about data keys, see GenerateDataKey and |
| 230 GenerateDataKeyWithoutPlaintext. |
| 231 |
| 232 :type policy: string |
| 233 :param policy: Policy to be attached to the key. This is required and |
| 234 delegates back to the account. The key is the root of trust. |
| 235 |
| 236 :type description: string |
| 237 :param description: Description of the key. We recommend that you |
| 238 choose a description that helps your customer decide whether the |
| 239 key is appropriate for a task. |
| 240 |
| 241 :type key_usage: string |
| 242 :param key_usage: Specifies the intended use of the key. Currently this |
| 243 defaults to ENCRYPT/DECRYPT, and only symmetric encryption and |
| 244 decryption are supported. |
| 245 |
| 246 """ |
| 247 params = {} |
| 248 if policy is not None: |
| 249 params['Policy'] = policy |
| 250 if description is not None: |
| 251 params['Description'] = description |
| 252 if key_usage is not None: |
| 253 params['KeyUsage'] = key_usage |
| 254 return self.make_request(action='CreateKey', |
| 255 body=json.dumps(params)) |
| 256 |
| 257 def decrypt(self, ciphertext_blob, encryption_context=None, |
| 258 grant_tokens=None): |
| 259 """ |
| 260 Decrypts ciphertext. Ciphertext is plaintext that has been |
| 261 previously encrypted by using the Encrypt function. |
| 262 |
| 263 :type ciphertext_blob: blob |
| 264 :param ciphertext_blob: Ciphertext including metadata. |
| 265 |
| 266 :type encryption_context: map |
| 267 :param encryption_context: The encryption context. If this was |
| 268 specified in the Encrypt function, it must be specified here or the |
| 269 decryption operation will fail. For more information, see |
| 270 `Encryption Context`_. |
| 271 |
| 272 :type grant_tokens: list |
| 273 :param grant_tokens: A list of grant tokens that represent grants which |
| 274 can be used to provide long term permissions to perform decryption. |
| 275 |
| 276 """ |
| 277 if not isinstance(ciphertext_blob, six.binary_type): |
| 278 raise TypeError( |
| 279 "Value of argument ``ciphertext_blob`` " |
| 280 "must be of type %s." % six.binary_type) |
| 281 ciphertext_blob = base64.b64encode(ciphertext_blob) |
| 282 params = {'CiphertextBlob': ciphertext_blob, } |
| 283 if encryption_context is not None: |
| 284 params['EncryptionContext'] = encryption_context |
| 285 if grant_tokens is not None: |
| 286 params['GrantTokens'] = grant_tokens |
| 287 response = self.make_request(action='Decrypt', |
| 288 body=json.dumps(params)) |
| 289 if response.get('Plaintext') is not None: |
| 290 response['Plaintext'] = base64.b64decode( |
| 291 response['Plaintext'].encode('utf-8')) |
| 292 return response |
| 293 |
| 294 def delete_alias(self, alias_name): |
| 295 """ |
| 296 Deletes the specified alias. |
| 297 |
| 298 :type alias_name: string |
| 299 :param alias_name: The alias to be deleted. |
| 300 |
| 301 """ |
| 302 params = {'AliasName': alias_name, } |
| 303 return self.make_request(action='DeleteAlias', |
| 304 body=json.dumps(params)) |
| 305 |
| 306 def describe_key(self, key_id): |
| 307 """ |
| 308 Provides detailed information about the specified customer |
| 309 master key. |
| 310 |
| 311 :type key_id: string |
| 312 :param key_id: Unique identifier of the customer master key to be |
| 313 described. This can be an ARN, an alias, or a globally unique |
| 314 identifier. |
| 315 |
| 316 """ |
| 317 params = {'KeyId': key_id, } |
| 318 return self.make_request(action='DescribeKey', |
| 319 body=json.dumps(params)) |
| 320 |
| 321 def disable_key(self, key_id): |
| 322 """ |
| 323 Marks a key as disabled, thereby preventing its use. |
| 324 |
| 325 :type key_id: string |
| 326 :param key_id: Unique identifier of the customer master key to be |
| 327 disabled. This can be an ARN, an alias, or a globally unique |
| 328 identifier. |
| 329 |
| 330 """ |
| 331 params = {'KeyId': key_id, } |
| 332 return self.make_request(action='DisableKey', |
| 333 body=json.dumps(params)) |
| 334 |
| 335 def disable_key_rotation(self, key_id): |
| 336 """ |
| 337 Disables rotation of the specified key. |
| 338 |
| 339 :type key_id: string |
| 340 :param key_id: Unique identifier of the customer master key for which |
| 341 rotation is to be disabled. This can be an ARN, an alias, or a |
| 342 globally unique identifier. |
| 343 |
| 344 """ |
| 345 params = {'KeyId': key_id, } |
| 346 return self.make_request(action='DisableKeyRotation', |
| 347 body=json.dumps(params)) |
| 348 |
| 349 def enable_key(self, key_id): |
| 350 """ |
| 351 Marks a key as enabled, thereby permitting its use. You can |
| 352 have up to 25 enabled keys at one time. |
| 353 |
| 354 :type key_id: string |
| 355 :param key_id: Unique identifier of the customer master key to be |
| 356 enabled. This can be an ARN, an alias, or a globally unique |
| 357 identifier. |
| 358 |
| 359 """ |
| 360 params = {'KeyId': key_id, } |
| 361 return self.make_request(action='EnableKey', |
| 362 body=json.dumps(params)) |
| 363 |
| 364 def enable_key_rotation(self, key_id): |
| 365 """ |
| 366 Enables rotation of the specified customer master key. |
| 367 |
| 368 :type key_id: string |
| 369 :param key_id: Unique identifier of the customer master key for which |
| 370 rotation is to be enabled. This can be an ARN, an alias, or a |
| 371 globally unique identifier. |
| 372 |
| 373 """ |
| 374 params = {'KeyId': key_id, } |
| 375 return self.make_request(action='EnableKeyRotation', |
| 376 body=json.dumps(params)) |
| 377 |
| 378 def encrypt(self, key_id, plaintext, encryption_context=None, |
| 379 grant_tokens=None): |
| 380 """ |
| 381 Encrypts plaintext into ciphertext by using a customer master |
| 382 key. |
| 383 |
| 384 :type key_id: string |
| 385 :param key_id: Unique identifier of the customer master. This can be an |
| 386 ARN, an alias, or the Key ID. |
| 387 |
| 388 :type plaintext: blob |
| 389 :param plaintext: Data to be encrypted. |
| 390 |
| 391 :type encryption_context: map |
| 392 :param encryption_context: Name:value pair that specifies the |
| 393 encryption context to be used for authenticated encryption. For |
| 394 more information, see `Authenticated Encryption`_. |
| 395 |
| 396 :type grant_tokens: list |
| 397 :param grant_tokens: A list of grant tokens that represent grants which |
| 398 can be used to provide long term permissions to perform encryption. |
| 399 |
| 400 """ |
| 401 if not isinstance(plaintext, six.binary_type): |
| 402 raise TypeError( |
| 403 "Value of argument ``plaintext`` " |
| 404 "must be of type %s." % six.binary_type) |
| 405 plaintext = base64.b64encode(plaintext) |
| 406 params = {'KeyId': key_id, 'Plaintext': plaintext, } |
| 407 if encryption_context is not None: |
| 408 params['EncryptionContext'] = encryption_context |
| 409 if grant_tokens is not None: |
| 410 params['GrantTokens'] = grant_tokens |
| 411 response = self.make_request(action='Encrypt', |
| 412 body=json.dumps(params)) |
| 413 if response.get('CiphertextBlob') is not None: |
| 414 response['CiphertextBlob'] = base64.b64decode( |
| 415 response['CiphertextBlob'].encode('utf-8')) |
| 416 return response |
| 417 |
| 418 def generate_data_key(self, key_id, encryption_context=None, |
| 419 number_of_bytes=None, key_spec=None, |
| 420 grant_tokens=None): |
| 421 """ |
| 422 Generates a secure data key. Data keys are used to encrypt and |
| 423 decrypt data. They are wrapped by customer master keys. |
| 424 |
| 425 :type key_id: string |
| 426 :param key_id: Unique identifier of the key. This can be an ARN, an |
| 427 alias, or a globally unique identifier. |
| 428 |
| 429 :type encryption_context: map |
| 430 :param encryption_context: Name/value pair that contains additional |
| 431 data to be authenticated during the encryption and decryption |
| 432 processes that use the key. This value is logged by AWS CloudTrail |
| 433 to provide context around the data encrypted by the key. |
| 434 |
| 435 :type number_of_bytes: integer |
| 436 :param number_of_bytes: Integer that contains the number of bytes to |
| 437 generate. Common values are 128, 256, 512, 1024 and so on. 1024 is |
| 438 the current limit. |
| 439 |
| 440 :type key_spec: string |
| 441 :param key_spec: Value that identifies the encryption algorithm and key |
| 442 size to generate a data key for. Currently this can be AES_128 or |
| 443 AES_256. |
| 444 |
| 445 :type grant_tokens: list |
| 446 :param grant_tokens: A list of grant tokens that represent grants which |
| 447 can be used to provide long term permissions to generate a key. |
| 448 |
| 449 """ |
| 450 params = {'KeyId': key_id, } |
| 451 if encryption_context is not None: |
| 452 params['EncryptionContext'] = encryption_context |
| 453 if number_of_bytes is not None: |
| 454 params['NumberOfBytes'] = number_of_bytes |
| 455 if key_spec is not None: |
| 456 params['KeySpec'] = key_spec |
| 457 if grant_tokens is not None: |
| 458 params['GrantTokens'] = grant_tokens |
| 459 response = self.make_request(action='GenerateDataKey', |
| 460 body=json.dumps(params)) |
| 461 if response.get('CiphertextBlob') is not None: |
| 462 response['CiphertextBlob'] = base64.b64decode( |
| 463 response['CiphertextBlob'].encode('utf-8')) |
| 464 if response.get('Plaintext') is not None: |
| 465 response['Plaintext'] = base64.b64decode( |
| 466 response['Plaintext'].encode('utf-8')) |
| 467 return response |
| 468 |
| 469 def generate_data_key_without_plaintext(self, key_id, |
| 470 encryption_context=None, |
| 471 key_spec=None, |
| 472 number_of_bytes=None, |
| 473 grant_tokens=None): |
| 474 """ |
| 475 Returns a key wrapped by a customer master key without the |
| 476 plaintext copy of that key. To retrieve the plaintext, see |
| 477 GenerateDataKey. |
| 478 |
| 479 :type key_id: string |
| 480 :param key_id: Unique identifier of the key. This can be an ARN, an |
| 481 alias, or a globally unique identifier. |
| 482 |
| 483 :type encryption_context: map |
| 484 :param encryption_context: Name:value pair that contains additional |
| 485 data to be authenticated during the encryption and decryption |
| 486 processes. |
| 487 |
| 488 :type key_spec: string |
| 489 :param key_spec: Value that identifies the encryption algorithm and key |
| 490 size. Currently this can be AES_128 or AES_256. |
| 491 |
| 492 :type number_of_bytes: integer |
| 493 :param number_of_bytes: Integer that contains the number of bytes to |
| 494 generate. Common values are 128, 256, 512, 1024 and so on. |
| 495 |
| 496 :type grant_tokens: list |
| 497 :param grant_tokens: A list of grant tokens that represent grants which |
| 498 can be used to provide long term permissions to generate a key. |
| 499 |
| 500 """ |
| 501 params = {'KeyId': key_id, } |
| 502 if encryption_context is not None: |
| 503 params['EncryptionContext'] = encryption_context |
| 504 if key_spec is not None: |
| 505 params['KeySpec'] = key_spec |
| 506 if number_of_bytes is not None: |
| 507 params['NumberOfBytes'] = number_of_bytes |
| 508 if grant_tokens is not None: |
| 509 params['GrantTokens'] = grant_tokens |
| 510 response = self.make_request(action='GenerateDataKeyWithoutPlaintext', |
| 511 body=json.dumps(params)) |
| 512 if response.get('CiphertextBlob') is not None: |
| 513 response['CiphertextBlob'] = base64.b64decode( |
| 514 response['CiphertextBlob'].encode('utf-8')) |
| 515 return response |
| 516 |
| 517 def generate_random(self, number_of_bytes=None): |
| 518 """ |
| 519 Generates an unpredictable byte string. |
| 520 |
| 521 :type number_of_bytes: integer |
| 522 :param number_of_bytes: Integer that contains the number of bytes to |
| 523 generate. Common values are 128, 256, 512, 1024 and so on. The |
| 524 current limit is 1024 bytes. |
| 525 |
| 526 """ |
| 527 params = {} |
| 528 if number_of_bytes is not None: |
| 529 params['NumberOfBytes'] = number_of_bytes |
| 530 response = self.make_request(action='GenerateRandom', |
| 531 body=json.dumps(params)) |
| 532 if response.get('Plaintext') is not None: |
| 533 response['Plaintext'] = base64.b64decode( |
| 534 response['Plaintext'].encode('utf-8')) |
| 535 return response |
| 536 |
| 537 def get_key_policy(self, key_id, policy_name): |
| 538 """ |
| 539 Retrieves a policy attached to the specified key. |
| 540 |
| 541 :type key_id: string |
| 542 :param key_id: Unique identifier of the key. This can be an ARN, an |
| 543 alias, or a globally unique identifier. |
| 544 |
| 545 :type policy_name: string |
| 546 :param policy_name: String that contains the name of the policy. |
| 547 Currently, this must be "default". Policy names can be discovered |
| 548 by calling ListKeyPolicies. |
| 549 |
| 550 """ |
| 551 params = {'KeyId': key_id, 'PolicyName': policy_name, } |
| 552 return self.make_request(action='GetKeyPolicy', |
| 553 body=json.dumps(params)) |
| 554 |
| 555 def get_key_rotation_status(self, key_id): |
| 556 """ |
| 557 Retrieves a Boolean value that indicates whether key rotation |
| 558 is enabled for the specified key. |
| 559 |
| 560 :type key_id: string |
| 561 :param key_id: Unique identifier of the key. This can be an ARN, an |
| 562 alias, or a globally unique identifier. |
| 563 |
| 564 """ |
| 565 params = {'KeyId': key_id, } |
| 566 return self.make_request(action='GetKeyRotationStatus', |
| 567 body=json.dumps(params)) |
| 568 |
| 569 def list_aliases(self, limit=None, marker=None): |
| 570 """ |
| 571 Lists all of the key aliases in the account. |
| 572 |
| 573 :type limit: integer |
| 574 :param limit: Specify this parameter when paginating results to |
| 575 indicate the maximum number of aliases you want in each response. |
| 576 If there are additional aliases beyond the maximum you specify, the |
| 577 `Truncated` response element will be set to `true.` |
| 578 |
| 579 :type marker: string |
| 580 :param marker: Use this parameter when paginating results, and only in |
| 581 a subsequent request after you've received a response where the |
| 582 results are truncated. Set it to the value of the `NextMarker` |
| 583 element in the response you just received. |
| 584 |
| 585 """ |
| 586 params = {} |
| 587 if limit is not None: |
| 588 params['Limit'] = limit |
| 589 if marker is not None: |
| 590 params['Marker'] = marker |
| 591 return self.make_request(action='ListAliases', |
| 592 body=json.dumps(params)) |
| 593 |
| 594 def list_grants(self, key_id, limit=None, marker=None): |
| 595 """ |
| 596 List the grants for a specified key. |
| 597 |
| 598 :type key_id: string |
| 599 :param key_id: Unique identifier of the key. This can be an ARN, an |
| 600 alias, or a globally unique identifier. |
| 601 |
| 602 :type limit: integer |
| 603 :param limit: Specify this parameter only when paginating results to |
| 604 indicate the maximum number of grants you want listed in the |
| 605 response. If there are additional grants beyond the maximum you |
| 606 specify, the `Truncated` response element will be set to `true.` |
| 607 |
| 608 :type marker: string |
| 609 :param marker: Use this parameter only when paginating results, and |
| 610 only in a subsequent request after you've received a response where |
| 611 the results are truncated. Set it to the value of the `NextMarker` |
| 612 in the response you just received. |
| 613 |
| 614 """ |
| 615 params = {'KeyId': key_id, } |
| 616 if limit is not None: |
| 617 params['Limit'] = limit |
| 618 if marker is not None: |
| 619 params['Marker'] = marker |
| 620 return self.make_request(action='ListGrants', |
| 621 body=json.dumps(params)) |
| 622 |
| 623 def list_key_policies(self, key_id, limit=None, marker=None): |
| 624 """ |
| 625 Retrieves a list of policies attached to a key. |
| 626 |
| 627 :type key_id: string |
| 628 :param key_id: Unique identifier of the key. This can be an ARN, an |
| 629 alias, or a globally unique identifier. |
| 630 |
| 631 :type limit: integer |
| 632 :param limit: Specify this parameter only when paginating results to |
| 633 indicate the maximum number of policies you want listed in the |
| 634 response. If there are additional policies beyond the maximum you |
| 635 specify, the `Truncated` response element will be set to `true.` |
| 636 |
| 637 :type marker: string |
| 638 :param marker: Use this parameter only when paginating results, and |
| 639 only in a subsequent request after you've received a response where |
| 640 the results are truncated. Set it to the value of the `NextMarker` |
| 641 in the response you just received. |
| 642 |
| 643 """ |
| 644 params = {'KeyId': key_id, } |
| 645 if limit is not None: |
| 646 params['Limit'] = limit |
| 647 if marker is not None: |
| 648 params['Marker'] = marker |
| 649 return self.make_request(action='ListKeyPolicies', |
| 650 body=json.dumps(params)) |
| 651 |
| 652 def list_keys(self, limit=None, marker=None): |
| 653 """ |
| 654 Lists the customer master keys. |
| 655 |
| 656 :type limit: integer |
| 657 :param limit: Specify this parameter only when paginating results to |
| 658 indicate the maximum number of keys you want listed in the |
| 659 response. If there are additional keys beyond the maximum you |
| 660 specify, the `Truncated` response element will be set to `true.` |
| 661 |
| 662 :type marker: string |
| 663 :param marker: Use this parameter only when paginating results, and |
| 664 only in a subsequent request after you've received a response where |
| 665 the results are truncated. Set it to the value of the `NextMarker` |
| 666 in the response you just received. |
| 667 |
| 668 """ |
| 669 params = {} |
| 670 if limit is not None: |
| 671 params['Limit'] = limit |
| 672 if marker is not None: |
| 673 params['Marker'] = marker |
| 674 return self.make_request(action='ListKeys', |
| 675 body=json.dumps(params)) |
| 676 |
| 677 def put_key_policy(self, key_id, policy_name, policy): |
| 678 """ |
| 679 Attaches a policy to the specified key. |
| 680 |
| 681 :type key_id: string |
| 682 :param key_id: Unique identifier of the key. This can be an ARN, an |
| 683 alias, or a globally unique identifier. |
| 684 |
| 685 :type policy_name: string |
| 686 :param policy_name: Name of the policy to be attached. Currently, the |
| 687 only supported name is "default". |
| 688 |
| 689 :type policy: string |
| 690 :param policy: The policy, in JSON format, to be attached to the key. |
| 691 |
| 692 """ |
| 693 params = { |
| 694 'KeyId': key_id, |
| 695 'PolicyName': policy_name, |
| 696 'Policy': policy, |
| 697 } |
| 698 return self.make_request(action='PutKeyPolicy', |
| 699 body=json.dumps(params)) |
| 700 |
| 701 def re_encrypt(self, ciphertext_blob, destination_key_id, |
| 702 source_encryption_context=None, |
| 703 destination_encryption_context=None, grant_tokens=None): |
| 704 """ |
| 705 Encrypts data on the server side with a new customer master |
| 706 key without exposing the plaintext of the data on the client |
| 707 side. The data is first decrypted and then encrypted. This |
| 708 operation can also be used to change the encryption context of |
| 709 a ciphertext. |
| 710 |
| 711 :type ciphertext_blob: blob |
| 712 :param ciphertext_blob: Ciphertext of the data to re-encrypt. |
| 713 |
| 714 :type source_encryption_context: map |
| 715 :param source_encryption_context: Encryption context used to encrypt |
| 716 and decrypt the data specified in the `CiphertextBlob` parameter. |
| 717 |
| 718 :type destination_key_id: string |
| 719 :param destination_key_id: Key identifier of the key used to re-encrypt |
| 720 the data. |
| 721 |
| 722 :type destination_encryption_context: map |
| 723 :param destination_encryption_context: Encryption context to be used |
| 724 when the data is re-encrypted. |
| 725 |
| 726 :type grant_tokens: list |
| 727 :param grant_tokens: Grant tokens that identify the grants that have |
| 728 permissions for the encryption and decryption process. |
| 729 |
| 730 """ |
| 731 if not isinstance(ciphertext_blob, six.binary_type): |
| 732 raise TypeError( |
| 733 "Value of argument ``ciphertext_blob`` " |
| 734 "must be of type %s." % six.binary_type) |
| 735 ciphertext_blob = base64.b64encode(ciphertext_blob) |
| 736 params = { |
| 737 'CiphertextBlob': ciphertext_blob, |
| 738 'DestinationKeyId': destination_key_id, |
| 739 } |
| 740 if source_encryption_context is not None: |
| 741 params['SourceEncryptionContext'] = source_encryption_context |
| 742 if destination_encryption_context is not None: |
| 743 params['DestinationEncryptionContext'] = destination_encryption_cont
ext |
| 744 if grant_tokens is not None: |
| 745 params['GrantTokens'] = grant_tokens |
| 746 response = self.make_request(action='ReEncrypt', |
| 747 body=json.dumps(params)) |
| 748 if response.get('CiphertextBlob') is not None: |
| 749 response['CiphertextBlob'] = base64.b64decode( |
| 750 response['CiphertextBlob'].encode('utf-8')) |
| 751 return response |
| 752 |
| 753 def retire_grant(self, grant_token): |
| 754 """ |
| 755 Retires a grant. You can retire a grant when you're done using |
| 756 it to clean up. You should revoke a grant when you intend to |
| 757 actively deny operations that depend on it. |
| 758 |
| 759 :type grant_token: string |
| 760 :param grant_token: Token that identifies the grant to be retired. |
| 761 |
| 762 """ |
| 763 params = {'GrantToken': grant_token, } |
| 764 return self.make_request(action='RetireGrant', |
| 765 body=json.dumps(params)) |
| 766 |
| 767 def revoke_grant(self, key_id, grant_id): |
| 768 """ |
| 769 Revokes a grant. You can revoke a grant to actively deny |
| 770 operations that depend on it. |
| 771 |
| 772 :type key_id: string |
| 773 :param key_id: Unique identifier of the key associated with the grant. |
| 774 |
| 775 :type grant_id: string |
| 776 :param grant_id: Identifier of the grant to be revoked. |
| 777 |
| 778 """ |
| 779 params = {'KeyId': key_id, 'GrantId': grant_id, } |
| 780 return self.make_request(action='RevokeGrant', |
| 781 body=json.dumps(params)) |
| 782 |
| 783 def update_key_description(self, key_id, description): |
| 784 """ |
| 785 |
| 786 |
| 787 :type key_id: string |
| 788 :param key_id: |
| 789 |
| 790 :type description: string |
| 791 :param description: |
| 792 |
| 793 """ |
| 794 params = {'KeyId': key_id, 'Description': description, } |
| 795 return self.make_request(action='UpdateKeyDescription', |
| 796 body=json.dumps(params)) |
| 797 |
| 798 def make_request(self, action, body): |
| 799 headers = { |
| 800 'X-Amz-Target': '%s.%s' % (self.TargetPrefix, action), |
| 801 'Host': self.region.endpoint, |
| 802 'Content-Type': 'application/x-amz-json-1.1', |
| 803 'Content-Length': str(len(body)), |
| 804 } |
| 805 http_request = self.build_base_http_request( |
| 806 method='POST', path='/', auth_path='/', params={}, |
| 807 headers=headers, data=body) |
| 808 response = self._mexe(http_request, sender=None, |
| 809 override_num_retries=10) |
| 810 response_body = response.read().decode('utf-8') |
| 811 boto.log.debug(response_body) |
| 812 if response.status == 200: |
| 813 if response_body: |
| 814 return json.loads(response_body) |
| 815 else: |
| 816 json_body = json.loads(response_body) |
| 817 fault_name = json_body.get('__type', None) |
| 818 exception_class = self._faults.get(fault_name, self.ResponseError) |
| 819 raise exception_class(response.status, response.reason, |
| 820 body=json_body) |
| 821 |
OLD | NEW |