Skip to main content

kubesealpy

A Python library for sealing and unsealing Kubernetes secrets, compatible with Bitnami's Sealed Secrets.

Features

  • Native Python implementation - No dependency on the kubeseal CLI
  • Full compatibility - Uses the same hybrid encryption (RSA-OAEP + AES-256-GCM) as kubeseal
  • Multiple certificate sources - Load from files, URLs, or directly from a Kubernetes cluster
  • All sealing scopes - Supports strict, namespace-wide, and cluster-wide scopes
  • Multi-key decryption - Try multiple private keys for key rotation scenarios
  • Type-safe - Full type hints and Pydantic models
  • CLI - New CLI coming in 2006

Installation

pip install kubesealpy

For development:

pip install kubesealpy[dev]

Quick Start

Sealing a Secret

from kubesealpy import Sealer, SealingScope

# Create a sealer from a certificate file
sealer = Sealer.from_certificate_file("/path/to/cert.pem")

# Seal a secret
sealed = sealer.seal(
    name="my-secret",
    namespace="default",
    data={
        "username": b"admin",
        "password": b"supersecret",
    },
)

# Output as YAML (ready to apply to Kubernetes)
print(sealed.to_yaml())

Output:

apiVersion: bitnami.com/v1alpha1
kind: SealedSecret
metadata:
  name: my-secret
  namespace: default
spec:
  encryptedData:
    username: AgBz...
    password: AgCx...
  template:
    metadata:
      name: my-secret
      namespace: default
    type: Opaque

Sealing from a Kubernetes Cluster

from kubesealpy import Sealer, SealingScope

# Fetch the certificate directly from your cluster's sealed-secrets controller
sealer = Sealer.from_cluster(
    controller_name="my-sealed-secrets",
    controller_namespace="sealed-secrets",
)

# Seal a secret
sealed = sealer.seal(
    name="my-secret",
    namespace="default",
    data={"api-key": b"secret-api-key"},
)

print(sealed.to_yaml())

Unsealing a Secret

from kubesealpy import Unsealer, SealedSecret

# Create an unsealer from a private key
unsealer = Unsealer.from_private_key_file("/path/to/private-key.pem")

# Load and unseal
sealed = SealedSecret.from_yaml(open("sealed-secret.yaml").read())
secret = unsealer.unseal(sealed)

# Access the decrypted data
import base64
password = base64.b64decode(secret.data["password"])
print(password.decode())  # "supersecret"

Certificate Sources

From a File

sealer = Sealer.from_certificate_file("/path/to/cert.pem")

From a URL

sealer = Sealer.from_certificate_url("https://example.com/cert.pem")

From a Kubernetes Cluster

# Uses your current kubeconfig context
sealer = Sealer.from_cluster()

# Or specify the controller location
sealer = Sealer.from_cluster(
    controller_name="sealed-secrets-controller",
    controller_namespace="kube-system",
)

From PEM Data

pem_data = open("cert.pem").read()
sealer = Sealer.from_certificate_pem(pem_data)

Sealing Scopes

Sealed Secrets supports three scoping modes that determine where a secret can be unsealed:

Strict (Default)

The secret is bound to both its name and namespace. It cannot be decrypted if either changes.

sealed = sealer.seal(
    name="my-secret",
    namespace="production",
    data={"key": b"value"},
    scope=SealingScope.STRICT,
)

Namespace-wide

The secret is bound only to its namespace. The name can change.

sealed = sealer.seal(
    name="my-secret",
    namespace="production",
    data={"key": b"value"},
    scope=SealingScope.NAMESPACE_WIDE,
)

Cluster-wide

The secret can be decrypted in any namespace with any name.

sealed = sealer.seal(
    name="my-secret",
    namespace="production",
    data={"key": b"value"},
    scope=SealingScope.CLUSTER_WIDE,
)

Working with Existing Secrets

You can seal an existing Kubernetes Secret object:

from kubesealpy import Secret, Sealer

# Create a Secret object
secret = Secret.from_string_data(
    name="my-secret",
    namespace="default",
    data={
        "username": "admin",
        "password": "secret123",
    },
    secret_type="Opaque",
    labels={"app": "myapp"},
)

# Seal it
sealer = Sealer.from_certificate_file("cert.pem")
sealed = sealer.seal_secret(secret)

Multi-Key Decryption

For key rotation scenarios, you can provide multiple private keys:

# From a directory of key files
unsealer = Unsealer.from_private_keys_directory("/path/to/keys/")

# The unsealer will try each key until one works
secret = unsealer.unseal(sealed_secret)

API Reference

Sealer

Method Description
Sealer(public_key) Create from an RSA public key
Sealer.from_certificate_file(path) Create from a PEM certificate file
Sealer.from_certificate_url(url) Create by fetching a certificate from a URL
Sealer.from_certificate_pem(data) Create from PEM certificate data
Sealer.from_cluster() Create by fetching from a Kubernetes cluster
seal(name, namespace, data, scope) Seal a secret
seal_secret(secret, scope) Seal an existing Secret object
seal_value(value, namespace, name, scope) Seal a single value

Unsealer

Method Description
Unsealer(private_keys) Create from a list of RSA private keys
Unsealer.from_private_key(key) Create from a single private key
Unsealer.from_private_key_file(path) Create from a PEM private key file
Unsealer.from_private_keys_directory(dir) Create from all keys in a directory
unseal(sealed_secret) Unseal a SealedSecret
unseal_value(value, namespace, name, scope) Unseal a single value

Models

Class Description
Secret Kubernetes Secret resource
SealedSecret Bitnami SealedSecret CRD
SealingScope Enum: STRICT, NAMESPACE_WIDE, CLUSTER_WIDE

Exceptions

Exception Description
KubesealPyError Base exception for all kubesealpy errors
EncryptionError Encryption operation failed
DecryptionError Decryption operation failed
CertificateError Certificate operation failed
CertificateExpiredError Certificate has expired
PrivateKeyError Private key operation failed
NoMatchingKeyError No private key could decrypt the data

Development

# Clone the repository
git clone https://gitlab.com/nighthawk-oss/kubesealpy
cd kubesealpy

# Install in development mode
pip install -e ".[dev]"

# Run tests
pytest -v

# Run tests with coverage
pytest --cov=kubesealpy --cov-report=term-missing

# Type checking
mypy src/kubesealpy

# Linting
ruff check src/kubesealpy

How It Works

kubesealpy implements the same hybrid encryption scheme as kubeseal:

  1. Session Key Generation: A random 32-byte AES key is generated
  2. RSA Encryption: The session key is encrypted using RSA-OAEP with SHA-256
  3. AES Encryption: The secret data is encrypted using AES-256-GCM with the session key
  4. Label Binding: A cryptographic label (based on scope) is included in RSA-OAEP to bind the ciphertext to specific namespace/name

The output format is:

[2-byte key length (big-endian)] | [RSA-encrypted session key] | [AES-GCM ciphertext]

License

MIT License

Author

Brandon Handeland < pypi at unbuffered dot net >

Metadata

Release files for kubesealpy 1.0.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for kubesealpy 1.0.1
File Size Uploaded Provenance
kubesealpy-1.0.1.tar.gz 14.8 kB Without provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for kubesealpy 1.0.1
File Interpreter ABI Platform
kubesealpy-1.0.1-py3-none-any.whl Python 3 none any Details

Total release size: 32.5 kB

Release files / kubesealpy-1.0.1.tar.gz

Download URL kubesealpy-1.0.1.tar.gz
Size 14.8 kB
Tags Source
SHA-256 checksum
How to use checksums
45a07e5ca690de696edba838e591eee0fedcfd44e8d0c699b3692f9f20488f89
BLAKE2b-256 checksum
How to use checksums
9b562a42b3b88418a125d17ffad35df67ba368df0701d1953e67633c2d414f40
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via poetry/2.2.1 CPython/3.12.12 Linux/5.15.154+

Release files / kubesealpy-1.0.1-py3-none-any.whl

Download URL kubesealpy-1.0.1-py3-none-any.whl
Size 17.7 kB
Tags Python 3
SHA-256 checksum
How to use checksums
132500a36ce30e5e9045770a63a2b7cbd316438862e2f28c17026d09e2509a47
BLAKE2b-256 checksum
How to use checksums
5826b058d77d0a7d81291f70bc43765cd71bb3bbe4b2662fac68d99458bdb471
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via poetry/2.2.1 CPython/3.12.12 Linux/5.15.154+

Security for kubesealpy 1.0.1

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.

Release history Release notifications | RSS feed

This release

1.0.1 This release

2 release files No provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page