Python SDK
Connect Python applications to SikkerKey with a machine identity, then read, export, cache, and monitor the secrets they are permitted to access.
The SikkerKey Python SDK gives Python applications secure, read-only access to secrets in your vault. Each client uses a machine identity, so the application can retrieve only the secrets and projects that machine is permitted to access.
#Requirements
Python 3.10 or later
A SikkerKey vault
A machine identity with access to the secrets your application needs
The SDK uses the cryptography package for Ed25519 machine authentication and encrypted fallback storage.
SDK calls are synchronous. In an asynchronous application, run network operations in an executor so they do not block the event loop.
#Install the SDK
Install the latest release from PyPI:
pip install sikkerkeyTo install the version covered by this page:
pip install sikkerkey==1.3.0#Read your first secret
from sikkerkey import SikkerKey
sikker_key = SikkerKey("vault_...")
api_key = sikker_key.get_secret("sk_...")
# Pass api_key directly to the client or service that needs it.The SDK loads the machine identity registered for vault_..., signs the request with the machine's Ed25519 private key, and returns the current value as a str.
Do not print secret values or include them in application logs.
#Choose a machine identity
Use a standard machine for persistent servers and workstations. Use an ephemeral machine for short-lived workloads that should keep their identity only in memory.
Use a standard machine
After provisioning the machine with the SikkerKey CLI, select its vault:
from sikkerkey import SikkerKey
sikker_key = SikkerKey("vault_...")You can also load a specific identity file:
sikker_key = SikkerKey(
"/etc/sikkerkey/vaults/vault_.../identity.json"
)Call SikkerKey() without an argument to select an identity automatically:
sikker_key = SikkerKey()Automatic selection first checks SIKKERKEY_IDENTITY. If it is not set, the SDK selects the identity when exactly one vault is registered under ~/.sikkerkey/vaults/. Select a vault explicitly when several identities are available.
Set SIKKERKEY_HOME when the application uses a different protected identity directory:
export SIKKERKEY_HOME=/var/lib/sikkerkeyUse an ephemeral machine
For serverless functions, CI jobs, containers, and other short-lived workloads, create an in-memory identity with an enrollment token:
import os
from sikkerkey import SikkerKey
sikker_key = SikkerKey.bootstrap_in_memory(
os.environ["SIKKERKEY_VAULT_ID"],
os.environ["SIKKERKEY_ENROLLMENT_TOKEN"],
hostname="checkout-worker",
name="Checkout worker",
)
api_key = sikker_key.get_secret("sk_...")The SDK generates an Ed25519 key pair in memory, registers the ephemeral machine, and returns a ready client. It does not write an identity or private key to disk. The private key disappears when the process exits.
The machine follows the access, hostname rules, use limit, and lifetime configured on the enrollment token. hostname defaults to the HOSTNAME environment variable and then to serverless. A name pattern configured on the token takes precedence over name.
Set the ephemeral machine lifetime long enough for the workload to finish, allow enough token uses for concurrent starts, and keep enrollment tokens in protected runtime configuration.
#Read secrets
Read a standard secret
api_key = sikker_key.get_secret("sk_...")Read a structured secret
Retrieve every field as a dictionary:
database = sikker_key.get_fields("sk_...")
host = database["host"]
username = database["username"]
password = database["password"]Use get_field when the application needs one field:
password = sikker_key.get_field(
"sk_...",
"password",
)Structured values are converted to strings. get_fields raises SecretStructureError when the value is not a structured object. get_field raises FieldNotFoundError and includes the available field names when the requested field is missing.
#Discover accessible secrets
List the secret metadata available to the current machine:
secrets = sikker_key.list_secrets()
for secret in secrets:
print(f"{secret.id}: {secret.name}")Limit the list to a project:
project_secrets = sikker_key.list_secrets_by_project(
"proj_..."
)Each SecretListItem contains id, name, field_names, and project_id. Listing returns metadata, not secret values.
#Export secrets for application configuration
Export all accessible values in one request:
configuration = sikker_key.export()Pass a project ID to limit the export:
configuration = sikker_key.export("proj_...")The returned dict[str, str] uses uppercase environment-style names. Spaces and punctuation become underscores. Structured secrets are flattened into one entry per field, such as DATABASE_HOST and DATABASE_PASSWORD.
Apply the values to the current process when that matches your application's configuration model:
import os
os.environ.update(configuration)#Enable encrypted fallback
Encrypted fallback allows a persistent application to use a previously retrieved value during a temporary network or service interruption. It is disabled until you enable it.
import logging
sikker_key = SikkerKey("vault_...").enable_cache(
max_age=3600,
on_fallback=lambda secret_id, cached_at: logging.warning(
"Using cached value for %s from epoch %s",
secret_id,
cached_at,
),
)Successful reads are encrypted locally with AES-256-GCM using a key derived from the machine identity and vault. max_age is measured in seconds and accepts an integer or float. Passing None means cached values do not expire automatically. on_fallback is optional and runs only when the SDK serves a cached value.
Fallback is limited to network failures, request timeouts, and temporary gateway or service availability responses. Authentication failures, denied access, missing secrets, rate limits, and other authoritative responses are returned to the application instead of being replaced by an older value.
Cache entries are stored under the vault's identity directory. They are bound to the machine, vault, secret, and creation time, and are rejected if they have been altered or belong to another identity. The cache format is compatible with SikkerKey CLI and the other SikkerKey SDKs.
Encrypted fallback is designed for a host with a persistent, protected identity directory. An ephemeral identity cannot recover its cache key after the process exits.
#Monitor secrets for changes
import logging
from sikkerkey import WatchStatus
def handle_change(event):
if event.status == WatchStatus.CHANGED:
reload_client(event.value, event.fields)
elif event.status == WatchStatus.DELETED:
logging.warning("Secret %s was deleted", event.secret_id)
elif event.status == WatchStatus.ACCESS_DENIED:
logging.warning("Access to %s was removed", event.secret_id)
elif event.status == WatchStatus.ERROR:
logging.error("Secret update failed: %s", event.error)
sikker_key.watch("sk_...", handle_change)The SDK checks watched secrets on a background daemon thread. It performs the first poll when the thread starts, then waits 15 seconds between cycles by default. A changed event includes the latest value and parsed fields when the secret is structured.
Deleted secrets and secrets the machine can no longer access are automatically removed from the watch list. A failed polling request is skipped and tried again during the next cycle. If retrieving a changed value fails, the callback receives WatchStatus.ERROR.
Callbacks run on the polling thread. Hand slow or blocking work to another thread, executor, or queue. The SDK contains callback exceptions so one callback cannot stop later polling; handle and log callback failures inside the callback when they matter to your application.
Change the interval, stop one watcher, or stop all monitoring:
sikker_key.set_poll_interval(30) # seconds; minimum 10
sikker_key.unwatch("sk_...")
sikker_key.close()Closing the watcher leaves the client available for subsequent secret reads.
#Work with multiple vaults
Create one client for each vault the application uses:
production = SikkerKey("vault_...")
staging = SikkerKey("vault_...")List locally registered vault IDs in alphabetical order:
vault_ids = SikkerKey.list_vaults()#Inspect the active machine
The client exposes the identity it is using for diagnostics:
machine_id = sikker_key.machine_id
machine_name = sikker_key.machine_name
vault_id = sikker_key.vault_id
api_url = sikker_key.api_url#Handle errors
All SDK exceptions extend SikkerKeyError. Catch a specific exception when the application can respond to that condition:
from sikkerkey import (
AccessDeniedError,
ApiError,
AuthenticationError,
ConfigurationError,
NotFoundError,
RateLimitedError,
)
try:
value = sikker_key.get_secret("sk_...")
except NotFoundError:
handle_missing_secret()
except AccessDeniedError:
handle_removed_access()
except AuthenticationError:
handle_machine_authentication_failure()
except RateLimitedError:
schedule_later_retry()
except ApiError as error:
record_service_error(error.http_status)
except ConfigurationError:
handle_identity_configuration_failure()The exception types are:
ConfigurationErrorfor identity, key, vault selection, or bootstrap configuration problems.AuthenticationErrorfor authentication failures.AccessDeniedErrorwhen the machine is not permitted to access the resource.NotFoundErrorwhen a secret or resource is unavailable.ConflictErrorfor a conflicting request.RateLimitedErrorwhen the request remains rate limited after retries.ServerSealedErrorwhen the service is temporarily unavailable.ApiErrorfor another HTTP or network failure. Network failures usehttp_status == 0.SecretStructureErrorwhen a structured read receives a non-object value.FieldNotFoundErrorwhen a requested structured field does not exist.
Retries and timeout
Authenticated requests retry network failures and HTTP 429 or 503 responses up to three times, waiting 1, 2, and 4 seconds. Every retry uses a fresh timestamp and nonce. Each request has a 15-second timeout; other HTTP responses are returned immediately as their matching exception.
#Method reference
Task | Method |
|---|---|
Connect with a registered identity |
|
Create an ephemeral identity |
|
Read a standard secret |
|
Read every structured field |
|
Read one structured field |
|
List accessible secrets |
|
List secrets in a project |
|
Export configuration values |
|
Enable encrypted fallback |
|
Monitor a secret |
|
Stop monitoring a secret |
|
Stop all monitoring |
|
List local vault identities |
|
#Source code and license
The Python SDK is open source under the MIT License. Review the source, report an issue, or contribute through the SikkerKeyOfficial GitHub organization.