# kubectl create secret: Usage, Options & Common CI Errors

> kubectl create secret builds generic, docker-registry, and TLS Secrets. The apply-pipe idempotency idiom, base64 confusion, and registry-auth errors in CI.

Source: https://latchkey.dev/learn/command-reference/kubectl-create-secret  
Updated: 2026-06-25

Create generic, registry-auth, or TLS Secrets straight from CI.

kubectl create secret builds a Secret from flags in three flavours: generic (literals/files), docker-registry (image pull auth), and tls (a cert/key pair). It is how pipelines wire credentials into a cluster.

## What it does

create secret generic takes --from-literal / --from-file. create secret docker-registry takes --docker-server/--docker-username/--docker-password and produces a .dockerconfigjson Secret for imagePullSecrets. create secret tls takes --cert and --key. kubectl base64-encodes the values for you - pass plaintext, not pre-encoded data.

## Common usage

```Terminal
kubectl create secret generic db --from-literal=password=s3cr3t
kubectl create secret tls web-tls --cert=tls.crt --key=tls.key
kubectl create secret docker-registry regcred \
  --docker-server=ghcr.io --docker-username=ci --docker-password=${TOKEN}
kubectl create secret generic db --from-literal=password=x \
  --dry-run=client -o yaml | kubectl apply -f -
```

## Common errors in CI

The number-one mistake is double base64: kubectl already encodes the value, so passing an already-base64 string yields a garbled credential that fails opaquely at runtime - always pass plaintext. "AlreadyExists" on re-run needs the generate-then-apply pipe shown above. For a docker-registry secret, an ImagePullBackOff with "401 Unauthorized" after creating it means the pod's imagePullSecrets does not reference the Secret, or the token is wrong/expired - the Secret existing is necessary but not sufficient. Secrets are base64, not encrypted; never echo them into CI logs.

## 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

### kubectl create secret: Usage, Options & Common CI Errors?

kubectl create secret builds a Secret from flags in three flavours: generic (literals/files), docker-registry (image pull auth), and tls (a cert/key pair). It is how pipelines wire credentials into a cluster.

### What it does?

create secret generic takes --from-literal / --from-file. create secret docker-registry takes --docker-server/--docker-username/--docker-password and produces a .dockerconfigjson Secret for imagePullSecrets. create secret tls takes --cert and --key. kubectl base64-encodes the values for you - pass plaintext, not pre-encoded data.

### Common errors in CI?

The number-one mistake is double base64: kubectl already encodes the value, so passing an already-base64 string yields a garbled credential that fails opaquely at runtime - always pass plaintext. "AlreadyExists" on re-run needs the generate-then-apply pipe shown above.

---

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
