@@ -1354,7 +1354,9 @@ print(Settings().model_dump())
13541354
13551355#### CLI Kebab Case for Arguments
13561356
1357- Change whether CLI arguments should use kebab case by enabling ` cli_kebab_case ` .
1357+ Change whether CLI arguments should use kebab case by enabling ` cli_kebab_case ` . By default, ` cli_kebab_case=True ` will
1358+ ignore enum fields, and is equivalent to ` cli_kebab_case='no_enums' ` . To apply kebab case to everything, including
1359+ enums, use ` cli_kebab_case='all' ` .
13581360
13591361``` py
13601362import sys
@@ -1857,6 +1859,248 @@ Last, run your application inside a Docker container and supply your newly creat
18571859docker service create --name pydantic-with-secrets --secret my_secret_data pydantic-app:latest
18581860```
18591861
1862+ ## Nested Secrets
1863+
1864+ The default secrets implementation, ` SecretsSettingsSource ` , has behaviour that is not always desired or sufficient.
1865+ For example, the default implementation does not support secret fields in nested submodels.
1866+
1867+ ` NestedSecretsSettingsSource ` can be used as a drop-in replacement to ` SecretsSettingsSource ` to adjust the default behaviour.
1868+ All differences are summarized in the table below.
1869+
1870+ | ` SecretsSettingsSource ` | ` NestedSecretsSettingsSourcee ` |
1871+ | -----------------------------------------------------------------------------------------------------------------------------------------------------------------| -----------------------------------------------------------------------------------------------------------------------------------|
1872+ | Secret fields must belong to a top level model. | Secrets can be fields of nested models. |
1873+ | Secret files can be placed in ` secrets_dir ` s only. | Secret files can be placed in subdirectories for nested models. |
1874+ | Secret files discovery is based on the same configuration options that are used by ` EnvSettingsSource ` : ` case_sensitive ` , ` env_nested_delimiter ` , ` env_prefix ` . | Default options are respected, but can be overridden with ` secrets_case_sensitive ` , ` secrets_nested_delimiter ` , ` secrets_prefix ` . |
1875+ | When ` secrets_dir ` is missing on the file system, a warning is generated. | Use ` secrets_dir_missing ` options to choose whether to issue warning, raise error, or silently ignore. |
1876+
1877+ ### Use Case: Plain Directory Layout
1878+
1879+ ``` text
1880+ 📂 secrets
1881+ ├── 📄 app_key
1882+ └── 📄 db_passwd
1883+ ```
1884+
1885+ In the example below, secrets nested delimiter ` '_' ` is different from env nested delimiter ` '__' ` .
1886+ Value for ` Settings.db.user ` can be passed in env variable ` MY_DB__USER ` .
1887+
1888+ ``` py
1889+ from pydantic import BaseModel, SecretStr
1890+
1891+ from pydantic_settings import (
1892+ BaseSettings,
1893+ NestedSecretsSettingsSource,
1894+ SettingsConfigDict,
1895+ )
1896+
1897+
1898+ class AppSettings (BaseModel ):
1899+ key: SecretStr
1900+
1901+
1902+ class DbSettings (BaseModel ):
1903+ user: str
1904+ passwd: SecretStr
1905+
1906+
1907+ class Settings (BaseSettings ):
1908+ app: AppSettings
1909+ db: DbSettings
1910+
1911+ model_config = SettingsConfigDict(
1912+ env_prefix = ' MY_' ,
1913+ env_nested_delimiter = ' __' ,
1914+ secrets_dir = ' secrets' ,
1915+ secrets_nested_delimiter = ' _' ,
1916+ )
1917+
1918+ @ classmethod
1919+ def settings_customise_sources (
1920+ cls ,
1921+ settings_cls ,
1922+ init_settings ,
1923+ env_settings ,
1924+ dotenv_settings ,
1925+ file_secret_settings ,
1926+ ):
1927+ return (
1928+ init_settings,
1929+ env_settings,
1930+ dotenv_settings,
1931+ NestedSecretsSettingsSource(file_secret_settings),
1932+ )
1933+ ```
1934+
1935+ ### Use Case: Nested Directory Layout
1936+
1937+ ``` text
1938+ 📂 secrets
1939+ ├── 📂 app
1940+ │ └── 📄 key
1941+ └── 📂 db
1942+ └── 📄 passwd
1943+ ```
1944+ ``` py
1945+ from pydantic import BaseModel, SecretStr
1946+
1947+ from pydantic_settings import (
1948+ BaseSettings,
1949+ NestedSecretsSettingsSource,
1950+ SettingsConfigDict,
1951+ )
1952+
1953+
1954+ class AppSettings (BaseModel ):
1955+ key: SecretStr
1956+
1957+
1958+ class DbSettings (BaseModel ):
1959+ user: str
1960+ passwd: SecretStr
1961+
1962+
1963+ class Settings (BaseSettings ):
1964+ app: AppSettings
1965+ db: DbSettings
1966+
1967+ model_config = SettingsConfigDict(
1968+ env_prefix = ' MY_' ,
1969+ env_nested_delimiter = ' __' ,
1970+ secrets_dir = ' secrets' ,
1971+ secrets_nested_subdir = True ,
1972+ )
1973+
1974+ @ classmethod
1975+ def settings_customise_sources (
1976+ cls ,
1977+ settings_cls ,
1978+ init_settings ,
1979+ env_settings ,
1980+ dotenv_settings ,
1981+ file_secret_settings ,
1982+ ):
1983+ return (
1984+ init_settings,
1985+ env_settings,
1986+ dotenv_settings,
1987+ NestedSecretsSettingsSource(file_secret_settings),
1988+ )
1989+ ```
1990+
1991+ ### Use Case: Multiple Nested Directories
1992+
1993+ ``` text
1994+ 📂 secrets
1995+ ├── 📂 default
1996+ │ ├── 📂 app
1997+ │ │ └── 📄 key
1998+ │ └── 📂 db
1999+ │ └── 📄 passwd
2000+ └── 📂 override
2001+ ├── 📂 app
2002+ │ └── 📄 key
2003+ └── 📂 db
2004+ └── 📄 passwd
2005+ ```
2006+ ``` py
2007+ from pydantic import BaseModel, SecretStr
2008+
2009+ from pydantic_settings import (
2010+ BaseSettings,
2011+ NestedSecretsSettingsSource,
2012+ SettingsConfigDict,
2013+ )
2014+
2015+
2016+ class AppSettings (BaseModel ):
2017+ key: SecretStr
2018+
2019+
2020+ class DbSettings (BaseModel ):
2021+ user: str
2022+ passwd: SecretStr
2023+
2024+
2025+ class Settings (BaseSettings ):
2026+ app: AppSettings
2027+ db: DbSettings
2028+
2029+ model_config = SettingsConfigDict(
2030+ env_prefix = ' MY_' ,
2031+ env_nested_delimiter = ' __' ,
2032+ secrets_dir = [' secrets/default' , ' secrets/override' ],
2033+ secrets_nested_subdir = True ,
2034+ )
2035+
2036+ @ classmethod
2037+ def settings_customise_sources (
2038+ cls ,
2039+ settings_cls ,
2040+ init_settings ,
2041+ env_settings ,
2042+ dotenv_settings ,
2043+ file_secret_settings ,
2044+ ):
2045+ return (
2046+ init_settings,
2047+ env_settings,
2048+ dotenv_settings,
2049+ NestedSecretsSettingsSource(file_secret_settings),
2050+ )
2051+ ```
2052+
2053+ ### Configuration Options
2054+
2055+ #### secrets_dir
2056+
2057+ Path to secrets directory, same as ` SecretsSettingsSource.secrets_dir ` . If ` list ` , the last match wins.
2058+ If ` secrets_dir ` is passed in both source constructor and model config, values are not merged (constructor wins).
2059+
2060+ #### secrets_dir_missing
2061+
2062+ If ` secrets_dir ` does not exist, original ` SecretsSettingsSource ` issues a warning.
2063+ However, this may be undesirable, for example if we don't mount Docker Secrets in e.g. dev environment.
2064+ Use ` secrets_dir_missing ` to choose:
2065+
2066+ * ` 'ok' ` — do nothing if ` secrets_dir ` does not exist
2067+ * ` 'warn' ` (default) — print warning, same as ` SecretsSettingsSource `
2068+ * ` 'error' ` — raise ` SettingsError `
2069+
2070+ If multiple ` secrets_dir ` passed, the same ` secrets_dir_missing ` action applies to each of them.
2071+
2072+ #### secrets_dir_max_size
2073+
2074+ Limit the size of ` secrets_dir ` for security reasons, defaults to ` SECRETS_DIR_MAX_SIZE ` equal to 16 MiB.
2075+
2076+ ` NestedSecretsSettingsSource ` is a thin wrapper around ` EnvSettingsSource ` ,
2077+ which loads all potential secrets on initialization. This could lead to ` MemoryError ` if we mount
2078+ a large file under ` secrets_dir ` .
2079+
2080+ If multiple ` secrets_dir ` passed, the limit applies to each directory independently.
2081+
2082+ #### secrets_case_sensitive
2083+
2084+ Same as ` case_sensitive ` , but works for secrets only. If not specified, defaults to ` case_sensitive ` .
2085+
2086+ #### secrets_nested_delimiter
2087+
2088+ Same as ` env_nested_delimiter ` , but works for secrets only. If not specified, defaults to ` env_nested_delimiter ` .
2089+ This option is used to implement _ nested secrets directory_ layout and allows to do even nasty things
2090+ like ` /run/secrets/model/delim/nested1/delim/nested2 ` .
2091+
2092+ #### secrets_nested_subdir
2093+
2094+ Boolean flag to turn on _ nested secrets directory_ mode, ` False ` by default. If ` True ` , sets ` secrets_nested_delimiter `
2095+ to ` os.sep ` . Raises ` SettingsError ` if ` secrets_nested_delimiter ` is already specified.
2096+
2097+ #### secrets_prefix
2098+
2099+ Secret path prefix, similar to ` env_prefix ` , but works for secrets only. Defaults to ` env_prefix `
2100+ if not specified. Works in both plain and nested directory modes, like
2101+ ` '/run/secrets/prefix_model__nested' ` and ` '/run/secrets/prefix_model/nested' ` .
2102+
2103+
18602104## AWS Secrets Manager
18612105
18622106You must set one parameter:
0 commit comments