Skip to main content

Python library for sealing and unsealing Kubernetes Sealed Secrets

Project description

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

Related Projects

Author

Brandon Handeland < pypi at unbuffered dot net >

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

kubesealpy-1.0.1.tar.gz (14.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

kubesealpy-1.0.1-py3-none-any.whl (17.7 kB view details)

Uploaded Python 3

File details

Details for the file kubesealpy-1.0.1.tar.gz.

File metadata

  • Download URL: kubesealpy-1.0.1.tar.gz
  • Upload date:
  • Size: 14.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/2.2.1 CPython/3.12.12 Linux/5.15.154+

File hashes

Hashes for kubesealpy-1.0.1.tar.gz
Algorithm Hash digest
SHA256 45a07e5ca690de696edba838e591eee0fedcfd44e8d0c699b3692f9f20488f89
MD5 2393caa1478ba77ad2c35712bae0daee
BLAKE2b-256 9b562a42b3b88418a125d17ffad35df67ba368df0701d1953e67633c2d414f40

See more details on using hashes here.

File details

Details for the file kubesealpy-1.0.1-py3-none-any.whl.

File metadata

  • Download URL: kubesealpy-1.0.1-py3-none-any.whl
  • Upload date:
  • Size: 17.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/2.2.1 CPython/3.12.12 Linux/5.15.154+

File hashes

Hashes for kubesealpy-1.0.1-py3-none-any.whl
Algorithm Hash digest
SHA256 132500a36ce30e5e9045770a63a2b7cbd316438862e2f28c17026d09e2509a47
MD5 b9fbc911f6f512bbb002786cd6bf01b4
BLAKE2b-256 5826b058d77d0a7d81291f70bc43765cd71bb3bbe4b2662fac68d99458bdb471

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page