def test_add_master_keys_mrk_sdk_default(self):
        """Check that an MRK-aware provider without an explicit discovery_region uses its default region when creating
        new keys if the requested keys are MRKs."""
        grant_tokens = (sentinel.grant_token2, sentinel.grant_token2)
        original_arn = arn_from_str(
            "arn:aws:kms:eu-west-2:222222222222:key/mrk-aaaaaaaa-1111-2222-3333-bbbbbbbbbbbb"
        )
        with patch.object(self.mock_botocore_session,
                          "get_config_variable",
                          return_value="us-west-2") as mock_get_config:
            provider = MRKAwareDiscoveryAwsKmsMasterKeyProvider(
                botocore_session=self.mock_botocore_session,
                grant_tokens=grant_tokens)
            mock_get_config.assert_called_once_with("region")

            master_key = provider._new_master_key(original_arn.to_string())

            # //= compliance/framework/aws-kms/aws-kms-mrk-aware-master-key-provider.txt#2.7
            # //= type=test
            # //# Otherwise if the mode is discovery then
            # //# the AWS Region MUST be the discovery MRK region.

            assert master_key.__class__ == MRKAwareKMSMasterKey
            self.mock_boto3_session.assert_called_with(botocore_session=ANY)
            self.mock_boto3_session_instance.client.assert_called_with(
                "kms",
                region_name=provider.default_region,
                config=provider._user_agent_adding_config,
            )
            assert provider.default_region in master_key._key_id
            assert original_arn.region not in master_key._key_id
            assert master_key.config.grant_tokens is grant_tokens
    def test_add_master_keys_mrk_with_discovery_region(self):
        """Check that an MRK-aware provider with an explicit discovery_region uses its configured region when creating
        new keys if the requested keys are MRKs."""
        grant_tokens = (sentinel.grant_token2, sentinel.grant_token2)
        original_arn = arn_from_str(
            "arn:aws:kms:eu-west-2:222222222222:key/mrk-aaaaaaaa-1111-2222-3333-bbbbbbbbbbbb"
        )
        configured_region = "us-east-1"
        provider = MRKAwareDiscoveryAwsKmsMasterKeyProvider(
            discovery_region=configured_region, grant_tokens=grant_tokens)
        master_key = provider._new_master_key(original_arn.to_string())

        # //= compliance/framework/aws-kms/aws-kms-mrk-aware-master-key-provider.txt#2.7
        # //= type=test
        # //# In discovery mode a AWS KMS MRK Aware Master Key (aws-kms-mrk-aware-
        # //# master-key.md) MUST be returned configured with
        assert master_key.__class__ == MRKAwareKMSMasterKey
        self.mock_boto3_session.assert_called_with(botocore_session=ANY)
        self.mock_boto3_session_instance.client.assert_called_with(
            "kms",
            region_name=configured_region,
            config=provider._user_agent_adding_config,
        )
        assert configured_region in master_key._key_id
        assert original_arn.region not in master_key._key_id
        assert master_key.config.grant_tokens is grant_tokens
    def test_add_master_keys_invalid_arn(self, non_arn):
        """Check that the provider throws an error when creating a new key with an invalid arn."""
        # //= compliance/framework/aws-kms/aws-kms-mrk-aware-master-key-provider.txt#2.7
        # //= type=test
        # //# In discovery mode, the requested
        # //# AWS KMS key identifier MUST be a well formed AWS KMS ARN.

        provider = MRKAwareDiscoveryAwsKmsMasterKeyProvider(
            discovery_region="us-east-1")
        with pytest.raises(MalformedArnError):
            provider._new_master_key(non_arn)
 def test_init_sdk_default_not_found(self):
     """Check that an MRK-aware provider without an explicit discovery_region fails to initialize if it cannot
     find a default region for the AWS SDK."""
     # //= compliance/framework/aws-kms/aws-kms-mrk-aware-master-key-provider.txt#2.6
     # //= type=test
     # //# If an AWS SDK Default Region can not be obtained
     # //# initialization MUST fail.
     with pytest.raises(ConfigMismatchError) as excinfo:
         MRKAwareDiscoveryAwsKmsMasterKeyProvider(
             botocore_session=self.botocore_no_region_session)
     excinfo.match("Failed to determine default discovery region")
    def test_add_master_keys_srk(self):
        """Check that the MRK-aware provider uses the original key region when creating new keys if the requested
        keys are SRKs."""
        original_arn = "arn:aws:kms:eu-west-2:222222222222:key/aaaaaaaa-1111-2222-3333-bbbbbbbbbbbb"
        provider = MRKAwareDiscoveryAwsKmsMasterKeyProvider(
            discovery_region="us-east-1")
        master_key = provider._new_master_key(original_arn)

        # //= compliance/framework/aws-kms/aws-kms-mrk-aware-master-key-provider.txt#2.7
        # //= type=test
        # //# Otherwise if the requested AWS KMS key
        # //# identifier is identified as a multi-Region key (aws-kms-key-
        # //# arn.md#identifying-an-aws-kms-multi-region-key), then AWS Region MUST
        # //# be the region from the AWS KMS key ARN stored in the provider info
        # //# from the encrypted data key.
        assert master_key.__class__ == MRKAwareKMSMasterKey
        self.mock_boto3_session.assert_called_with(botocore_session=ANY)
        self.mock_boto3_session_instance.client.assert_called_with(
            "kms",
            region_name="eu-west-2",
            config=provider._user_agent_adding_config,
        )
        assert master_key._key_id == original_arn
예제 #6
0
def aws_kms_master_key_provider(
        discovery=True,  # type: bool
        **kwargs  # type: List[Union[Text, str]]
):
    # type: (...) -> Union[MRKAwareDiscoveryAwsKmsMasterKeyProvider, MRKAwareStrictAwsKmsMasterKeyProvider]
    """Apply post-processing to transform ``KMSMasterKeyProvider``-specific values from CLI
    arguments to valid ``KMSMasterKeyProvider`` parameters, then call ``KMSMasterKeyProvider``
    with those parameters.

    :param bool discovery: Return a MRKAwareDiscoveryAwsKmsMasterKeyProvider
    :param dict kwargs: Named parameters collected from CLI arguments as prepared
        in aws_encryption_sdk_cli.internal.master_key_parsing._parse_master_key_providers_from_args
    :rtype: aws_encryption_sdk.key_providers.kms.BaseKMSMasterKeyProvider
    """
    kwargs = copy.deepcopy(kwargs)
    try:
        profile_names = kwargs.pop("profile")
        if len(profile_names) != 1:
            raise BadUserArgumentError(
                "Only one profile may be specified per master key provider configuration. {} provided."
                .format(len(profile_names)))
        profile_name = profile_names[0]  # type: Optional[Text]
    except KeyError:
        profile_name = None

    botocore_session = botocore.session.Session(profile=profile_name)
    botocore_session.user_agent_extra = USER_AGENT_SUFFIX
    kwargs["botocore_session"] = botocore_session

    try:
        region_name = kwargs.pop("region")
        if len(region_name) != 1:
            raise BadUserArgumentError(
                "Only one region may be specified per master key provider configuration. {} provided."
                .format(len(region_name)))
        kwargs["region_names"] = region_name
    except KeyError:
        pass
    if discovery:
        accounts = kwargs.pop("discovery-account", None)
        partition = kwargs.pop("discovery-partition", None)
        if accounts and partition:
            discovery_filter = DiscoveryFilter(account_ids=accounts,
                                               partition=partition)
            kwargs["discovery_filter"] = discovery_filter  # type: ignore

        return MRKAwareDiscoveryAwsKmsMasterKeyProvider(**kwargs)
    return MRKAwareStrictAwsKmsMasterKeyProvider(**kwargs)
    def _kms_mrk_aware_discovery_master_key_from_spec(self, _keys):
        # type: (KeysManifest) -> KMSMasterKey
        """Build an AWS KMS master key using this specification.

        :param KeySpec key_spec: Key specification to use with this master key
        :return: AWS KMS master key based on this specification
        :rtype: KMSMasterKey
        :raises TypeError: if this is not an AWS KMS master key specification
        """
        if not self.type_name == "aws-kms-mrk-aware-discovery":
            raise TypeError(
                "This is not an AWS KMS MRK-aware discovery master key")

        return MRKAwareDiscoveryAwsKmsMasterKeyProvider(
            discovery_region=self.default_mrk_region,
            discovery_filter=self.discovery_filter)
 def test_init_implicit_discovery_region(self):
     """Check that an MRK-aware provider without an explicit discovery_region uses the default SDK region."""
     with patch.object(
             self.mock_botocore_session,
             "get_config_variable",
             return_value=sentinel.default_region) as mock_get_config:
         test = MRKAwareDiscoveryAwsKmsMasterKeyProvider(
             botocore_session=self.mock_botocore_session)
         mock_get_config.assert_called_once_with("region")
         # //= compliance/framework/aws-kms/aws-kms-mrk-aware-master-key-provider.txt#2.6
         # //= type=test
         # //# In discovery mode
         # //# if a default MRK Region is not configured the AWS SDK Default Region
         # //# MUST be used.
         assert test.default_region is sentinel.default_region
         assert test.config.discovery_region is sentinel.default_region
"""Helper utilities for interacting with AWS KMS."""
try:
    from aws_encryption_sdk.identifiers import AlgorithmSuite
except ImportError:
    from aws_encryption_sdk.identifiers import Algorithm as AlgorithmSuite
from aws_encryption_sdk.key_providers.kms import (
    DiscoveryAwsKmsMasterKeyProvider,
    MRKAwareDiscoveryAwsKmsMasterKeyProvider,
    StrictAwsKmsMasterKeyProvider,
)

from awses_test_vectors.internal.defaults import ENCODING

# This lets us easily use a single boto3 client per region for all KMS master keys.
KMS_MASTER_KEY_PROVIDER = DiscoveryAwsKmsMasterKeyProvider()
KMS_MRK_AWARE_MASTER_KEY_PROVIDER = MRKAwareDiscoveryAwsKmsMasterKeyProvider(
    discovery_region="us-west-2")


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(
 def test_init_explicit_discovery_region(self):
     provider = MRKAwareDiscoveryAwsKmsMasterKeyProvider(
         discovery_region="us-east-1")
     assert provider.config.discovery_region == "us-east-1"
def encrypt_decrypt(mrk_arn, mrk_arn_second_region, source_plaintext):
    """Illustrates usage of KMS Multi-Region Keys.

    :param str mrk_arn: Amazon Resource Name (ARN) of the first KMS MRK
    :param str mrk_arn_second_region: Amazon Resource Name (ARN) of a related KMS MRK in a different region
    :param bytes source_plaintext: Data to encrypt
    """
    # Encrypt in the first region

    # Set up an encryption client with an explicit commitment policy. Note that if you do not explicitly choose a
    # commitment policy, REQUIRE_ENCRYPT_REQUIRE_DECRYPT is used by default.
    client = aws_encryption_sdk.EncryptionSDKClient(
        commitment_policy=CommitmentPolicy.REQUIRE_ENCRYPT_REQUIRE_DECRYPT)

    # For this example, set mrk_arn to be a Multi-Region key.
    # Multi-Region keys have a distinctive key ID that begins with 'mrk'.
    # For example: "arn:aws:kms:us-east-1:111122223333:key/mrk-1234abcd12ab34cd56ef1234567890ab".

    # Create a Strict Multi-Region Key Aware Master Key Provider which targets the Multi-Region key ARN.
    kwargs = dict(key_ids=[mrk_arn])
    strict_key_provider = MRKAwareStrictAwsKmsMasterKeyProvider(**kwargs)

    # Encrypt the plaintext using the AWS Encryption SDK. It returns the encrypted message and the header
    ciphertext, _ = client.encrypt(source=source_plaintext,
                                   key_provider=strict_key_provider)

    # Decrypt in a second region

    # For this example, set mrk_arn_second_region to be Multi-Region key related to key_arn.
    # Related multi-Region keys have the same key ID. Their key ARNs differs only in the Region field.
    # For example: "arn:aws:kms:us-west-2:111122223333:key/mrk-1234abcd12ab34cd56ef1234567890ab"

    # Create a Strict Multi-Region Key Aware Master Key Provider which targets the Multi-Region key in the second region
    kwargs = dict(key_ids=[mrk_arn_second_region])
    strict_key_provider_region_2 = MRKAwareStrictAwsKmsMasterKeyProvider(
        **kwargs)

    # Decrypt your ciphertext
    plaintext, _ = client.decrypt(source=ciphertext,
                                  key_provider=strict_key_provider_region_2)

    # Verify that the original message and the decrypted message are the same
    assert source_plaintext == plaintext

    # Decrypt in discovery mode in a second region

    # First determine what region you want to perform discovery in, as well as what
    # accounts and partition you want to allow if using a Discovery Filter.
    # In this example, we just want to use whatever region, account, and partition
    # our second key is in, in order to ensure we can discover it.
    # Note that the ARN itself is never used in the configuration.
    arn = arn_from_str(mrk_arn_second_region)
    discovery_region = arn.region
    filter_accounts = [arn.account_id]
    filter_partition = arn.partition

    # Configure a Discovery Region and optional Discovery Filter
    decrypt_kwargs = dict(
        discovery_filter=DiscoveryFilter(account_ids=filter_accounts,
                                         partition=filter_partition),
        discovery_region=discovery_region,
    )

    # Create an MRK-aware master key provider in discovery mode that targets the second region.
    # This will cause the provider to try to decrypt using this region whenever it encounters an MRK.
    discovery_key_provider = MRKAwareDiscoveryAwsKmsMasterKeyProvider(
        **decrypt_kwargs)

    # Decrypt the encrypted message using the AWS Encryption SDK. It returns the decrypted message and the header.
    plaintext, _ = client.decrypt(source=ciphertext,
                                  key_provider=discovery_key_provider)

    # Verify that the original message and the decrypted message are the same
    assert source_plaintext == plaintext