def _process_caching_config(raw_caching_config):
    # type: (RAW_CONFIG) -> CACHING_CONFIG
    """Applies additional processing to prepare the caching configuration.

    :param list raw_caching_config: Unprocessed caching configuration
    :returns: Processed caching configuration
    :rtype: dict
    :raises ParameterParseError: if invalid parameter name is found
    :raises ParameterParseError: if either capacity or max_age are not defined
    """
    _cast_types = {
        "capacity": int,
        "max_messages_encrypted": int,
        "max_bytes_encrypted": int,
        "max_age": float
    }
    parsed_config = _parse_and_collapse_config(raw_caching_config)

    if "capacity" not in parsed_config or "max_age" not in parsed_config:
        raise ParameterParseError(
            'If enabling caching, both "capacity" and "max_age" are required')

    caching_config = {}  # type: Dict[str, Union[str, int, float]]
    for key, value in parsed_config.items():
        try:
            caching_config[key] = _cast_types[key](value)
        except KeyError:
            raise ParameterParseError(
                'Invalid caching configuration key: "{}"'.format(key))
    return caching_config
Esempio n. 2
0
def _process_discovery_args(parsed_args):
    """
    Process rules for discovery filters on Account ID and Partition ID
    :param parsed_args:
    :return: Dict[str, Union[str, List[str]]]
    :raises: ParameterParseError
    """
    if parsed_args.discovery is False:
        if parsed_args.discovery_account:
            raise ParameterParseError(
                "Error: --discovery-account is only available if discovery is enabled"
            )
        if parsed_args.discovery_partition:
            raise ParameterParseError(
                "Error: --discovery-partition is only available if discovery is enabled"
            )
        return None
    if not parsed_args.discovery_partition and not parsed_args.discovery_account:
        return None
    if parsed_args.discovery_partition and not parsed_args.discovery_account:
        raise ParameterParseError(
            "Error: --discovery-partition requires at least one --discovery-account"
        )
    if parsed_args.discovery_account and not parsed_args.discovery_partition:
        raise ParameterParseError(
            "Error: --discovery-account requires at least one --discovery-partition"
        )

    return {
        "account_ids": parsed_args.discovery_account,
        "partition": parsed_args.discovery_partition
    }
def _process_master_key_provider_configs(raw_keys, action):
    # type: (List[RAW_CONFIG], str) -> List[MASTER_KEY_PROVIDER_CONFIG]
    """Applied additional processing to prepare the master key provider configuration.

    :param list raw_keys: List of master key provider configurations
    :param str action: Action defined in CLI input
    :returns: List of processed master key provider configurations
    :rtype: list of dicts
    :raises ParameterParseError: if exactly one provider value is not provided
    :raises ParameterParseError: if no key values are provided
    """
    if raw_keys is None:
        if action == "decrypt":
            # We allow not defining any master key provider configuration if decrypting with aws-kms.
            _LOGGER.debug(
                "No master key provider config provided on decrypt request. Using aws-kms with no master keys."
            )
            return [{"provider": DEFAULT_MASTER_KEY_PROVIDER, "key": []}]
        raise ParameterParseError(
            "No master key provider configuration found.")

    processed_configs = []  # type: List[MASTER_KEY_PROVIDER_CONFIG]
    for raw_config in raw_keys:
        parsed_args = {}  # type: Dict[str, Union[str, List[str]]]
        parsed_args.update(_parse_kwargs(raw_config))

        provider = parsed_args.get(
            "provider", [DEFAULT_MASTER_KEY_PROVIDER
                         ])  # If no provider is defined, use aws-kms
        if len(provider) != 1:
            raise ParameterParseError(
                'Exactly one "provider" must be provided for each master key provider configuration. '
                "{} provided".format(len(provider)))
        parsed_args["provider"] = provider[0]

        aws_kms_on_decrypt = parsed_args["provider"] in (
            "aws-kms", DEFAULT_MASTER_KEY_PROVIDER) and action == "decrypt"

        if aws_kms_on_decrypt:
            if "key" in parsed_args:
                raise ParameterParseError(
                    "Exact master keys cannot be specified for aws-kms master key provider on decrypt."
                )
            parsed_args["key"] = []
        elif "key" not in parsed_args:
            raise ParameterParseError(
                'At least one "key" must be provided for each master key provider configuration'
            )
        processed_configs.append(parsed_args)
    return processed_configs
Esempio n. 4
0
def parse_args(raw_args=None):
    # type: (Optional[List[str]]) -> argparse.Namespace
    """Handles argparse to collect the needed input values.

    :param list raw_args: List of arguments
    :returns: parsed arguments
    :rtype: argparse.Namespace
    """
    parser = _build_parser()
    parsed_args = parser.parse_args(args=raw_args)

    try:
        if parsed_args.dummy_redirect is not None:
            raise ParameterParseError(
                'Found invalid argument "{actual}". Did you mean "-{actual}"?'.
                format(actual=parsed_args.dummy_redirect))

        if parsed_args.action == "decrypt" and parsed_args.discovery is None:
            raise ParameterParseError(
                "Discovery must be set to True or False.")
        discovery_filter = _process_discovery_args(parsed_args)

        if parsed_args.required_encryption_context_keys is not None:
            raise ParameterParseError(
                "--required-encryption-context-keys cannot be manually provided."
            )

        if parsed_args.overwrite_metadata:
            parsed_args.metadata_output.force_overwrite()

        parsed_args.wrapping_keys = _process_wrapping_key_provider_configs(
            parsed_args.wrapping_keys, parsed_args.action,
            parsed_args.discovery, discovery_filter)

        # mypy does not appear to understand nargs="+" behavior
        parsed_args.encryption_context, parsed_args.required_encryption_context_keys = _process_encryption_context(
            action=parsed_args.action,
            raw_encryption_context=parsed_args.encryption_context,
            raw_required_encryption_context_keys=parsed_args.
            required_encryption_context_keys,  # type: ignore
        )

        if parsed_args.caching is not None:
            parsed_args.caching = _process_caching_config(parsed_args.caching)
    except ParameterParseError as error:
        parser.error(*error.args)

    return parsed_args
def _process_non_kms_key_config(parsed_args):
    """Processes a single key provider configuration for a non-KMS wrapping key

    :param dict parsed_args: The parsed kwargs for the key provider
    """
    if "discovery" in parsed_args or "discovery-account" in parsed_args or "discovery-partition" in parsed_args:
        raise ParameterParseError(
            "Discovery attributes are supported only for AWS KMS wrapping keys"
        )

    if "key" not in parsed_args:
        raise ParameterParseError(
            'At least one "key" must be provided for each wrapping key provider configuration'
        )

    return parsed_args
def parse_args(raw_args=None):
    # type: (Optional[List[str]]) -> argparse.Namespace
    """Handles argparse to collect the needed input values.

    :param list raw_args: List of arguments
    :returns: parsed arguments
    :rtype: argparse.Namespace
    """
    parser = _build_parser()
    parsed_args = parser.parse_args(args=raw_args)

    try:
        if parsed_args.dummy_redirect is not None:
            raise ParameterParseError(
                'Found invalid argument "{actual}". Did you mean "-{actual}"?'.
                format(actual=parsed_args.dummy_redirect))

        # We add the 'required_encryption_context_keys' to arg parse, even though it is not
        # meant to be used by customers, so that we can  pass the parsed arguments around internally
        if parsed_args.required_encryption_context_keys is not None:
            raise ParameterParseError(
                "--required-encryption-context-keys cannot be manually provided"
            )

        if parsed_args.overwrite_metadata:
            parsed_args.metadata_output.force_overwrite()

        parsed_args.wrapping_keys = _process_wrapping_key_provider_configs(
            parsed_args.wrapping_keys, parsed_args.action)

        # mypy does not appear to understand nargs="+" behavior
        parsed_args.encryption_context, parsed_args.required_encryption_context_keys = _process_encryption_context(
            action=parsed_args.action,
            raw_encryption_context=parsed_args.encryption_context,
            raw_required_encryption_context_keys=parsed_args.
            required_encryption_context_keys,  # type: ignore
        )

        if parsed_args.caching is not None:
            parsed_args.caching = _process_caching_config(parsed_args.caching)
    except ParameterParseError as error:
        parser.error(*error.args)

    return parsed_args
def _process_wrapping_key_provider_configs(  # noqa: C901
        raw_keys,  # type: List[RAW_CONFIG]
        action,  # type: str
):
    # type: (...) -> List[MASTER_KEY_PROVIDER_CONFIG]
    """Applied additional processing to prepare the wrapping key provider configuration.

    :param list raw_keys: List of wrapping key provider configurations
    :param str action: Action defined in CLI input
    :returns: List of processed wrapping key provider configurations
    :rtype: list of dicts
    :raises ParameterParseError: if exactly one provider value is not provided
    :raises ParameterParseError: if no key values are provided
    """
    if raw_keys is None:
        raise ParameterParseError(
            "No wrapping key provider configuration found")

    processed_configs = []  # type: List[MASTER_KEY_PROVIDER_CONFIG]
    for raw_config in raw_keys:
        parsed_args = {
        }  # type: Dict[str, Union[str, List[str], Dict[str, Union[str, List[str]]]]]
        parsed_args.update(_parse_kwargs(raw_config))

        provider = parsed_args.get(
            "provider", [DEFAULT_MASTER_KEY_PROVIDER
                         ])  # If no provider is defined, use aws-kms
        if len(provider) != 1:
            raise ParameterParseError(
                'You must provide exactly one "provider" for each wrapping key provider configuration. '
                "{} provided".format(len(provider)))
        parsed_args["provider"] = provider[0]  # type: ignore

        provider_is_kms = parsed_args["provider"] in (
            "aws-kms", DEFAULT_MASTER_KEY_PROVIDER)

        if not provider_is_kms:
            processed_configs.append(_process_non_kms_key_config(parsed_args))
        else:
            processed_configs.append(
                _process_kms_key_config(parsed_args, action))  # type: ignore
    return processed_configs
def discovery_pseudobool(value):
    """Translates an input value in various 'truthy' or 'falsy' forms into a boolean."""
    if isinstance(value, bool):
        return value
    if isinstance(value, str):
        if value.lower() in {"false", "f", "0", "no", "n"}:
            return False
        if value.lower() in {"true", "t", "1", "yes", "y"}:
            return True
    raise ParameterParseError(
        "Value {} could not be parsed as true or false".format(value))
def parse_args(raw_args=None):
    # type: (Optional[List[str]]) -> argparse.Namespace
    """Handles argparse to collect the needed input values.

    :param list raw_args: List of arguments
    :returns: parsed arguments
    :rtype: argparse.Namespace
    """
    parser = _build_parser()
    parsed_args = parser.parse_args(args=raw_args)

    try:
        if parsed_args.dummy_redirect is not None:
            raise ParameterParseError(
                'Found invalid argument "{actual}". Did you mean "-{actual}"?'.
                format(actual=parsed_args.dummy_redirect))

        if parsed_args.required_encryption_context_keys is not None:
            raise ParameterParseError(
                "--required-encryption-context-keys cannot be manually provided."
            )

        if parsed_args.overwrite_metadata:
            parsed_args.metadata_output.force_overwrite()

        parsed_args.master_keys = _process_master_key_provider_configs(
            parsed_args.master_keys, parsed_args.action)

        parsed_args.encryption_context, parsed_args.required_encryption_context_keys = _process_encryption_context(
            action=parsed_args.action,
            raw_encryption_context=parsed_args.encryption_context,
            raw_required_encryption_context_keys=parsed_args.
            required_encryption_context_keys,
        )

        if parsed_args.caching is not None:
            parsed_args.caching = _process_caching_config(parsed_args.caching)
    except ParameterParseError as error:
        parser.error(*error.args)

    return parsed_args
Esempio n. 10
0
def _parse_kwargs(args):
    # type: (RAW_CONFIG) -> PARSED_CONFIG
    """Parses a list of CLI arguments of "key=value" form into key/values pairs.

    :param iterable args: arguments to unpack
    :returns: parsed arguments
    :rtype: dict
    :raises ParameterParseError: if a badly formed parameter if found
    """
    value_error_message = 'Argument parameter must follow the format "key=value"'
    kwargs = defaultdict(list)  # type: Dict[str, List[str]]
    for arg in args:
        _LOGGER.debug("Attempting to parse argument: %s", arg)
        try:
            key, value = arg.split("=", 1)
            if not (key and value):
                raise ParameterParseError(value_error_message)
            kwargs[key].append(value)
        except ValueError:
            _LOGGER.debug("Failed to parse argument")
            raise ParameterParseError(value_error_message)
    return dict(kwargs)
def _process_kms_key_config(parsed_args, action):
    """Processes a single key provider configuration for a KMS wrapping key

    :param dict parsed_args: The parsed kwargs for the key provider
    :param action: The action being taken (encrypt or decrypt)
    """
    args_include_discovery = ("discovery" in parsed_args
                              or "discovery-account" in parsed_args
                              or "discovery-partition" in parsed_args)

    if action == "encrypt" and args_include_discovery:
        raise ParameterParseError(
            "Discovery attributes are supported only on decryption for AWS KMS keys"
        )

    if "key" not in parsed_args and action == "encrypt":
        raise ParameterParseError(
            'At least one "key" must be provided for each wrapping key provider configuration'
        )

    _process_discovery_args(parsed_args)

    discovery = parsed_args["discovery"]
    if "key" in parsed_args and discovery:
        # Decrypt MUST fail without attempting any decryption if discovery mode is enabled
        # and at least one key=<Key ARN> parameter value is provided
        raise ParameterParseError(
            "If discovery is true (enabled), you cannot specify wrapping keys")
    if "key" not in parsed_args:
        if not discovery:
            # Decrypt MUST fail without attempting any decryption if discovery mode is disabled
            # and no key=<Key ARN> parameter value is provided
            raise ParameterParseError(
                "When discovery is false (disabled), you must specify at least one wrapping key"
            )
        parsed_args["key"] = []
    return parsed_args
def _process_discovery_args(key_config):  # noqa: C901
    """Process rules for discovery filters on Account ID and Partition ID
    :param key_config: The key configuration being parsed
    :raises: ParameterParseError
    """
    if "discovery" not in key_config:
        if "discovery-account" in key_config or "discovery-partition" in key_config:
            raise ParameterParseError(
                "Discovery-account and discovery-partition are valid only when the discovery attribute is set to true"
            )

        key_config["discovery"] = False
        return

    # Translate the raw value of 'discovery' as passed by customer into a bool we can work with
    discovery = discovery_pseudobool(key_config.pop("discovery")[0])
    key_config["discovery"] = discovery

    accounts = key_config.get("discovery-account", None)
    partition = key_config.get("discovery-partition", None)

    if not discovery:
        if accounts or partition:
            raise ParameterParseError(
                "Discovery-account and discovery-partition are valid only when the discovery attribute is set to true"
            )
    else:
        if accounts and not partition:
            raise ParameterParseError(
                "When specifying discovery-account, you must also specify discovery-partition"
            )
        if partition and not accounts:
            raise ParameterParseError(
                "When specifying discovery-partition, you must also specify discovery-account"
            )

        if accounts and partition:
            for account in accounts:
                if len(account) == 0:
                    raise ParameterParseError(
                        "Value passed to discovery-account cannot be empty")
            if len(partition) != 1:
                raise ParameterParseError(
                    "You can only specify discovery-partition once")
            if not partition[0]:
                raise ParameterParseError(
                    "Value passed to discovery-partition cannot be empty")

            key_config["discovery-partition"] = partition[0]
Esempio n. 13
0
def _process_wrapping_key_provider_configs(  # noqa: C901
        raw_keys,  # type: List[RAW_CONFIG]
        action,  # type: str
        discovery=None,  # type: bool
        discovery_filter=None,  # type: Dict[str, Union[str, List[str]]]
):
    # type: (...) -> List[MASTER_KEY_PROVIDER_CONFIG]
    """Applied additional processing to prepare the wrapping key provider configuration.

    :param list raw_keys: List of wrapping key provider configurations
    :param str action: Action defined in CLI input
    :param bool discovery: Are we in discovery mode?
    :param Dict[str, Union[str, List[str]]] discovery_filter: Filter options for discovery mode
    :returns: List of processed wrapping key provider configurations
    :rtype: list of dicts
    :raises ParameterParseError: if exactly one provider value is not provided
    :raises ParameterParseError: if no key values are provided
    """
    if raw_keys is None:
        if action == "decrypt":
            # We allow not defining any wrapping key provider configuration if decrypting with aws-kms.
            _LOGGER.debug(
                "No wrapping key provider config provided on decrypt request. Using aws-kms with no wrapping keys."
            )
            return [{"provider": DEFAULT_MASTER_KEY_PROVIDER, "key": []}]
        raise ParameterParseError(
            "No wrapping key provider configuration found.")

    if action == "decrypt" and discovery is None:
        discovery = False

    processed_configs = []  # type: List[MASTER_KEY_PROVIDER_CONFIG]
    for raw_config in raw_keys:
        parsed_args = {
        }  # type: Dict[str, Union[str, List[str], Dict[str, Union[str, List[str]]]]]
        parsed_args.update(_parse_kwargs(raw_config))

        provider = parsed_args.get(
            "provider", [DEFAULT_MASTER_KEY_PROVIDER
                         ])  # If no provider is defined, use aws-kms
        if len(provider) != 1:
            raise ParameterParseError(
                'Exactly one "provider" must be provided for each wrapping key provider configuration. '
                "{} provided".format(len(provider)))
        parsed_args["provider"] = provider[0]  # type: ignore

        aws_kms_on_decrypt = parsed_args["provider"] in (
            "aws-kms", DEFAULT_MASTER_KEY_PROVIDER) and action == "decrypt"

        if aws_kms_on_decrypt:
            if "key" in parsed_args and discovery:
                # Decrypt MUST fail without attempting any decryption if discovery mode is enabled
                # and at least one key=<Key ARN> parameter value is provided
                raise ParameterParseError(
                    "Exact wrapping keys cannot be specified for aws-kms wrapping key provider on decrypt "
                    "in discovery mode.")
            if "key" not in parsed_args and not discovery:
                # Decrypt MUST fail without attempting any decryption if discovery mode is disabled
                # and no key=<Key ARN> parameter value is provided
                raise ParameterParseError(
                    "At least one key must be specified for aws-kms wrapping key provider on decrypt "
                    "when discovery mode is disabled.")
            parsed_args["key"] = []
        elif "key" not in parsed_args:
            raise ParameterParseError(
                'At least one "key" must be provided for each wrapping key provider configuration'
            )
        if discovery and discovery_filter:
            parsed_args["discovery_filter"] = discovery_filter
        processed_configs.append(parsed_args)  # type: ignore
    return processed_configs