sysnet-apikeys
Sdílená knihovna pro správu API klíčů FastAPI služeb SYSNET: klíč se ukládá jen jako SHA-256, klient může mít víc klíčů, rotace probíhá s překryvem bez výpadku, klíče mají oprávnění (scopes) a platnost, správa je přes CLI nebo admin API. Rozhodnutí a zdůvodnění: interní ADR 006 společnosti SYSNET.
Stav: 1.1.0 (stabilní API). Jádro, úložiště (paměť, SQL, Mongo, starý YAML jen pro čtení), vazba na FastAPI, admin router, CLI a audit.
Pilotně nasazeno: taxonomy na vývojovém prostředí (Hermes VM, APIKEYS_STORE=mongo). Produkční nasazení zatím neproběhlo.
Dokumentace
| Jste... | Dokument |
|---|---|
| Uživatel (volám službu s klíčem) | docs/uzivatel.md |
| Programátor (zapojuji knihovnu) | docs/programator.md |
| Administrátor (spravuji klíče a provoz) | docs/administrator.md |
| Manažer (rozhoduji) | docs/manazer.md |
Přehled: docs/README.md. Změny: CHANGELOG.md.
Co řeší
- Klíč se ukládá jako SHA-256, otevřený klíč se vrací jednou při vydání.
- Klient má víc klíčů; rotace vydá nový klíč a starému zkrátí platnost na
nyní + grace. Oba platí souběžně. - Chybějící, neznámý, zrušený i propadlý klíč dává stejnou chybu (nic se nenapovídá útočníkovi).
- Identita se vrací hodnotou (
Principal). Nesdílí se stav mezi požadavky, na rozdíl od starší funkceContext.check_api_keyvsysnet-pyutils, která identitu ukládá do sdíleného stavu. - Nové klíče mají tvar
snk_<public_id>_<tajemství>;public_idje bezpečné uvádět v logu a v tiketu.
Instalace
pip install "sysnet-apikeys[fastapi,mongo]" # nebo [fastapi,sql]; CLI: přidejte cli, audit: přidejte audit
Python 3.11 a vyšší.
Příklad (spouští se jako test)
import asyncio
from datetime import timedelta
from typing import Annotated
import httpx
from fastapi import Depends, FastAPI
from sysnet_apikeys import ApiKeyService, InMemoryStore, Principal
from sysnet_apikeys.fastapi import ApiKeyAuth, install_error_handlers
service = ApiKeyService(InMemoryStore())
auth = ApiKeyAuth(service)
app = FastAPI()
install_error_handlers(app)
@app.get("/dokumenty")
async def dokumenty(principal: Annotated[Principal, Depends(auth)]) -> dict[str, str]:
return {"volá": principal.client}
async def main() -> None:
old = await service.issue("ippc-docs", scopes=["read"])
new = await service.rotate("ippc-docs", grace=timedelta(days=1))
async with httpx.AsyncClient(transport=httpx.ASGITransport(app=app), base_url="http://t") as c:
for key in (old.key, new.key):
print((await c.get("/dokumenty", headers={"X-API-KEY": key})).status_code)
asyncio.run(main())
Výstup: 200 a 200. Starý i nový klíč platí do konce překryvu.
Úložiště
| Úložiště | Extra | Poznámka |
|---|---|---|
MongoStore(db, collection=...) |
mongo |
pymongo.AsyncMongoClient; _id = hash, unikátní public_id |
SqlStore(engine, table=...) |
sql |
PostgreSQL (asyncpg); create_schema() vytvoří tabulku |
LegacyYamlStore |
(jádro) | jen pro čtení, pro migraci |
InMemoryStore |
(jádro) | testy a malé nástroje |
Admin API a CLI
app.include_router(make_admin_router(service, admin_key=os.environ.get("ADMIN_API_KEY")), prefix="/admin")
Proměnná se jmenuje ADMIN_API_KEY stejně jako v notificator a geocode. Bez admin_key vrací admin API 503.
Vygenerování při nasazení (jednou, hodnotu nikdy nevypíše, existující nepřepíše, nový soubor má práva 600):
sysnet-apikeys admin-key /opt/docker/<služba>/.env --ensure # bez --ensure jen ověří (kód 1 = chybí)
CLI čte úložiště z proměnných APIKEYS_STORE (mongo|sql) a APIKEYS_MONGO_URL/APIKEYS_MONGO_DB nebo APIKEYS_SQL_URL.
Příkazy: issue, rotate, revoke, list, unused, import-yaml, admin-key. Otevřený klíč tiskne jen issue a rotate.
Klíč je bez expirace, dokud nezadáte --expires-in-days N (u issue i rotate). Volba --admin-key-file (nebo APIKEYS_ADMIN_KEY_FILE) zapne kontrolu ADMIN_API_KEY u příkazů, které mění úložiště; bez ní se chování nemění.
import-yaml conf/x.yml je dry-run, --apply zapíše hashe (klienti se nemění). Postupy najdete v příručce administrátora.
Audit (sysnet-audit)
from audit_lib import AuditLogger, MongoAuditBackend
from sysnet_apikeys.audit import audit_hook
service = ApiKeyService(
store, audit=audit_hook(AuditLogger(backend=MongoAuditBackend(), service_name="moje-sluzba"))
)
Vydání, rotace a rušení klíče se zapíše jako api_key.issued|rotated|revoked. Klíč ani hash se nezapisují.
Selhání zápisu auditu operaci nezruší. Vyžaduje pip install "sysnet-apikeys[audit]" a nastavení audit_lib.
Migrace ze starého YAML
LegacyYamlStore.from_file("conf/xyz.yml") čte stávající api_keys: [{klíč: jméno}]. Klíče dostanou oprávnění *
a Principal.agenda a Principal.client odpovídají dnešnímu agenda a user_name. Úložiště je jen pro čtení.
Známá omezení
- Souběžné vydání klíče téhož klienta není atomické (může vzniknout víc aktivních klíčů). Podrobnosti v příručce programátora.
- Hash bez soli je určen jen pro klíče s vysokou entropií, ne pro hesla.
Vývoj
python -m venv .venv && .venv/bin/pip install -e ".[dev]"
.venv/bin/python -m pytest && .venv/bin/ruff check . && .venv/bin/mypy
Testy úložišť potřebují PostgreSQL a MongoDB (APIKEYS_TEST_PG, APIKEYS_TEST_MONGO); bez nich padají, nepřeskakují se.
Verzování: pyproject.toml a sysnet_apikeys/__init__.py musí mít stejnou verzi, tag vX.Y.Z spustí release.
Licence
GNU Affero General Public License v3.0 nebo novější (AGPL-3.0-or-later), plný text v LICENSE.
Stejně jsou licencované ostatní sdílené knihovny SYSNET, na kterých balíček stojí (sysnet-pyutils, sysnet-audit).
Pokud službu postavenou na této knihovně zpřístupníte uživatelům po síti, musíte jim nabídnout odpovídající zdrojový kód
včetně svých změn knihovny (§13). Interní provoz bez zpřístupnění třetím stranám tím dotčen není. Toto je obecná orientace, ne právní stanovisko.
Copyright (C) SYSNET s.r.o.
Metadata
Release files for sysnet-apikeys 1.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| sysnet_apikeys-1.1.0.tar.gz | 66.5 kB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| sysnet_apikeys-1.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 105.4 kB
Release files / sysnet_apikeys-1.1.0.tar.gz
| Download URL | sysnet_apikeys-1.1.0.tar.gz |
|---|---|
| Size | 66.5 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
58ba9f967fd310e291054b22f572258277655522e1ebba6fa780fb5170549710
|
|
BLAKE2b-256 checksum How to use checksums |
b90aa61947601734721929bac914e38f362551ce5b1de154af89f2bf6c6ca67b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.11.16
|
Release files / sysnet_apikeys-1.1.0-py3-none-any.whl
| Download URL | sysnet_apikeys-1.1.0-py3-none-any.whl |
|---|---|
| Size | 38.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
af55093c24de74ffc365b6382906b8a4aff67d508f87a53e8665d18b54a04bdf
|
|
BLAKE2b-256 checksum How to use checksums |
ab6e68dffcd5a3d6bc4c403b250710000196aa3cf336d3a47d995e65beb58095
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.11.16
|
Security for sysnet-apikeys 1.1.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.