# kubeseal: Encrypt a Secret into a SealedSecret

> kubeseal encrypts a Kubernetes Secret into a SealedSecret safe to commit. Reference for --format, --scope, --controller-name, and the encryption errors in CI.

Source: https://latchkey.dev/learn/command-reference/kubeseal-seal  
Updated: 2026-06-30

kubeseal encrypts a regular Kubernetes Secret into a SealedSecret that only the cluster controller can decrypt, so it is safe to commit to Git.

Sealed Secrets let you keep secrets in a GitOps repo. kubeseal takes a plain Secret and produces an encrypted SealedSecret resource.

## What it does

kubeseal reads a Secret manifest, fetches the sealed-secrets controller public certificate, and encrypts each value with it, emitting a SealedSecret. Only the controller in that cluster holds the private key, so the output is safe to store in Git. By default sealing is scoped to the Secret's name and namespace.

## Common usage

```Terminal
kubectl create secret generic db \
  --from-literal=password="$DB_PASSWORD" \
  --dry-run=client -o yaml \
  | kubeseal --format yaml > sealedsecret.yaml
```

## Options

| Flag | What it does |
| --- | --- |
| --format yaml|json | Output format of the SealedSecret |
| --scope strict|namespace-wide|cluster-wide | How tightly the seal is bound to name/namespace |
| --controller-name <name> | Controller deployment name (default sealed-secrets-controller) |
| --controller-namespace <ns> | Namespace of the controller (default kube-system) |
| --cert <file> | Use an offline public cert instead of querying the cluster |

## In CI

A SealedSecret sealed with the default strict scope only decrypts when applied under the exact name and namespace it was sealed for; renaming it later breaks decryption. For a secret reused across namespaces, seal with --scope cluster-wide so the controller does not enforce the namespace.

## Common errors in CI

"error: cannot fetch certificate: ... the server could not find the requested resource" means the --controller-name or --controller-namespace is wrong. "cannot get sealed secret service" means kubeseal cannot reach the controller; use --cert with a fetched certificate for offline sealing. Sealing succeeds but the controller logs "no key could decrypt secret" when the SealedSecret's name/namespace differ from where it was sealed.

## Using this in CI

A runner has no kubeconfig, no cached context, and no interactive auth. Every kubectl invocation in CI needs the context supplied explicitly, and most confusing CI failures here are the command running against the wrong cluster or no cluster at all.

```Terminal
# never rely on the ambient context on a runner
kubectl --context "$KUBE_CONTEXT" -n "$NAMESPACE" get pods

# confirm what you are actually connected to before mutating anything
kubectl config current-context
kubectl cluster-info

# fail fast instead of hanging on an unreachable API server
kubectl --request-timeout=30s get nodes
```

> Always set `--request-timeout` in CI. Without it an unreachable API server hangs until the job times out, which turns a thirty-second failure into a twenty-minute one.

## FAQ

### kubeseal: Encrypt a Secret into a SealedSecret?

Sealed Secrets let you keep secrets in a GitOps repo. kubeseal takes a plain Secret and produces an encrypted SealedSecret resource.

### What it does?

kubeseal reads a Secret manifest, fetches the sealed-secrets controller public certificate, and encrypts each value with it, emitting a SealedSecret. Only the controller in that cluster holds the private key, so the output is safe to store in Git. By default sealing is scoped to the Secret's name and namespace.

### In CI?

A SealedSecret sealed with the default strict scope only decrypts when applied under the exact name and namespace it was sealed for; renaming it later breaks decryption. For a secret reused across namespaces, seal with --scope cluster-wide so the controller does not enforce the namespace.

### Common errors in CI?

"error: cannot fetch certificate: ... the server could not find the requested resource" means the --controller-name or --controller-namespace is wrong. "cannot get sealed secret service" means kubeseal cannot reach the controller; use --cert with a fetched certificate for offline sealing.

---

Latchkey runs CI/CD that repairs its own failures. Agent entry points: https://latchkey.dev/agent.txt, https://latchkey.dev/openapi.json, https://latchkey.dev/llms.txt
