def test_add_master_keys_class(self, mock_client): """Check that the MRK-aware provider creates MRKAwareKMSMasterKeys""" mock_client.return_value = self.mock_boto3_client_instance key_id = "arn:aws:kms:eu-west-2:222222222222:key/mrk-aaaaaaaa-1111-2222-3333-bbbbbbbbbbbb" provider = StrictAwsKmsMasterKeyProvider(key_ids=[key_id]) master_key = provider._new_master_key(key_id) assert master_key.__class__ == KMSMasterKey
def test_init_with_regionless_key_ids_and_region_names(): key_ids = ("alias/key_1", ) region_names = ("test-region-1", ) provider = StrictAwsKmsMasterKeyProvider(region_names=region_names, key_ids=key_ids) assert provider.master_key( "alias/key_1").config.client.meta.region_name == region_names[0]
def test_decrypt_failure_strict_mismatched_key_id(self): """Test that a Strict KMS Master Key Provider fails to decrypt an EDK when it has not been configured with the correct key id """ cmk_arn = get_cmk_arn() encrypt_provider = StrictAwsKmsMasterKeyProvider(key_ids=[cmk_arn]) ciphertext, _ = aws_encryption_sdk.EncryptionSDKClient().encrypt( source=VALUES["plaintext_128"], key_provider=encrypt_provider, encryption_context=VALUES["encryption_context"], frame_length=1024, ) # Check that we can decrypt the ciphertext using the original provider plaintext, _ = aws_encryption_sdk.EncryptionSDKClient().decrypt( source=ciphertext, key_provider=encrypt_provider ) assert plaintext == VALUES["plaintext_128"] # Check that we cannot decrypt the ciphertext using a non-discovery provider without the correct key_id second_cmk_arn = cmk_arn + "-doesnotexist" decrypt_provider = StrictAwsKmsMasterKeyProvider(key_ids=[second_cmk_arn]) with pytest.raises(DecryptKeyError) as excinfo: aws_encryption_sdk.EncryptionSDKClient().decrypt(source=ciphertext, key_provider=decrypt_provider) excinfo.match("Unable to decrypt any data key")
def setup_kms_master_key_provider_with_duplicate_keys(num_keys): """Reads the test_values config file and builds the requested KMS Master Key Provider with multiple copies of the requested key.""" assert num_keys > 1 cmk_arn = get_cmk_arn() provider = StrictAwsKmsMasterKeyProvider(key_ids=[cmk_arn]) for _ in range(num_keys - 1): provider.add_master_key_provider( StrictAwsKmsMasterKeyProvider(key_ids=[cmk_arn])) return provider
def test_decrypt_success_discovery_no_filter(self): """Test that a Discovery KMS Master Key Provider in unfiltered discovery mode can decrypt a valid EDK. """ cmk_arn = get_cmk_arn() encrypt_provider = StrictAwsKmsMasterKeyProvider(key_ids=[cmk_arn]) ciphertext, _ = aws_encryption_sdk.EncryptionSDKClient().encrypt( source=VALUES["plaintext_128"], key_provider=encrypt_provider, encryption_context=VALUES["encryption_context"], frame_length=1024, ) # Check that we can decrypt the ciphertext using the original provider plaintext, _ = aws_encryption_sdk.EncryptionSDKClient().decrypt( source=ciphertext, key_provider=encrypt_provider ) assert plaintext == VALUES["plaintext_128"] # Check that we can decrypt the ciphertext using a discovery provider with no filter decrypt_provider = DiscoveryAwsKmsMasterKeyProvider() plaintext, _ = aws_encryption_sdk.EncryptionSDKClient().decrypt( source=ciphertext, key_provider=decrypt_provider ) assert plaintext == VALUES["plaintext_128"]
def test_decrypt_success_discovery_filter(self): """Test that a Discovery KMS Master Key Provider in filtered discovery mode can decrypt a ciphertext when it is configured with the correct account id and partition. """ cmk_arn = get_cmk_arn() encrypt_provider = StrictAwsKmsMasterKeyProvider(key_ids=[cmk_arn]) ciphertext, _ = aws_encryption_sdk.EncryptionSDKClient().encrypt( source=VALUES["plaintext_128"], key_provider=encrypt_provider, encryption_context=VALUES["encryption_context"], frame_length=1024, ) # Check that we can decrypt the ciphertext using the original provider plaintext, _ = aws_encryption_sdk.EncryptionSDKClient().decrypt( source=ciphertext, key_provider=encrypt_provider ) assert plaintext == VALUES["plaintext_128"] # Check that we can decrypt the ciphertext using a discovery provider that allows this account and partition arn = arn_from_str(cmk_arn) discovery_filter = DiscoveryFilter(partition=arn.partition, account_ids=[arn.account_id]) decrypt_provider = DiscoveryAwsKmsMasterKeyProvider(discovery_filter=discovery_filter) plaintext, _ = aws_encryption_sdk.EncryptionSDKClient().decrypt( source=ciphertext, key_provider=decrypt_provider ) assert plaintext == VALUES["plaintext_128"]
def test_init_null_key_id_fails(self): key_ids = ( "arn:aws:kms:us-east-1:222222222222:key/aaaaaaaa-1111-2222-3333-bbbbbbbbbbbb", None) with pytest.raises(ConfigMismatchError) as excinfo: StrictAwsKmsMasterKeyProvider(key_ids=key_ids) excinfo.match("Key ids must be valid AWS KMS ARNs")
def test_init_empty_key_ids_fails(self): # //= compliance/framework/aws-kms/aws-kms-mrk-aware-master-key-provider.txt#2.6 # //= type=test # //# The key id list MUST NOT be empty or null in strict mode. with pytest.raises(ConfigMismatchError) as excinfo: StrictAwsKmsMasterKeyProvider(key_ids=[]) excinfo.match("To enable strict mode you must provide key ids")
def test_decrypt_failure_discovery_disallowed_partition(self): """Test that a KMS Master Key Provider in filtered discovery mode fails to decrypt an EDK if the EDK was wrapped by a KMS Master Key in an AWS partition that is not allowed by the filter. """ cmk_arn = get_cmk_arn() encrypt_provider = StrictAwsKmsMasterKeyProvider(key_ids=[cmk_arn]) ciphertext, _ = aws_encryption_sdk.EncryptionSDKClient().encrypt( source=VALUES["plaintext_128"], key_provider=encrypt_provider, encryption_context=VALUES["encryption_context"], frame_length=1024, ) # Check that we can decrypt the ciphertext using the original provider plaintext, _ = aws_encryption_sdk.EncryptionSDKClient().decrypt( source=ciphertext, key_provider=encrypt_provider ) assert plaintext == VALUES["plaintext_128"] # Check that we cannot decrypt the ciphertext using a discovery provider that does not match this key's # partition arn = arn_from_str(cmk_arn) discovery_filter = DiscoveryFilter(partition="aws-cn", account_ids=[arn.account_id]) decrypt_provider = DiscoveryAwsKmsMasterKeyProvider(discovery_filter=discovery_filter) with pytest.raises(MasterKeyProviderError) as excinfo: aws_encryption_sdk.EncryptionSDKClient().decrypt(source=ciphertext, key_provider=decrypt_provider) excinfo.match("not allowed by this Master Key Provider")
def arn_from_key_id(key_id): # type: (str) -> str """Determine the KMS CMK Arn for the identified key ID. To avoid needing additional KMS permissions, we just call ``generate_data_key`` using a master key identified by ``key_id``. :param str key_id: Original key ID :returns: Full Arn for KMS CMK that key ID identifies :rtype: str """ provider = StrictAwsKmsMasterKeyProvider(key_ids=[key_id]) encrypted_data_key = provider.master_key(key_id.encode(ENCODING)).generate_data_key( algorithm=AlgorithmSuite.AES_256_GCM_IV12_TAG16_HKDF_SHA384_ECDSA_P384, encryption_context={} ) return encrypted_data_key.key_provider.key_info.decode(ENCODING)
def test_init_with_key_ids(self, mock_add_keys): key_ids = ( "arn:aws:kms:us-east-1:222222222222:key/aaaaaaaa-1111-2222-3333-bbbbbbbbbbbb", "arn:aws:kms:us-east-1:333333333333:key/aaaaaaaa-1111-2222-3333-bbbbbbbbbbbb", ) test = StrictAwsKmsMasterKeyProvider(key_ids=key_ids) assert not test.vend_masterkey_on_decrypt mock_add_keys.assert_called_once_with(key_ids)
def test_init_empty_string_key_id_fails(self): # //= compliance/framework/aws-kms/aws-kms-mrk-aware-master-key-provider.txt#2.6 # //= type=test # //# The key id list MUST NOT contain any null or empty string values. key_ids = ( "arn:aws:kms:us-east-1:222222222222:key/aaaaaaaa-1111-2222-3333-bbbbbbbbbbbb", "") with pytest.raises(ConfigMismatchError) as excinfo: StrictAwsKmsMasterKeyProvider(key_ids=key_ids) excinfo.match("Key ids must be valid AWS KMS ARNs")
def setup_kms_master_key_provider(cache=True): """Reads the test_values config file and builds the requested KMS Master Key Provider.""" global _KMS_MKP # pylint: disable=global-statement if cache and _KMS_MKP is not None: return _KMS_MKP cmk_arn = get_cmk_arn() kms_master_key_provider = StrictAwsKmsMasterKeyProvider(key_ids=[cmk_arn]) if cache: _KMS_MKP = kms_master_key_provider return kms_master_key_provider
def test_init_with_discovery_fails(self, mock_add_keys): key_ids = ( "arn:aws:kms:us-east-1:222222222222:key/aaaaaaaa-1111-2222-3333-bbbbbbbbbbbb", "arn:aws:kms:us-east-1:333333333333:key/aaaaaaaa-1111-2222-3333-bbbbbbbbbbbb", ) discovery_filter = DiscoveryFilter(account_ids=["1234"], partition="aws") with pytest.raises(ConfigMismatchError) as excinfo: StrictAwsKmsMasterKeyProvider(key_ids=key_ids, discovery_filter=discovery_filter) excinfo.match( "To enable discovery mode, use a DiscoveryAwsKmsMasterKeyProvider") mock_add_keys.assert_not_called()
def kms_master_key_provider(cache: Optional[bool] = True): """Build the expected KMS Master Key Provider based on environment variables.""" global _KMS_MKP # pylint: disable=global-statement if cache and _KMS_MKP is not None: return _KMS_MKP cmk_arn = get_cmk_arn() _kms_master_key_provider = StrictAwsKmsMasterKeyProvider(key_ids=[cmk_arn]) if cache: _KMS_MKP = _kms_master_key_provider return _kms_master_key_provider
def test_init_with_key_ids(self, mock_add_keys): key_ids = ( "arn:aws:kms:us-east-1:222222222222:key/aaaaaaaa-1111-2222-3333-bbbbbbbbbbbb", "arn:aws:kms:us-east-1:333333333333:key/aaaaaaaa-1111-2222-3333-bbbbbbbbbbbb", ) test = StrictAwsKmsMasterKeyProvider(key_ids=key_ids) # //= compliance/framework/aws-kms/aws-kms-mrk-aware-master-key-provider.txt#2.8 # //= type=test # //# If the configured mode is strict this function MUST return a # //# list of master keys obtained by calling Get Master Key (aws-kms-mrk- # //# aware-master-key-provider.md#get-master-key) for each AWS KMS key # //# identifier in the configured key ids assert not test.vend_masterkey_on_decrypt mock_add_keys.assert_called_once_with(key_ids)
def setup_kms_master_key_provider_with_botocore_session(cache=True): """Reads the test_values config file and builds the requested KMS Master Key Provider with botocore_session.""" global _KMS_MKP_BOTO # pylint: disable=global-statement if cache and _KMS_MKP_BOTO is not None: return _KMS_MKP_BOTO cmk_arn = get_cmk_arn() kms_master_key_provider = StrictAwsKmsMasterKeyProvider( key_ids=[cmk_arn], botocore_session=botocore.session.Session()) if cache: _KMS_MKP_BOTO = kms_master_key_provider return kms_master_key_provider
def test_init_with_discovery_region_fails(self, mock_add_keys): # //= compliance/framework/aws-kms/aws-kms-mrk-aware-master-key-provider.txt#2.6 # //= type=test # //# A default MRK Region MUST NOT be configured in strict mode. key_ids = ( "arn:aws:kms:us-east-1:222222222222:key/aaaaaaaa-1111-2222-3333-bbbbbbbbbbbb", "arn:aws:kms:us-east-1:333333333333:key/aaaaaaaa-1111-2222-3333-bbbbbbbbbbbb", ) with pytest.raises(ConfigMismatchError) as excinfo: StrictAwsKmsMasterKeyProvider(key_ids=key_ids, discovery_region="us-east-1") excinfo.match( "To enable MRK-aware discovery mode, use a MRKAwareDiscoveryAwsKmsMasterKeyProvider" ) mock_add_keys.assert_not_called()
def test_encrypt_failure_unknown_cmk(self): """Test that a Master Key Provider returns the correct error when one of the keys with which it was configured is unable to encrypt """ cmk_arn = get_cmk_arn() second_cmk_arn = cmk_arn + "-doesnotexist" provider = StrictAwsKmsMasterKeyProvider(key_ids=[cmk_arn, second_cmk_arn]) with pytest.raises(EncryptKeyError) as excinfo: aws_encryption_sdk.EncryptionSDKClient().encrypt( source=VALUES["plaintext_128"], key_provider=provider, encryption_context=VALUES["encryption_context"], frame_length=1024, ) excinfo.match("Master Key {key_id} unable to encrypt".format(key_id=second_cmk_arn))
def test_init_with_discovery_fails(self, mock_add_keys): # //= compliance/framework/aws-kms/aws-kms-mrk-aware-master-key-provider.txt#2.6 # //= type=test # //# A discovery filter MUST NOT be configured in strict mode. key_ids = ( "arn:aws:kms:us-east-1:222222222222:key/aaaaaaaa-1111-2222-3333-bbbbbbbbbbbb", "arn:aws:kms:us-east-1:333333333333:key/aaaaaaaa-1111-2222-3333-bbbbbbbbbbbb", ) discovery_filter = DiscoveryFilter(account_ids=["1234"], partition="aws") with pytest.raises(ConfigMismatchError) as excinfo: StrictAwsKmsMasterKeyProvider(key_ids=key_ids, discovery_filter=discovery_filter) excinfo.match( "To enable discovery mode, use a DiscoveryAwsKmsMasterKeyProvider") mock_add_keys.assert_not_called()
def test_decrypt_success_strict_matching_key_id(self): """Test that a Strict KMS Master Key Provider can successfully decrypt an EDK when it has been configured with the correct key id """ cmk_arn = get_cmk_arn() provider = StrictAwsKmsMasterKeyProvider(key_ids=[cmk_arn]) ciphertext, _ = aws_encryption_sdk.EncryptionSDKClient().encrypt( source=VALUES["plaintext_128"], key_provider=provider, encryption_context=VALUES["encryption_context"], frame_length=1024, ) plaintext, _ = aws_encryption_sdk.EncryptionSDKClient().decrypt( source=ciphertext, key_provider=self.kms_master_key_provider ) assert plaintext == VALUES["plaintext_128"]
def test_init_bare_fails(self): with pytest.raises(ConfigMismatchError) as excinfo: StrictAwsKmsMasterKeyProvider() excinfo.match("To enable strict mode you must provide key ids")