Loading...
Loading...
Seal or reseal Kubernetes Secrets into SealedSecrets using kubeseal for secure GitOps storage. Use whenever the user says seal, reseal, or re-seal a secret or SealedSecret, and when they need to create, update, rotate, or fix SealedSecrets, seal credentials for GitOps repos, or migrate secrets between services. NEVER leak plaintext credentials or seal keys in output, logs, or files.
npx skill4agent add mmontes11/skills kubesealValidated againstv0.38.4. Flag names are stable across recent releases, but runkubesealif a command behaves unexpectedly.kubeseal --help
tls.crttls.keytls.keytls.crt--raw/tmp/rmecho "" > /tmp/secret-temp.yamlNote: the public cert (/tls.crt) is not sensitive and does not need sanitizing — sealing it away only forces a re-fetch. Only overwrite files that contain plaintext secret values or the private key..pem
kubesealtls.crtcerts/# From the project root; typical names: tls.crt, sealed-secrets-cert.pem, sealed-secrets.crt
ls certs/
# If certs/ is not at the root, locate it:
find . -type d -name certs -not -path '*/.git/*'CERTCERT=certs/tls.crtcerts/certs/mcp__kubernetes__resources_listapiVersion: v1kind: SecretlabelSelector: sealedsecrets.bitnami.com/sealed-secrets-key=activenamespacekube-systemsealed-secretsactivemetadata.creationTimestampdata["tls.crt"]printf '%s' '<tls.crt base64 from the MCP response>' | base64 -d > /tmp/sealed-secrets-cert.pem
CERT=/tmp/sealed-secrets-cert.pemDANGER — that Secret also contains, the controller's private key. Read and use only thetls.keyfield. Never decode, print, echo, write, or committls.crt. Do not paste the raw MCP response anywhere.tls.key
illegal base64 data at input byte Nno key could decrypt secretopenssl x509 -in "$CERT" -noout -subject -dates || echo "NOT A VALID CERT — do not seal with this file"certs/kubeseal --cert "$CERT" -o yaml -f /dev/stdin > path/to/repo/sealedsecret.yaml <<'EOF'
apiVersion: v1
kind: Secret
metadata:
name: my-secret
namespace: my-namespace
type: Opaque
stringData:
key1: "value1"
key2: "value2"
EOF# Write secret to temp file (NEVER to repo)
cat > /tmp/my-secret.yaml <<'EOF'
apiVersion: v1
kind: Secret
metadata:
name: my-secret
namespace: my-namespace
type: Opaque
stringData:
key1: "value1"
key2: "value2"
EOF
# Seal and output YAML (sealed output is safe to write straight to the repo)
kubeseal --cert "$CERT" --format yaml -f /tmp/my-secret.yaml > path/to/repo/sealedsecret.yaml
# SANITIZE the plaintext temp file immediately (the sealed output is not sensitive)
echo "" > /tmp/my-secret.yamlThis is the path for a reseal request — the user asks to reseal an existing SealedSecret, usually because it fails to unseal (,illegal base64 data at input byte N) or because a credential changed. Resealing rewritesno key could decrypt secretin place; keepspec.encryptedData,metadata(labels, annotations,spec.template), name, and namespace byte-identical to the original unless the user asks otherwise, and match the surrounding files' conventions.type
--rawencryptedData--merge-intomcp__kubernetes__resources_getapiVersion: v1kind: Secretkubectl get secret <name> -n <namespace> -o jsonpath='{.data}'DANGER — do not interpolate secret values into YAML. A value containing,",:, leading spaces, or\nwill break the quoting and either corrupt the secret or make$fail withkubeseal. This is common with generated passwords and S3 keys. Never build YAML likeerror: no secrets found.password: "$EXISTING_PASS"
--raw--rawstrict--name--namespaceNS=my-namespace
NAME=my-secret
# Decode a value you want to PRESERVE (capture in variable, NEVER echo)
EXISTING_PASS=$(printf '%s' '<base64value>' | base64 -d)
# Re-seal the preserved value and the updated value straight into the repo file.
# printf '%s' avoids adding a trailing newline to the secret.
printf '%s' "$EXISTING_PASS" | kubeseal --cert "$CERT" \
--raw --namespace "$NS" --name "$NAME" --from-file=/dev/stdin
# -> paste the output under spec.encryptedData.password in path/to/repo/sealedsecret.yaml
printf '%s' 'new-value' | kubeseal --cert "$CERT" \
--raw --namespace "$NS" --name "$NAME" --from-file=/dev/stdin
# -> paste the output under spec.encryptedData.access-key-id--merge-intodata:stringData:cat > /tmp/updated-secret.yaml <<EOF
apiVersion: v1
kind: Secret
metadata:
name: $NAME
namespace: $NS
type: Opaque
data:
access-key-id: $(printf '%s' 'new-value' | base64 -w0)
password: $(printf '%s' "$EXISTING_PASS" | base64 -w0)
EOF
kubeseal --cert "$CERT" --format yaml -f /tmp/updated-secret.yaml > path/to/repo/sealedsecret.yaml
# SANITIZE the plaintext temp file
echo "" > /tmp/updated-secret.yamlcerts/openssl x509| Flag | Purpose |
|---|---|
| Public key file for encryption. Always pass this explicitly — omitting it makes kubeseal auto-detect the controller. Use a local file only, never a URL |
| Output format (default: json) |
| Input Secret YAML file (use |
| Namespace scope for the secret being sealed (not the controller's location) |
| Scoping of the sealed secret (default: |
| Merge sealed keys into existing SealedSecret file (in-place) |
| Encrypt a single raw value from |
| (with |
| Name of the sealed secret (required with |
| Re-encrypt an existing SealedSecret with the controller's latest key (needs cluster) |
| Verify the sealed secret decrypts — contacts the controller; requires cluster access |
| FORBIDDEN — do not use. Get the cert from |
| Namespace where the controller runs (default: |
| Controller name (default: |
| Disaster-recovery decrypt using |
strictnamespace-widecluster-wide# Seal only the keys you want to update
cat > /tmp/delta-secret.yaml <<'EOF'
apiVersion: v1
kind: Secret
metadata:
name: my-secret
namespace: my-namespace
type: Opaque
stringData:
new-key: "new-value"
EOF
# Merge into existing sealed secret
kubeseal --cert "$CERT" --merge-into path/to/repo/sealedsecret.yaml -f /tmp/delta-secret.yaml
# SANITIZE
echo "" > /tmp/delta-secret.yaml--merge-into--raw--rawspec.encryptedData.<key># strict scope (default): --name AND --namespace are REQUIRED and must match the target SealedSecret
printf '%s' 'p@ss"word:with$pecial' | kubeseal --cert "$CERT" \
--raw --namespace my-namespace --name my-secret --from-file=/dev/stdin
# namespace-wide: only --namespace required
printf '%s' 'value' | kubeseal --cert "$CERT" \
--raw --scope namespace-wide --namespace my-namespace --from-file=/dev/stdin
# cluster-wide: neither required
printf '%s' 'value' | kubeseal --cert "$CERT" \
--raw --scope cluster-wide --from-file=/dev/stdinprintf '%s'echo--raw--re-encryptkubeseal --re-encrypt -o yaml -f path/to/repo/sealedsecret.yaml > /tmp/reencrypted.yaml
cp /tmp/reencrypted.yaml path/to/repo/sealedsecret.yaml--re-encryptapiVersion: bitnami.com/v1alpha1
kind: SealedSecret
metadata:
name: my-secret
namespace: my-namespace
spec:
encryptedData:
key1: AgC...base64encrypteddata...==
key2: AgC...base64encrypteddata...==
template:
metadata:
name: my-secret
namespace: my-namespace
type: OpaqueapiVersion: v1
kind: Secret
metadata:
name: s3-credentials
namespace: my-namespace
type: Opaque
stringData:
access-key-id: "<access-key>"
secret-access-key: "<secret-key>"apiVersion: v1
kind: Secret
metadata:
name: db-credentials
namespace: my-namespace
type: Opaque
stringData:
username: "admin"
password: "<password>"apiVersion: v1
kind: Secret
metadata:
name: tls-cert
namespace: my-namespace
type: kubernetes.io/tls
stringData:
tls.crt: |
-----BEGIN CERTIFICATE-----
...
-----END CERTIFICATE-----
tls.key: |
-----BEGIN PRIVATE KEY-----
...
-----END PRIVATE KEY-----encryptedData--merge-intokubeseal --re-encryptstringDatadatastringDatadatastrictnamespace-widecluster-widegit filter-repokubeseal --fetch-cert > certs/sealed-secrets-cert.pemerror: cannot get sealed secret service: services "sealed-secrets-controller" not found.illegal base64 data at input byte Nno key could decrypt secret--fetch-certopenssl x509-----BEGIN CERTIFICATE-----certs/certs/tls.keytls.crt# --validate talks to the controller (no --cert needed); add --controller-namespace/--controller-name if non-default
kubeseal --validate -f path/to/repo/sealedsecret.yaml# Check the Secret exists and has the expected keys
kubectl get secret <name> -n <namespace> -o jsonpath='{.data}' | python3 -c "import sys,json; [print(k) for k in json.load(sys.stdin).keys()]"mcp__kubernetes__resources_getcerts/--fetch-certkubectlopenssl x509set +o historytls.key