kubesealpy
A Python library for sealing and unsealing Kubernetes secrets, compatible with Bitnami's Sealed Secrets.
Features
- Native Python implementation - No dependency on the
kubesealCLI - 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:
- Session Key Generation: A random 32-byte AES key is generated
- RSA Encryption: The session key is encrypted using RSA-OAEP with SHA-256
- AES Encryption: The secret data is encrypted using AES-256-GCM with the session key
- 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
- Bitnami Sealed Secrets - The original project
- kubeseal - Official CLI tool
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)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| kubesealpy-1.0.1.tar.gz | 14.8 kB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| 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.