Module aws_lambda_powertools.utilities.parameters.secrets

AWS Secrets Manager parameter retrieval and caching utility

Functions

def get_secret(name: str, transform: TransformOptions = None, force_fetch: bool = False, max_age: int | None = None, **sdk_options)

Retrieve a parameter value from AWS Secrets Manager

Parameters

name : str
Name of the parameter
transform : str, optional
Transforms the content from a JSON object ('json') or base64 binary string ('binary')
force_fetch : bool, optional
Force update even before a cached item has expired, defaults to False
max_age : int, optional
Maximum age of the cached value
sdk_options : dict, optional
Dictionary of options that will be passed to the get_secret_value call

Raises

GetParameterError
When the parameter provider fails to retrieve a parameter value for a given name.
TransformParameterError
When the parameter provider fails to transform a parameter value.

Example

Retrieves a secret*

>>> from aws_lambda_powertools.utilities.parameters import get_secret
>>>
>>> get_secret("my-secret")

Retrieves a secret and transforms using a JSON deserializer*

>>> from aws_lambda_powertools.utilities.parameters import get_secret
>>>
>>> get_secret("my-secret", transform="json")

Retrieves a secret and passes custom arguments to the SDK

>>> from aws_lambda_powertools.utilities.parameters import get_secret
>>>
>>> get_secret("my-secret", VersionId="f658cac0-98a5-41d9-b993-8a76a7799194")
def set_secret(name: str, value: str | bytes, *, client_request_token: str | None = None, **sdk_options)

Modify the details of a secret or create a new secret if it doesn't already exist.

We aim to minimize API calls by assuming that the secret already exists and needs updating. If it doesn't exist, we attempt to create a new one. Refer to the following workflow for a better understanding:

              ┌────────────────────────┐      ┌─────────────────┐
    ┌───────▶│Resource NotFound error?│────▶│Create Secret API│─────┐
    │         └────────────────────────┘      └─────────────────┘     │
    │                                                                 │
    │                                                                 │
    │                                                                 ▼

┌─────────────────┐ ┌─────────────────────┐ │Update Secret API│────────────────────────────────────────────▶│ Return or Exception │ └─────────────────┘ └─────────────────────┘

Parameters

name : str
The ARN or name of the secret to add a new version to or create a new one.
value : str, dict or bytes
Specifies text data that you want to encrypt and store in this new version of the secret.
client_request_token : str, optional
This value helps ensure idempotency. It's recommended that you generate a UUID-type value to ensure uniqueness within the specified secret. This value becomes the VersionId of the new version. This field is auto-populated if not provided, but no idempotency will be enforced this way.
sdk_options : dict, optional
Dictionary of options that will be passed to the Secrets Manager update_secret API call

Raises

SetSecretError
When attempting to update or create a secret fails.

Returns:

Setsecretresponse

The dict returned by boto3.

Example

Sets a secret*

>>> from aws_lambda_powertools.utilities import parameters
>>>
>>> parameters.set_secret(name="llamas-are-awesome", value="supers3cr3tllam@passw0rd")

Sets a secret and includes an client_request_token

>>> from aws_lambda_powertools.utilities import parameters
>>>
>>> parameters.set_secret(
        name="my-secret",
        value='{"password": "supers3cr3tllam@passw0rd"}',
        client_request_token="YOUR_TOKEN_HERE"
    )

URLs:

<https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/secretsmanager/client/put_secret_value.html>
<https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/secretsmanager/client/create_secret.html>

Classes

class SecretsProvider (config: Config | None = None, boto_config: Config | None = None, boto3_session: boto3.session.Session | None = None, boto3_client: SecretsManagerClient | None = None)

AWS Secrets Manager Parameter Provider

Parameters

config : botocore.config.Config, optional
Botocore configuration to pass during client initialization
boto3_session : boto3.session.Session, optional
Boto3 session to create a boto3_client from
boto3_client : SecretsManagerClient, optional
Boto3 SecretsManager Client to use, boto3_session will be ignored if both are provided

Example

Retrieves a parameter value from Secrets Manager

>>> from aws_lambda_powertools.utilities.parameters import SecretsProvider
>>> secrets_provider = SecretsProvider()
>>>
>>> value = secrets_provider.get("my-parameter")
>>>
>>> print(value)
My parameter value

Retrieves a parameter value from Secrets Manager in another AWS region

>>> from botocore.config import Config
>>> from aws_lambda_powertools.utilities.parameters import SecretsProvider
>>>
>>> config = Config(region_name="us-west-1")
>>> secrets_provider = SecretsProvider(config=config)
>>>
>>> value = secrets_provider.get("my-parameter")
>>>
>>> print(value)
My parameter value

Retrieves a parameter value from Secrets Manager passing options to the SDK call

>>> from aws_lambda_powertools.utilities.parameters import SecretsProvider
>>> secrets_provider = SecretsProvider()
>>>
>>> value = secrets_provider.get("my-parameter", VersionId="f658cac0-98a5-41d9-b993-8a76a7799194")
>>>
>>> print(value)
My parameter value

Initialize the Secrets Manager client

Expand source code
class SecretsProvider(BaseProvider):
    """
    AWS Secrets Manager Parameter Provider

    Parameters
    ----------
    config: botocore.config.Config, optional
        Botocore configuration to pass during client initialization
    boto3_session : boto3.session.Session, optional
            Boto3 session to create a boto3_client from
    boto3_client: SecretsManagerClient, optional
            Boto3 SecretsManager Client to use, boto3_session will be ignored if both are provided

    Example
    -------
    **Retrieves a parameter value from Secrets Manager**

        >>> from aws_lambda_powertools.utilities.parameters import SecretsProvider
        >>> secrets_provider = SecretsProvider()
        >>>
        >>> value = secrets_provider.get("my-parameter")
        >>>
        >>> print(value)
        My parameter value

    **Retrieves a parameter value from Secrets Manager in another AWS region**

        >>> from botocore.config import Config
        >>> from aws_lambda_powertools.utilities.parameters import SecretsProvider
        >>>
        >>> config = Config(region_name="us-west-1")
        >>> secrets_provider = SecretsProvider(config=config)
        >>>
        >>> value = secrets_provider.get("my-parameter")
        >>>
        >>> print(value)
        My parameter value

    **Retrieves a parameter value from Secrets Manager passing options to the SDK call**

        >>> from aws_lambda_powertools.utilities.parameters import SecretsProvider
        >>> secrets_provider = SecretsProvider()
        >>>
        >>> value = secrets_provider.get("my-parameter", VersionId="f658cac0-98a5-41d9-b993-8a76a7799194")
        >>>
        >>> print(value)
        My parameter value
    """

    def __init__(
        self,
        config: Config | None = None,
        boto_config: Config | None = None,
        boto3_session: boto3.session.Session | None = None,
        boto3_client: SecretsManagerClient | None = None,
    ):
        """
        Initialize the Secrets Manager client
        """
        if config:
            warnings.warn(
                message="The 'config' parameter is deprecated in V3 and will be removed in V4. "
                "Please use 'boto_config' instead.",
                category=PowertoolsDeprecationWarning,
                stacklevel=2,
            )

        if boto3_client is None:
            boto3_session = boto3_session or boto3.session.Session()
            boto3_client = boto3_session.client("secretsmanager", config=boto_config or config)
        self.client = boto3_client

        super().__init__(client=self.client)

    def _get(self, name: str, **sdk_options) -> str | bytes:
        """
        Retrieve a parameter value from AWS Systems Manager Parameter Store

        Parameters
        ----------
        name: str
            Name of the parameter
        sdk_options: dict, optional
            Dictionary of options that will be passed to the Secrets Manager get_secret_value API call
        """

        # Explicit arguments will take precedence over keyword arguments
        sdk_options["SecretId"] = name

        secret_value = self.client.get_secret_value(**sdk_options)

        if "SecretString" in secret_value:
            return secret_value["SecretString"]

        return secret_value["SecretBinary"]

    def _get_multiple(self, path: str, **sdk_options) -> dict[str, str]:
        """
        Retrieving multiple parameter values is not supported with AWS Secrets Manager
        """
        raise NotImplementedError()

    def _create_secret(self, name: str, **sdk_options) -> CreateSecretResponseTypeDef:
        """
        Create a secret with the given name.

        Parameters:
        ----------
        name: str
            The name of the secret.
        **sdk_options:
            Additional options to be passed to the create_secret method.

        Raises:
            SetSecretError: If there is an error setting the secret.
        """
        try:
            sdk_options["Name"] = name
            return self.client.create_secret(**sdk_options)
        except Exception as exc:
            raise SetSecretError(f"Error setting secret - {str(exc)}") from exc

    def _update_secret(self, name: str, **sdk_options):
        """
        Update a secret with the given name.

        Parameters:
        ----------
        name: str
            The name of the secret.
        **sdk_options:
            Additional options to be passed to the create_secret method.
        """
        sdk_options["SecretId"] = name
        return self.client.put_secret_value(**sdk_options)

    def set(
        self,
        name: str,
        value: str | bytes | dict,
        *,  # force keyword arguments
        client_request_token: str | None = None,
        **sdk_options,
    ) -> CreateSecretResponseTypeDef:
        """
        Modify the details of a secret or create a new secret if it doesn't already exist.

        We aim to minimize API calls by assuming that the secret already exists and needs updating.
        If it doesn't exist, we attempt to create a new one. Refer to the following workflow for a better understanding:


                          ┌────────────────────────┐      ┌─────────────────┐
                ┌───────▶│Resource NotFound error?│────▶│Create Secret API│─────┐
                │         └────────────────────────┘      └─────────────────┘     │
                │                                                                 │
                │                                                                 │
                │                                                                 ▼
        ┌─────────────────┐                                              ┌─────────────────────┐
        │Update Secret API│────────────────────────────────────────────▶│ Return or Exception │
        └─────────────────┘                                              └─────────────────────┘

        Parameters
        ----------
        name: str
            The ARN or name of the secret to add a new version to or create a new one.
        value: str, dict or bytes
            Specifies text data that you want to encrypt and store in this new version of the secret.
        client_request_token: str, optional
            This value helps ensure idempotency. It's recommended that you generate
            a UUID-type value to ensure uniqueness within the specified secret.
            This value becomes the VersionId of the new version. This field is
            auto-populated if not provided, but no idempotency will be enforced this way.
        sdk_options: dict, optional
            Dictionary of options that will be passed to the Secrets Manager update_secret API call

        Raises
        ------
        SetSecretError
            When attempting to update or create a secret fails.

        Returns:
        -------
        SetSecretResponse:
            The dict returned by boto3.

        Example
        -------
        **Sets a secret***

            >>> from aws_lambda_powertools.utilities import parameters
            >>>
            >>> parameters.set_secret(name="llamas-are-awesome", value="supers3cr3tllam@passw0rd")

        **Sets a secret and includes an client_request_token**

            >>> from aws_lambda_powertools.utilities import parameters
            >>> import uuid
            >>>
            >>> parameters.set_secret(
                    name="my-secret",
                    value='{"password": "supers3cr3tllam@passw0rd"}',
                    client_request_token=str(uuid.uuid4())
                )

        URLs:
        -------
            https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/secretsmanager/client/put_secret_value.html
            https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/secretsmanager/client/create_secret.html
        """

        if isinstance(value, dict):
            value = json.dumps(value, cls=Encoder)

        if isinstance(value, bytes):
            sdk_options["SecretBinary"] = value
        else:
            sdk_options["SecretString"] = value

        if client_request_token:
            sdk_options["ClientRequestToken"] = client_request_token

        try:
            logger.debug(f"Attempting to update secret {name}")
            return self._update_secret(name=name, **sdk_options)
        except self.client.exceptions.ResourceNotFoundException:
            logger.debug(f"Secret {name} doesn't exist, creating a new one")
            return self._create_secret(name=name, **sdk_options)
        except Exception as exc:
            raise SetSecretError(f"Error setting secret - {str(exc)}") from exc

Ancestors

Methods

def set(self, name: str, value: str | bytes | dict, *, client_request_token: str | None = None, **sdk_options)

Modify the details of a secret or create a new secret if it doesn't already exist.

We aim to minimize API calls by assuming that the secret already exists and needs updating. If it doesn't exist, we attempt to create a new one. Refer to the following workflow for a better understanding:

              ┌────────────────────────┐      ┌─────────────────┐
    ┌───────▶│Resource NotFound error?│────▶│Create Secret API│─────┐
    │         └────────────────────────┘      └─────────────────┘     │
    │                                                                 │
    │                                                                 │
    │                                                                 ▼

┌─────────────────┐ ┌─────────────────────┐ │Update Secret API│────────────────────────────────────────────▶│ Return or Exception │ └─────────────────┘ └─────────────────────┘

Parameters

name : str
The ARN or name of the secret to add a new version to or create a new one.
value : str, dict or bytes
Specifies text data that you want to encrypt and store in this new version of the secret.
client_request_token : str, optional
This value helps ensure idempotency. It's recommended that you generate a UUID-type value to ensure uniqueness within the specified secret. This value becomes the VersionId of the new version. This field is auto-populated if not provided, but no idempotency will be enforced this way.
sdk_options : dict, optional
Dictionary of options that will be passed to the Secrets Manager update_secret API call

Raises

SetSecretError
When attempting to update or create a secret fails.

Returns:

Setsecretresponse

The dict returned by boto3.

Example

Sets a secret*

>>> from aws_lambda_powertools.utilities import parameters
>>>
>>> parameters.set_secret(name="llamas-are-awesome", value="supers3cr3tllam@passw0rd")

Sets a secret and includes an client_request_token

>>> from aws_lambda_powertools.utilities import parameters
>>> import uuid
>>>
>>> parameters.set_secret(
        name="my-secret",
        value='{"password": "supers3cr3tllam@passw0rd"}',
        client_request_token=str(uuid.uuid4())
    )

URLs:

<https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/secretsmanager/client/put_secret_value.html>
<https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/secretsmanager/client/create_secret.html>

Inherited members