tools/SDKs/Python SDK

Python SDK

Connect Python applications to SikkerKey with a machine identity, then read, export, cache, and monitor the secrets they are permitted to access.

Updated yesterday

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:

bash
pip install sikkerkey

To install the version covered by this page:

bash
pip install sikkerkey==1.3.0

#Read your first secret

python
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:

python
from sikkerkey import SikkerKey

sikker_key = SikkerKey("vault_...")

You can also load a specific identity file:

python
sikker_key = SikkerKey(
    "/etc/sikkerkey/vaults/vault_.../identity.json"
)

Call SikkerKey() without an argument to select an identity automatically:

python
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:

bash
export SIKKERKEY_HOME=/var/lib/sikkerkey

Use an ephemeral machine

For serverless functions, CI jobs, containers, and other short-lived workloads, create an in-memory identity with an enrollment token:

python
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

python
api_key = sikker_key.get_secret("sk_...")

Read a structured secret

Retrieve every field as a dictionary:

python
database = sikker_key.get_fields("sk_...")

host = database["host"]
username = database["username"]
password = database["password"]

Use get_field when the application needs one field:

python
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:

python
secrets = sikker_key.list_secrets()

for secret in secrets:
    print(f"{secret.id}: {secret.name}")

Limit the list to a project:

python
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:

python
configuration = sikker_key.export()

Pass a project ID to limit the export:

python
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:

python
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.

python
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

python
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:

python
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:

python
production = SikkerKey("vault_...")
staging = SikkerKey("vault_...")

List locally registered vault IDs in alphabetical order:

python
vault_ids = SikkerKey.list_vaults()

#Inspect the active machine

The client exposes the identity it is using for diagnostics:

python
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:

python
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:

  • ConfigurationError for identity, key, vault selection, or bootstrap configuration problems.

  • AuthenticationError for authentication failures.

  • AccessDeniedError when the machine is not permitted to access the resource.

  • NotFoundError when a secret or resource is unavailable.

  • ConflictError for a conflicting request.

  • RateLimitedError when the request remains rate limited after retries.

  • ServerSealedError when the service is temporarily unavailable.

  • ApiError for another HTTP or network failure. Network failures use http_status == 0.

  • SecretStructureError when a structured read receives a non-object value.

  • FieldNotFoundError when 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

SikkerKey(vault_or_path)

Create an ephemeral identity

SikkerKey.bootstrap_in_memory(...)

Read a standard secret

get_secret(secret_id)

Read every structured field

get_fields(secret_id)

Read one structured field

get_field(secret_id, field)

List accessible secrets

list_secrets()

List secrets in a project

list_secrets_by_project(project_id)

Export configuration values

export(project_id)

Enable encrypted fallback

enable_cache(...)

Monitor a secret

watch(secret_id, callback)

Stop monitoring a secret

unwatch(secret_id)

Stop all monitoring

close()

List local vault identities

SikkerKey.list_vaults()


#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.