@linode/kubeseal-encrypt
v1.0.1
Published
Hybrid RSA-OAEP + AES-GCM encryption for Kubernetes Sealed Secrets in browser and Node.js
Downloads
345
Maintainers
Readme
@linode/kubeseal-encrypt
Hybrid RSA-OAEP + AES-GCM encryption for Kubernetes Sealed Secrets, compatible with both browser and Node.js environments.
Features
- ✅ Browser and Node.js support
- ✅ Compatible with Bitnami Sealed Secrets
- ✅ TypeScript with full type definitions
- ✅ Zero runtime dependencies
- ✅ ESM and CommonJS support
- ✅ PEM validation
- ✅ Tree-shakeable
Installation
npm install @linode/kubeseal-encryptUsage
Browser
import { encryptSecretItem } from '@linode/kubeseal-encrypt'
const publicKeyPEM = `-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA...
-----END PUBLIC KEY-----`
const encryptedData = await encryptSecretItem(
publicKeyPEM,
'default', // Kubernetes namespace
'my-secret-value'
)
console.log(encryptedData)Node.js
const { encryptSecretItem } = require('@linode/kubeseal-encrypt')
const fs = require('fs')
// Read PEM from file
const publicKeyPEM = fs.readFileSync('./sealed-secrets-cert.pem', 'utf8')
// Encrypt data
const encryptedData = await encryptSecretItem(
publicKeyPEM,
'default',
'my-secret-value'
)
console.log(encryptedData)With Validation
import { encryptSecretItem, validatePEM, validateNamespace } from '@linode/kubeseal-encrypt'
// Validate PEM before using
const pemValidation = validatePEM(publicKeyPEM)
if (!pemValidation.valid) {
console.error('Invalid PEM:', pemValidation.error)
process.exit(1)
}
// Validate namespace
const nsValidation = validateNamespace('my-namespace')
if (!nsValidation.valid) {
console.error('Invalid namespace:', nsValidation.error)
process.exit(1)
}
// Encrypt
const encrypted = await encryptSecretItem(publicKeyPEM, 'my-namespace', 'secret-value')API Reference
encryptSecretItem(sealedSecretsPEM, namespace, data)
Encrypts data using the Sealed Secrets public key.
Parameters:
sealedSecretsPEM(string): PEM-formatted RSA public key from sealed-secrets controllernamespace(string): Kubernetes namespace (required)data(string): Data to encrypt
Returns: Promise<string> - Encrypted data
Throws:
Errorif PEM format is invalidErrorif namespace is invalidErrorif crypto API is unavailable
validatePEM(pem)
Validates PEM format.
Parameters:
pem(string): PEM-formatted public key
Returns: ValidationResult - Object with valid boolean and optional error message
validateNamespace(namespace)
Validates Kubernetes namespace format.
Parameters:
namespace(string): Kubernetes namespace to validate
Returns: ValidationResult - Object with valid boolean and optional error message
How It Works
This package implements the same hybrid encryption scheme as kubeseal:
- RSA-OAEP: Encrypts a random 256-bit AES session key using the sealed-secrets public key
- AES-GCM: Encrypts the actual data with the session key
- Output format:
[2-byte RSA length][RSA-encrypted key][AES-encrypted data][16-byte auth tag]
The namespace is used as the RSA-OAEP label for additional security, ensuring that encrypted data can only be decrypted in the correct namespace.
Getting the Public Key
The recommended way to get the sealed-secrets public certificate is using kubeseal:
Method 1: Fetch from Controller (Recommended)
kubeseal --fetch-cert \
--controller-name=sealed-secrets-controller \
--controller-namespace=kube-system \
> sealed-secrets-cert.pem[!NOTE]
Replace sealed-secrets-controller and kube-system with your actual controller name and namespace if different.
This fetches the certificate directly from the sealed-secrets controller running in your cluster.
Method 2: Download from Kubernetes directly
The controller prints the certificate to its logs on startup. You can retrieve it with:
kubectl get secret -n kube-system sealed-secrets-key \
-o jsonpath="{.data['public\.pem']}" | base64 -d > sealed-secrets-cert.pem[!NOTE]
Replace the namespace and secret name if they are different in your setup.
Notes
- The certificate automatically renews every 30 days (since v0.9.x)
- For offline/air-gapped environments, save the certificate locally and distribute it
- You can set the
SEALED_SECRETS_CERTenvironment variable to point to a local certificate file
Requirements
- Browser: Modern browser with Web Crypto API support
- Node.js: Version 18.0.0 or higher
TypeScript
This package includes full TypeScript type definitions:
import type { ValidationResult, CryptoAdapter, AlgorithmConfig } from '@linode/kubeseal-encrypt'Development
# Install dependencies
npm install
# Run tests
npm test
# Run tests with coverage
npm run test:coverage
# Build package
npm run build
# Create local tarball for testing
npm run pack:localTesting Locally
In Another Project
Build and pack the package:
npm run build npm packInstall in your project:
npm install /path/to/linode-kubeseal-encrypt-1.0.0.tgzUse it:
const { encryptSecretItem } = require('@linode/kubeseal-encrypt')
In Kubernetes Cluster
Get the sealed-secrets public key:
kubeseal --fetch-cert \ --controller-name=sealed-secrets-controller \ --controller-namespace=kube-system \ > sealed-secrets-cert.pem[!NOTE]
Replace sealed-secrets-controller and kube-system with your actual controller name and namespace if different.Create a test script:
const { encryptSecretItem } = require('@linode/kubeseal-encrypt') const fs = require('fs') ;(async () => { const pem = fs.readFileSync('public-key.pem', 'utf8') const encrypted = await encryptSecretItem(pem, 'default', 'test-secret') console.log('Encrypted:', encrypted) })()Create a SealedSecret manifest:
apiVersion: bitnami.com/v1alpha1 kind: SealedSecret metadata: name: my-sealed-secret namespace: default spec: encryptedData: password: <encrypted-data-from-script>Apply and verify:
kubectl apply -f sealed-secret.yaml kubectl get secret my-sealed-secret -o yaml
License
Copyright 2025 Akamai Technologies, Inc.
Licensed under the Apache License, Version 2.0. See LICENSE for details.
Contributing
We welcome contributions! Please see CONTRIBUTING.md for guidelines.
For security issues, please see SECURITY.md.
Privacy
For information about Akamai's privacy practices, please visit https://www.akamai.com/legal/privacy-statement
