Préface
Dans cet article, je parlerai de la configuration de vos services en utilisant le bundle Vault (KV et jusqu'à présent uniquement la première version, c'est-à-dire sans secrets de version) et Pydantic (Paramètres) sous le patronage de Sitri .
Donc, disons que nous avons une application superapp avec des configurations configurées dans Vault et une authentification utilisant approle, configurons quelque chose comme ceci (je laisserai le paramètre de stratégie pour l'accès aux moteurs secrets et aux secrets eux-mêmes dans les coulisses, car c'est assez simple et l'article n'est pas à propos de ça):
Key Value --- ----- bind_secret_id true local_secret_ids false policies [superapp_service] secret_id_bound_cidrs <nil> secret_id_num_uses 0 secret_id_ttl 0s token_bound_cidrs [] token_explicit_max_ttl 0s token_max_ttl 30m token_no_default_policy false token_num_uses 50 token_period 0s token_policies [superapp_service] token_ttl 20m token_type default
.: , , secret_id_ttl , 0 .
SuperApp : , kafka faust .
Sitri
, vault- provider_config.py:
import hvac
from sitri.providers.contrib.vault import VaultKVConfigProvider
from sitri.providers.contrib.system import SystemConfigProvider
configurator = SystemConfigProvider(prefix="superapp")
ENV = configurator.get("env")
def vault_client_factory() -> hvac.Client:
client = hvac.Client(url=configurator.get("vault_api"))
client.auth_approle(
role_id=configurator.get("role_id"),
secret_id=configurator.get("secret_id"),
)
return client
provider = VaultKVConfigProvider(
vault_connector=vault_client_factory, mount_point=f"{configurator.get('app_name')}/{ENV}"
)
vault, .. :
export SUPERAPP_ENV=dev
export SUPERAPP_APP_NAME=superapp
export SUPERAPP_VAULT_API=https://your-vault-host.domain
export SUPERAPP_ROLE_ID=535b268d-b858-5fb9-1e3e-79068ca77e27 #
export SUPERAPP_SECRET_ID=243ab423-12a2-63dc-3d5d-0b95b1745ccf #
, mount_point , SUPERAPP_ENV. settings- , secret_path .
(, Kafka, Faust) .
from pydantic import Field
from sitri.settings.contrib.vault import VaultKVSettings
from superapp.config.provider_config import provider
class DBSettings(VaultKVSettings):
user: str = Field(..., vault_secret_key="username")
password: str = Field(...)
host: str = Field(...)
port: int = Field(...)
class Config:
provider = provider
default_secret_path = "db"
, , . . - superapp/dev/db, , config , pydantic , extra- vault_secret_key — , pydantic , , .
, , , superapp/dev/db, password username, , user .
:
{
"host": "testhost",
"password": "testpassword",
"port": "1234",
"username": "testuser"
}
, , , :
db_settings = DBSettings()
pprint(db_settings.dict())
# ->
# {
# "host": "testhost",
# "password": "testpassword",
# "port": 1234,
# "user": "testuser"
# }
Kafka
from typing import Dict, Any
from pydantic import Field
from sitri.settings.contrib.vault import VaultKVSettings
from superapp.config.provider_config import provider, configurator
class KafkaSettings(VaultKVSettings):
mechanism: str = Field(..., vault_secret_key="auth_mechanism")
brokers: str = Field(...)
auth_data: Dict[str, Any] = Field(...)
class Config:
provider = provider
default_secret_path = "kafka"
default_mount_point = f"{configurator.get('app_name')}/common"
, , , superapp/common/kafka
{
"auth_data": "{\"password\": \"testpassword\", \"username\": \"testuser\"}",
"auth_mechanism": "SASL_PLAINTEXT",
"brokers": "kafka://test"
}
Dict[str, Any] , :
{
"auth_data":
{
"password": "testpassword",
"username": "testuser"
},
"brokers": "kafka://test",
"mechanism": "SASL_PLAINTEXT"
}
, json, :
{
"auth_data": {
"password": "testpassword",
"username": "testuser"
},
"auth_mechanism": "SASL_PLAINTEXT",
"brokers": "kafka://test"
}
.
P.S.
, secret_path mount_point , ( ). :
Secret path prioritization:
- vault_secret_path (Field arg)
- default_secret_path (Config class field)
- secret_path (provider initialization optional arg)
Mount point prioritization:
- vault_mount_point (Field arg)
- default_mount_point (Config class field)
- mount_point (provider initialization optional arg)
Faust
from typing import Dict
from pydantic import Field, BaseModel
from sitri.settings.contrib.vault import VaultKVSettings
from superapp.config.provider_config import provider
class AgentConfig(BaseModel):
partitions: int = Field(...)
concurrency: int = Field(...)
class FaustSettings(VaultKVSettings):
app_name: str = Field(...)
default_partitions_count: int = Field(..., vault_secret_key="partitions_count")
default_concurrency: int = Field(..., vault_secret_key="agent_concurrency")
agents: Dict[str, AgentConfig] = Field(default=None, vault_secret_key="agents_specification")
class Config:
provider = provider
default_secret_path = "faust"
superapp/dev/faust:
{
"agent_concurrency": "5",
"app_name": "superapp-workers",
"partitions_count": "10"
}
, - - concurrency . , - :
{
"agents": None,
"app_name": "superapp-workers",
"default_concurrency": 5,
"default_partitions_count": 10
}
, X :
{
"partitions": 5,
"concurrency": 2
}
:
{
"agent_concurrency": "5",
"agents_specification": {
"X": {
"concurrency": "2",
"partitions": "5"
}
},
"app_name": "superapp-workers",
"partitions_count": "10"
}
, AgentConfig:
{
"agents":
{
"X":
{
"concurrency": 2,
"partitions": 5
}
},
"app_name": "superapp-workers",
"default_concurrency": 5,
"default_partitions_count": 10
}
from pydantic import BaseModel, Field
from superapp.config.database_settings import DBSettings
from superapp.config.faust_settings import FaustSettings
from superapp.config.kafka_settings import KafkaSettings
class AppSettings(BaseModel):
db: DBSettings = Field(default_factory=DBSettings)
faust: FaustSettings = Field(default_factory=FaustSettings)
kafka: KafkaSettings = Field(default_factory=KafkaSettings)
, default_factory .
, :
from superapp.config import AppSettings
config = AppSettings()
print(config)
print(config.dict())
:
db=DBSettings(user='testuser', password='testpassword', host='testhost', port=1234)
faust=FaustSettings(app_name='superapp-workers', default_partitions_count=10, default_concurrency=5, agents={'X': AgentConfig(partitions=5, concurrency=2)})
kafka=KafkaSettings(mechanism='SASL_PLAINTEXT', brokers='kafka://test', auth_data={'password': 'testpassword', 'username': 'testuser'})
{
"db":
{
"host": "testhost",
"password": "testpassword",
"port": 1234,
"user": "testuser"
},
"faust":
{
"agents":
{
"X":
{
"concurrency": 2,
"partitions": 5
}
},
"app_name": "superapp-workers",
"default_concurrency": 5,
"default_partitions_count": 10
},
"kafka":
{
"auth_data":
{
"password": "testpassword",
"username": "testuser"
},
"brokers": "kafka://test",
"mechanism": "SASL_PLAINTEXT"
}
}
, , !
-:
superapp ├── config │ ├── app_settings.py │ ├── database_settings.py │ ├── faust_settings.py │ ├── __init__.py │ ├── kafka_settings.py │ └── provider_config.py ├── __init__.py └── main.py
Sitri, , vault - .
, . !
P.S. github