Python client for Selectel Secrets Manager (sync + async)
Project description
selectel-sm
A typed Python client for Selectel Secrets Manager, with both synchronous and asynchronous clients sharing a single transport-agnostic core.
⚠️ Disclaimer
This is a non-commercial, community project built out of pure enthusiasm. I am not an employee of Selectel and have no affiliation with them whatsoever. I built this simply because I couldn't find a maintained library for working with Selectel's Secrets Manager.
Installation
pip install selectel-sm # library
pip install "selectel-sm[cli]" # + CLI (typer + rich)
Requires Python 3.12+.
Authentication
Secrets Manager requires a project-scoped IAM token. (The public docs mention an account-scoped token, but in practice SM rejects it — a project-scoped token is required.) The library obtains one for you from service-user credentials, caches it, and refreshes it before expiry:
from selectel_sm import SecretsManagerClient
with SecretsManagerClient.from_credentials(
region="ru-7",
account_id="123456",
username="my-service-user",
password="...",
project_name="my-project",
) as client:
secret = client.secrets.get("database_password")
print(secret.value) # -> b"..."
Or bring your own project-scoped token (the client introspects it to discover the service catalog):
client = SecretsManagerClient.from_token(region="ru-7", token="gAAAAAB...")
The async client mirrors the same API:
from selectel_sm import AsyncSecretsManagerClient
async with AsyncSecretsManagerClient.from_credentials(region="ru-7", ...) as client:
secret = await client.secrets.get("database_password")
Endpoint resolution
The Secrets Manager URL is not hardcoded. After authenticating, the library reads the
service catalog returned in the Keystone token and resolves the secrets-manager endpoint for
the configured region and interface (default public). Set sm_base_url on the client to
bypass catalog resolution (e.g. for testing).
Usage
All operations live under client.secrets (and identically on the async client with await).
Secrets
# Create a secret with its first version. `value` is plain data (bytes or str);
# it is base64-encoded for you before being sent.
client.secrets.create("api_key", "s3cr3t", description="Third-party API key")
# Read the current value.
secret = client.secrets.get("api_key")
secret.value # b"s3cr3t"
secret.description # "Third-party API key" ("" from the API becomes None)
secret.version # the current SecretVersion
# Update / clear the description (None clears it).
client.secrets.update_description("api_key", "Rotated key")
# List all secrets (metadata only — no values).
for summary in client.secrets.list():
print(summary.name, summary.type, summary.description, summary.created_at)
# Delete a secret and all of its versions.
client.secrets.delete("api_key")
Versions
# Add a new version. Pass activate=True to make it the current version.
client.secrets.create_version("api_key", "rotated-secret", activate=True)
# The secret plus metadata for all of its versions (no values).
sv = client.secrets.get_versions("api_key")
sv.versions # tuple[SecretVersion, ...]
sv.current # the version flagged is_current, if any
# A single version, including its value.
version = client.secrets.get_version("api_key", version_id=1)
version.value # b"..."
# Make a specific version current.
client.secrets.activate_version("api_key", version_id=1)
Error handling
Every error derives from SelectelSMError, so you can catch broadly or narrowly:
from selectel_sm import NotFoundError, SelectelSMError
try:
client.secrets.get("does-not-exist")
except NotFoundError:
...
except SelectelSMError:
...
HTTP statuses map to BadRequestError (400), ForbiddenError (403), NotFoundError (404),
ConflictError (409), and ServerError (5xx). Authentication and endpoint-resolution problems
raise AuthenticationError and EndpointNotFoundError respectively.
A note on quirks
Selectel's Secrets Manager API has a few undocumented behaviors this client handles for you, for example:
- Listing requires a
?list=<any value>flag and a trailing slash (/v1/?list=true), otherwise it returns404 page not found. - Secret values must be valid base64 — the client always encodes plain input for you.
activate versionis documented as204 No Contentbut actually returns200with the version's metadata.
Support & maintenance
Because I don't work with Selectel, I may not be aware of the latest changes to their API, and something could break unexpectedly. I do my best to keep this library up to date, but that isn't always possible. Contributions, bug reports, and help with its development are very welcome — please open an issue or a pull request.
Development
uv sync
uv run ruff check . && uv run ruff format --check .
uv run mypy selectel_sm
uv run pytest
License
MIT © Andrew Krylov
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file selectel_sm-0.1.1.tar.gz.
File metadata
- Download URL: selectel_sm-0.1.1.tar.gz
- Upload date:
- Size: 68.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: Hatch/1.17.0 {"ci":null,"cpu":"x86_64","distro":{"id":"resolute","libc":{"lib":"glibc","version":"2.43"},"name":"Ubuntu","version":"26.04"},"implementation":{"name":"CPython","version":"3.14.4"},"installer":{"name":"hatch","version":"1.17.0"},"openssl_version":"OpenSSL 3.5.5 27 Jan 2026","python":"3.14.4","system":{"name":"Linux","release":"7.0.0-22-generic"}} HTTPX2/2.4.0
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
23b0618893b2ca8081ed900104f1ed978580d0ec96e1d510534ed4981a55162b
|
|
| MD5 |
9c9244b5eb7297869e0befde9dd66fba
|
|
| BLAKE2b-256 |
453262504ef3f488002af32c3f162cc82e35b0c660a704fede8b9f7db722b1a3
|
File details
Details for the file selectel_sm-0.1.1-py3-none-any.whl.
File metadata
- Download URL: selectel_sm-0.1.1-py3-none-any.whl
- Upload date:
- Size: 32.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: Hatch/1.17.0 {"ci":null,"cpu":"x86_64","distro":{"id":"resolute","libc":{"lib":"glibc","version":"2.43"},"name":"Ubuntu","version":"26.04"},"implementation":{"name":"CPython","version":"3.14.4"},"installer":{"name":"hatch","version":"1.17.0"},"openssl_version":"OpenSSL 3.5.5 27 Jan 2026","python":"3.14.4","system":{"name":"Linux","release":"7.0.0-22-generic"}} HTTPX2/2.4.0
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3befcc630a1166fbd465763f5dcac99d1e8f85d8e47fde4cdb5b5aeb4a2a0d2c
|
|
| MD5 |
58261ebe9274671dab5a92aa22c4dd5f
|
|
| BLAKE2b-256 |
4d198d6319194dbf440becde5b0bc1d141f13be3e7896d846c4a6397c42891b5
|