Table of Contents
Types of Secrets in OpenShift
In OpenShift, Secret objects are Kubernetes secrets with some OpenShift-specific integrations and usage patterns. At a high level they all store key–value data, but are used for different purposes.
Opaque (generic) secrets
- Type:
Opaque - Use for: Arbitrary key–value data that doesn’t fit a more specific type, such as application API keys or custom tokens.
- Created from:
- Literal values
- Files
--from-env-filestyle configuration
Example:
oc create secret generic app-credentials \
--from-literal=api-key='my-api-key' \
--from-literal=api-secret='my-secret'
Opaque is often the default when no type is specified.
Docker registry (image pull) secrets
- Types:
kubernetes.io/dockerconfigjsonkubernetes.io/dockercfg(legacy)- Use for: Authenticating to container registries (e.g. private Quay, Docker Hub, internal registries).
- Integrated with:
- ServiceAccounts’
imagePullSecrets - Cluster-wide or project-level image pull configuration
Example (create from Docker credentials):
oc create secret docker-registry pull-secret \
--docker-server=quay.io \
--docker-username=myuser \
--docker-password='mypassword' \
--docker-email=myuser@example.comTLS secrets
- Type:
kubernetes.io/tls - Use for: Storing X.509 certificates and private keys, typically used by:
- Routes (HTTPS/TLS termination)
- Ingress controllers
- Applications that need server certificates
Required keys:
tls.crt– certificate (and chain, if needed)tls.key– private key
Example:
oc create secret tls my-tls-secret \
--cert=server.crt \
--key=server.keyRoutes can reference this secret for edge or re-encrypt termination.
Basic authentication secrets
- Type:
kubernetes.io/basic-auth - Use for: Username/password pairs, often for external services.
- Standard keys:
usernamepassword
Example:
oc create secret generic db-basic-auth \
--type=kubernetes.io/basic-auth \
--from-literal=username=dbuser \
--from-literal=password='S3cureP@ss'SSH auth secrets
- Type:
kubernetes.io/ssh-auth - Use for: Private SSH keys (for Git over SSH, or other SSH-based integrations).
- Key:
ssh-privatekey
Example:
oc create secret generic git-ssh-key \
--type=kubernetes.io/ssh-auth \
--from-file=ssh-privatekey=id_rsaService account tokens (service-account-token)
- Type:
kubernetes.io/service-account-token - Automatically managed by Kubernetes/OpenShift.
- Use for: Credentials that Pods use to authenticate to the API server.
- You normally do not create these manually; they are bound to a
ServiceAccount.
Creating Secrets in OpenShift
OpenShift provides multiple ways to create secrets, via CLI, web console, and manifests.
Using `oc create secret`
The CLI provides subcommands for common secret types:
- Generic / Opaque:
oc create secret generic app-secret \
--from-literal=token='12345' \
--from-file=config.yaml=./config.yaml- Docker registry:
oc create secret docker-registry registry-creds \
--docker-server=registry.example.com \
--docker-username=user \
--docker-password='pass' \
--docker-email=user@example.com- TLS:
oc create secret tls tls-cert \
--cert=./tls.crt \
--key=./tls.keyFrom environment files
You can create a secret from a file in KEY=VALUE format:
cat > secret.env <<EOF
DB_USER=myuser
DB_PASS=mypass
EOF
oc create secret generic db-credentials \
--from-env-file=secret.envUsing YAML manifests
Secrets are Kubernetes API objects. They can be declared in YAML and applied with oc apply -f.
Example Opaque secret:
apiVersion: v1
kind: Secret
metadata:
name: app-credentials
type: Opaque
data:
api-key: bXktYXBpLWtleQ==
api-secret: bXktc2VjcmV0Key points:
datavalues must be base64-encoded.stringData(write-only) can be used for clear text; the API server will encode todata.
Example using stringData:
apiVersion: v1
kind: Secret
metadata:
name: app-credentials
type: Opaque
stringData:
api-key: my-api-key
api-secret: my-secretUsing the OpenShift web console
Typical workflow:
- Navigate to Workloads → Secrets in the developer or admin perspective.
- Click Create and choose the secret type (e.g., Key/value, TLS, Image pull secret).
- Fill in the key/value pairs or upload files.
- Select the Project/Namespace where the secret will live.
- Save and then reference the secret from Deployments, BuildConfigs, or Routes.
The console guides you through type-specific fields (e.g., server URL for registry secrets, TLS cert/key upload, etc.).
Using Secrets in Pods
Once a secret exists, it must be explicitly referenced by workloads. Common integration patterns are environment variables, mounted volumes, and image pull secrets.
Exposing secrets as environment variables
Useful for small pieces of configuration (e.g. credentials) read by the application at startup.
From a single secret key
YAML snippet:
env:
- name: DB_USER
valueFrom:
secretKeyRef:
name: db-credentials
key: DB_USER
- name: DB_PASS
valueFrom:
secretKeyRef:
name: db-credentials
key: DB_PASS
Using oc set env:
oc set env deployment/myapp \
DB_USER_SECRET_FROM=secretKeyRef:name=db-credentials,key=DB_USERFrom all keys in a secret
Exports every key in a secret as an environment variable with the same name:
envFrom:
- secretRef:
name: app-credentialsMounting secrets as volumes
This is the recommended approach for files (certificates, SSH keys, config files, etc.) and for apps that periodically reload secrets.
YAML snippet:
volumes:
- name: certs
secret:
secretName: my-tls-secret
containers:
- name: web
image: myimage
volumeMounts:
- name: certs
mountPath: /etc/tls
readOnly: true
Each key in the secret will appear as a file in the mount directory (/etc/tls/tls.crt, /etc/tls/tls.key, etc. for TLS secrets).
Mapping secret keys to specific file paths
You can customize file names and mount only selected keys:
volumes:
- name: ssh-key
secret:
secretName: git-ssh-key
items:
- key: ssh-privatekey
path: id_rsa
containers:
- name: builder
image: my-builder
volumeMounts:
- name: ssh-key
mountPath: /root/.ssh
readOnly: trueImage pull secrets
When pulling images from private registries, reference a Docker registry secret so the kubelet can authenticate.
On a ServiceAccount
Attach the secret to a ServiceAccount used by Pods:
oc secrets link my-serviceaccount registry-creds --for=pullOr directly in YAML:
apiVersion: v1
kind: ServiceAccount
metadata:
name: my-serviceaccount
imagePullSecrets:
- name: registry-credsAny Pod using this ServiceAccount will automatically use the pull secret.
On a Pod/Deployment
You can also define imagePullSecrets directly:
spec:
imagePullSecrets:
- name: registry-creds
In OpenShift, the project’s default builder and default ServiceAccounts often already reference secrets for the internal registry.
Secrets in Common OpenShift Workflows
With Routes and TLS termination
Routes can reference TLS secrets for HTTPS:
- For edge or re-encrypt termination, you usually:
- Create a TLS secret with
tls.crtandtls.key. - Reference it in the
Routeunderspec.tls.
Example:
apiVersion: route.openshift.io/v1
kind: Route
metadata:
name: my-secure-route
spec:
host: app.example.com
to:
kind: Service
name: my-service
tls:
termination: edge
key: |
-----BEGIN PRIVATE KEY-----
...
certificate: |
-----BEGIN CERTIFICATE-----
...Alternatively, the console allows you to select a pre-created TLS secret.
With Builds and Source-to-Image (S2I)
Build configurations often need secrets for:
- Pulling base images from private registries.
- Accessing private Git repositories.
Typical patterns:
- Use
sourceSecretin aBuildConfigfor Git SSH keys:
spec:
source:
type: Git
git:
uri: git@github.com:org/repo.git
sourceSecret:
name: git-ssh-key- Use
pullSecretfor private image registries:
spec:
strategy:
sourceStrategy:
from:
kind: ImageStreamTag
name: 'my-base-image:latest'
pullSecret:
name: registry-credsWith Deployments and StatefulSets
When defining workloads:
- Reference secrets for:
- Database credentials
- API tokens
- File-based certificates/keys
- Use
envFromorvolumeMountsaccordingly.
Operations teams often standardize secret names and keys across projects to keep manifests portable (e.g., always DB_USER, DB_PASSWORD, SSL_CERT, SSL_KEY).
Namespaces, Access Control, and Secrets
Secrets are namespaced resources:
- A secret in one project/namespace is not visible in another.
- Access is controlled via RBAC (covered elsewhere), but for secrets:
get,list, and especiallyviewaccess can expose sensitive data.- It’s common to restrict who can
getoreditsecrets.
Impact:
- Separate applications with different trust boundaries should be in different projects with separate secrets.
- Shared secrets across projects must be deliberately duplicated or managed by an external secrets manager.
When using oc:
oc get secretshows metadata only.oc get secret my-secret -o yamlexposes encoded data.oc extract secret/my-secretcan write secret values to local files.
Treat local copies with the same care as the original secret.
Lifecycle and Rotation of Secrets
Updating a secret
Updating secret data can be done via:
oc edit secret my-secretoc apply -f updated-secret.yamloc create secret ... --dry-run=client -o yaml | oc apply -f -
By default, Pods will not automatically restart when the secret changes. How updates are propagated depends on how you use the secret:
- As environment variables:
- Values are fixed at Pod start.
- You must roll out a new Pod (e.g.,
oc rollout restart deployment/myapp) to pick up changes. - As a mounted volume:
- The Secret volume is updated by the kubelet.
- Many applications still need a restart or reload to apply new values.
- Some applications watch files for changes and reload automatically.
Secret rotation strategies
Common patterns:
- Use short-lived credentials where possible (e.g., tokens with limited TTL).
- Schedule rotations (manually or automated) for:
- Certificates before expiry.
- Passwords and keys according to policy.
- Combine secret updates with:
- Rolling Deployment updates.
- Health checks to ensure new credentials work.
In OpenShift, Operators and controllers often manage their own secrets and rotation (for example, for platform components); application teams typically manage application-level secrets.
Security Considerations Specific to Secrets
Secrets are not a complete security solution by themselves; they are one building block.
Key points in OpenShift:
- Secrets are only base64-encoded at rest in the etcd data store. Real confidentiality at rest requires:
- etcd encryption (cluster-level feature).
- Protecting etcd and control plane access.
- Secret environment variables are visible in:
- Process environments inside the container.
- Some debugging tools, if not restricted.
- Mounted secret volumes:
- Are readable by the container user according to volume permissions.
- Should be mounted
readOnly: truewhere possible.
Additional practices:
- Avoid placing secret values in:
- Logs
- Labels, annotations, or names
- Application responses or error messages
- Prefer:
- Narrow RBAC rules for
secretsresource. - Different secrets for different components, even if values initially match.
- Using
stringDatain manifests only when necessary, and keeping those manifests secure.
Working with Secrets in `oc`
Some useful CLI commands in day-to-day work:
- List secrets:
oc get secrets- View a specific secret (encoded):
oc get secret app-credentials -o yaml- Decode a specific key:
oc get secret app-credentials -o jsonpath='{.data.api-key}' | base64 -d- Extract all secret data to files:
oc extract secret/app-credentials --to=-
# or to a directory
oc extract secret/app-credentials --to=./secrets- Patch a secret (e.g., change a key):
oc patch secret app-credentials \
-p='{"stringData":{"api-key":"new-api-key"}}'Use these tools carefully and avoid leaving sensitive data in shell history or shared terminals.