This release is a pre-release and may not be stable for production use.
Swarmauri Hierarchical Key Provider
Plugin providing a policy-driven composite key provider capable of routing
key operations across multiple child providers. It implements the
IKeyProvider interface and exposes a single HierarchicalKeyProvider
class.
Overview
HierarchicalKeyProvider composes a mapping of named child providers and
routes every key operation to the correct child according to declarative
policies. It offers:
- Create/import routing ? specify ordered
CreateRuleobjects that match key class, algorithm, usage, or export policy. The first rule that matches aKeySpecwins. - Automatic discovery ? when looking up an unknown key identifier (KID) the provider probes each child until it finds the owning provider and caches the association for future calls.
- Persistent indexing ? optionally persist the learned KID ? provider map
to JSON via the
index_fileargument so the routing cache survives process restarts. - Capability passthrough ? rotate, destroy, list, JWKS, HKDF, and random byte requests are forwarded transparently to the owning (or designated) child provider. JWKS responses are merged across children while avoiding duplicate KIDs.
- Heuristic fallback ? if no policy matches a create/import request the provider falls back to sensible defaults: asymmetric keys prefer children named like KMS/PKCS#11, symmetric keys prefer local/file providers, and otherwise the first registered child is used.
Installation
Choose the installer that matches your workflow.
pip
pip install swarmauri_keyprovider_hierarchical
Poetry
poetry add swarmauri_keyprovider_hierarchical
uv
uv venv # create (or reuse) a virtual environment
source .venv/bin/activate
uv pip install swarmauri_keyprovider_hierarchical
If you are already inside a uv-managed environment you can shorten the last
two steps to uv pip install swarmauri_keyprovider_hierarchical.
Quickstart
The example below wires two LocalKeyProvider instances behind a
HierarchicalKeyProvider. Symmetric keys are routed to a local provider while
asymmetric keys land on a provider named kms. The composite provider also
serves random bytes and JWKS responses for all children.
"""Create keys across multiple providers with policy-driven routing."""
import asyncio
from swarmauri_keyprovider_hierarchical import HierarchicalKeyProvider, CreateRule
from swarmauri_keyprovider_local import LocalKeyProvider
from swarmauri_core.key_providers.types import (
ExportPolicy,
KeyAlg,
KeyClass,
KeySpec,
KeyUse,
)
async def main() -> None:
children = {
"kms": LocalKeyProvider(),
"local": LocalKeyProvider(),
}
provider = HierarchicalKeyProvider(
children,
create_policy=[
CreateRule(provider="kms", klass=KeyClass.asymmetric),
CreateRule(provider="local", klass=KeyClass.symmetric),
],
randomness_provider="local", # designate a child for random_bytes
)
symmetric_spec = KeySpec(
klass=KeyClass.symmetric,
alg=KeyAlg.AES256_GCM,
uses=(KeyUse.ENCRYPT, KeyUse.DECRYPT),
export_policy=ExportPolicy.SECRET_WHEN_ALLOWED,
)
asymmetric_spec = KeySpec(
klass=KeyClass.asymmetric,
alg=KeyAlg.ED25519,
uses=(KeyUse.SIGN, KeyUse.VERIFY),
export_policy=ExportPolicy.PUBLIC_ONLY,
)
symmetric_ref = await provider.create_key(symmetric_spec)
asymmetric_ref = await provider.create_key(asymmetric_spec)
random_token = await provider.random_bytes(16)
jwks = await provider.jwks()
print(f"Symmetric key kid: {symmetric_ref.kid}")
print(f"Asymmetric key kid: {asymmetric_ref.kid}")
print(f"Random token length: {len(random_token)} bytes")
print(f"JWKS entries: {len(jwks['keys'])}")
if __name__ == "__main__":
asyncio.run(main())
Running the script prints the generated key identifiers, confirms the random token length, and shows how many public keys were merged into the JWKS document.
Routing policy
CreateRule is a dataclass that narrows matching by any combination of
attributes:
provider(required): the name of the child provider to route to.klass: limit matches to a specificKeyClass(symmetric or asymmetric).algs: iterable of allowedKeyAlgvalues.uses: iterable of desiredKeyUsevalues; at least one requested use must intersect with the spec.export_policies: iterable ofExportPolicyvalues.
Rules are evaluated in order, and the first match wins. When an import policy is not supplied, create rules are re-used for imports.
Index persistence & discovery
Pass index_file to persist the in-memory KID ? provider cache as JSON. On
startup, any known mappings are re-loaded (invalid provider names are skipped).
When a lookup is made for an unknown KID the provider probes each child with a
get_key call; if a child recognizes the KID the mapping is remembered and
future calls avoid probing. Destroying a key (without specifying a version)
removes the cached entry.
Randomness & key derivation
Use the randomness_provider and derivation_provider keyword arguments to
pin those helper methods to a specific child. If they are omitted the first
registered provider is used for both random bytes and HKDF requests.
Want to help?
If you want to contribute to swarmauri-sdk, read up on our guidelines for contributing that will help you get started.
Metadata
Release files for swarmauri_keyprovider_hierarchical 0.11.0.dev1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| swarmauri_keyprovider_hierarchical-0.11.0.dev1.tar.gz | 11.5 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| swarmauri_keyprovider_hierarchical-0.11.0.dev1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 24.4 kB
Release files / swarmauri_keyprovider_hierarchical-0.11.0.dev1.tar.gz
| Download URL | swarmauri_keyprovider_hierarchical-0.11.0.dev1.tar.gz |
|---|---|
| Size | 11.5 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
10b43cf722efdfe099f26165285293c6ad988bf67791235dbed433c49117eb74
|
|
BLAKE2b-256 checksum How to use checksums |
67eee9d55c90aaa3b913ac66b07fad45eb6d2292692d718c26b50b6b068a208a
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.11.26 {"installer":{"name":"uv","version":"0.11.26","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / swarmauri_keyprovider_hierarchical-0.11.0.dev1-py3-none-any.whl
| Download URL | swarmauri_keyprovider_hierarchical-0.11.0.dev1-py3-none-any.whl |
|---|---|
| Size | 12.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
b6155e7d97bbcb058fb2d673f05fbc2241e081032594f29893b7b9246ec43fd7
|
|
BLAKE2b-256 checksum How to use checksums |
deae1532fa98f21c032d45919a8a7e8414e7f9450353244ec8fa70346a7cd0a0
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.11.26 {"installer":{"name":"uv","version":"0.11.26","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|