Skip to content

Commit 90108c3

Browse files
committed
Add support for AWS Secrets Manager
1 parent e5fb741 commit 90108c3

File tree

7 files changed

+98
-8
lines changed

7 files changed

+98
-8
lines changed

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ refresh-lockfiles:
1313
find requirements/ -name '*.txt' ! -name 'all.txt' -type f -delete
1414
pip-compile -q --no-emit-index-url --resolver backtracking -o requirements/linting.txt requirements/linting.in
1515
pip-compile -q --no-emit-index-url --resolver backtracking -o requirements/testing.txt requirements/testing.in
16-
pip-compile -q --no-emit-index-url --resolver backtracking --extra toml --extra yaml --extra azure-key-vault -o requirements/pyproject.txt pyproject.toml
16+
pip-compile -q --no-emit-index-url --resolver backtracking --extra toml --extra yaml --extra azure-key-vault --extra aws-secrets-manager -o requirements/pyproject.txt pyproject.toml
1717
pip install --dry-run -r requirements/all.txt
1818

1919
.PHONY: format

pydantic_settings/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
from .main import BaseSettings, CliApp, SettingsConfigDict
22
from .sources import (
33
CLI_SUPPRESS,
4+
AWSSecretsManagerSettingsSource,
45
AzureKeyVaultSettingsSource,
56
CliExplicitFlag,
67
CliImplicitFlag,
@@ -50,6 +51,7 @@
5051
'TomlConfigSettingsSource',
5152
'YamlConfigSettingsSource',
5253
'AzureKeyVaultSettingsSource',
54+
'AWSSecretsManagerSettingsSource',
5355
'get_subcommand',
5456
'__version__',
5557
)

pydantic_settings/sources.py

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,19 @@ def import_azure_key_vault() -> None:
111111
) from e
112112

113113

114+
def import_aws_secrets_manager() -> None:
115+
global boto3_client
116+
global SecretsManagerClient
117+
118+
try:
119+
from boto3 import client as boto3_client
120+
from mypy_boto3_secretsmanager.client import SecretsManagerClient
121+
except ImportError as e:
122+
raise ImportError(
123+
'AWS Secrets Manager dependencies are not installed, run `pip install pydantic-settings[aws-secrets-manager]`'
124+
) from e
125+
126+
114127
DotenvType = Union[Path, str, Sequence[Union[Path, str]]]
115128
PathType = Union[Path, str, Sequence[Union[Path, str]]]
116129
DEFAULT_PATH: PathType = Path('')
@@ -2250,6 +2263,43 @@ def __repr__(self) -> str:
22502263
return f'{self.__class__.__name__}(url={self._url!r}, ' f'env_nested_delimiter={self.env_nested_delimiter!r})'
22512264

22522265

2266+
class AWSSecretsManagerSettingsSource(EnvSettingsSource):
2267+
_secret_id: str
2268+
_secretsmanager_client: SecretsManagerClient # type: ignore
2269+
2270+
def __init__(
2271+
self,
2272+
settings_cls: type[BaseSettings],
2273+
secret_id: str,
2274+
env_prefix: str | None = None,
2275+
env_parse_none_str: str | None = None,
2276+
env_parse_enums: bool | None = None,
2277+
) -> None:
2278+
import_aws_secrets_manager()
2279+
self._secretsmanager_client = boto3_client('secretsmanager') # type: ignore
2280+
self._secret_id = secret_id
2281+
super().__init__(
2282+
settings_cls,
2283+
case_sensitive=True,
2284+
env_prefix=env_prefix,
2285+
env_nested_delimiter='--',
2286+
env_ignore_empty=False,
2287+
env_parse_none_str=env_parse_none_str,
2288+
env_parse_enums=env_parse_enums,
2289+
)
2290+
2291+
def _load_env_vars(self) -> Mapping[str, Optional[str]]:
2292+
response = self._secretsmanager_client.get_secret_value(SecretId=self._secret_id)
2293+
2294+
return json.loads(response['SecretString'])
2295+
2296+
def __repr__(self) -> str:
2297+
return (
2298+
f'{self.__class__.__name__}(secret_id={self._secret_id!r}, '
2299+
f'env_nested_delimiter={self.env_nested_delimiter!r})'
2300+
)
2301+
2302+
22532303
def _get_env_var_key(key: str, case_sensitive: bool = False) -> str:
22542304
return key if case_sensitive else key.lower()
22552305

pyproject.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,9 +47,10 @@ dependencies = [
4747
dynamic = ['version']
4848

4949
[project.optional-dependencies]
50-
yaml = ["pyyaml>=6.0.1"]
50+
yaml = ["pyyaml>=6.0.2"]
5151
toml = ["tomli>=2.0.1"]
5252
azure-key-vault = ["azure-keyvault-secrets>=4.8.0", "azure-identity>=1.16.0"]
53+
aws-secrets-manager = ["boto3>=1.35.0", "boto3-stubs[secretsmanager]"]
5354

5455
[project.urls]
5556
Homepage = 'https://github.com/pydantic/pydantic-settings'

requirements/linting.in

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,6 @@ ruff
33
pyupgrade
44
mypy
55
types-PyYAML
6-
pyyaml==6.0.1
6+
pyyaml==6.0.2
77
pre-commit
8+
boto3-stubs[secretsmanager]

requirements/linting.txt

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@
66
#
77
black==24.8.0
88
# via -r requirements/linting.in
9+
boto3-stubs[secretsmanager]==1.37.8
10+
# via -r requirements/linting.in
11+
botocore-stubs==1.37.8
12+
# via boto3-stubs
913
cfgv==3.4.0
1014
# via pre-commit
1115
click==8.1.7
@@ -18,6 +22,8 @@ identify==2.6.0
1822
# via pre-commit
1923
mypy==1.11.2
2024
# via -r requirements/linting.in
25+
mypy-boto3-secretsmanager==1.37.0
26+
# via boto3-stubs
2127
mypy-extensions==1.0.0
2228
# via
2329
# black
@@ -36,7 +42,7 @@ pre-commit==3.5.0
3642
# via -r requirements/linting.in
3743
pyupgrade==3.16.0
3844
# via -r requirements/linting.in
39-
pyyaml==6.0.1
45+
pyyaml==6.0.2
4046
# via
4147
# -r requirements/linting.in
4248
# pre-commit
@@ -48,8 +54,12 @@ tomli==2.0.1
4854
# via
4955
# black
5056
# mypy
57+
types-awscrt==0.23.10
58+
# via botocore-stubs
5159
types-pyyaml==6.0.12.20240808
5260
# via -r requirements/linting.in
61+
types-s3transfer==0.11.4
62+
# via boto3-stubs
5363
typing-extensions==4.12.2
5464
# via
5565
# black

requirements/pyproject.txt

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
# This file is autogenerated by pip-compile with Python 3.13
33
# by the following command:
44
#
5-
# pip-compile --extra=azure-key-vault --extra=toml --extra=yaml --no-emit-index-url --output-file=requirements/pyproject.txt pyproject.toml
5+
# pip-compile --extra=aws-secrets-manager --extra=azure-key-vault --extra=toml --extra=yaml --no-emit-index-url --output-file=requirements/pyproject.txt pyproject.toml
66
#
77
annotated-types==0.7.0
88
# via pydantic
@@ -14,6 +14,16 @@ azure-identity==1.17.1
1414
# via pydantic-settings (pyproject.toml)
1515
azure-keyvault-secrets==4.8.0
1616
# via pydantic-settings (pyproject.toml)
17+
boto3==1.37.8
18+
# via pydantic-settings (pyproject.toml)
19+
boto3-stubs[secretsmanager]==1.37.8
20+
# via pydantic-settings (pyproject.toml)
21+
botocore==1.37.8
22+
# via
23+
# boto3
24+
# s3transfer
25+
botocore-stubs==1.37.8
26+
# via boto3-stubs
1727
certifi==2024.8.30
1828
# via requests
1929
cffi==1.17.1
@@ -29,12 +39,18 @@ idna==3.8
2939
# via requests
3040
isodate==0.6.1
3141
# via azure-keyvault-secrets
42+
jmespath==1.0.1
43+
# via
44+
# boto3
45+
# botocore
3246
msal==1.31.0
3347
# via
3448
# azure-identity
3549
# msal-extensions
3650
msal-extensions==1.2.0
3751
# via azure-identity
52+
mypy-boto3-secretsmanager==1.37.0
53+
# via boto3-stubs
3854
portalocker==2.10.1
3955
# via msal-extensions
4056
pycparser==2.22
@@ -47,20 +63,28 @@ pyjwt[crypto]==2.9.0
4763
# via
4864
# msal
4965
# pyjwt
66+
python-dateutil==2.9.0.post0
67+
# via botocore
5068
python-dotenv==1.0.1
5169
# via pydantic-settings (pyproject.toml)
52-
pyyaml==6.0.1
70+
pyyaml==6.0.2
5371
# via pydantic-settings (pyproject.toml)
5472
requests==2.32.3
5573
# via
5674
# azure-core
5775
# msal
76+
s3transfer==0.11.4
77+
# via boto3
5878
six==1.16.0
5979
# via
6080
# azure-core
6181
# isodate
6282
tomli==2.0.1
6383
# via pydantic-settings (pyproject.toml)
84+
types-awscrt==0.23.10
85+
# via botocore-stubs
86+
types-s3transfer==0.11.4
87+
# via boto3-stubs
6488
typing-extensions==4.12.2
6589
# via
6690
# azure-core
@@ -71,5 +95,7 @@ typing-extensions==4.12.2
7195
# typing-inspection
7296
typing-inspection==0.4.0
7397
# via pydantic-settings (pyproject.toml)
74-
urllib3==2.2.2
75-
# via requests
98+
urllib3==2.3.0
99+
# via
100+
# botocore
101+
# requests

0 commit comments

Comments
 (0)