Kubernetes Secret: Create, Retrieve and Manage k8s Secret

If your task is to securely configure sensitive data like passwords, tokens, or API keys inside your Kubernetes cluster, then this guide is for you.

Kubernetes Secret is the built-in solution designed exactly for that — to keep confidential information safe and separate from your application code.

In the next sections, you’ll learn what Secrets are, how they work, and how to create/add and manage them effectively in real-world deployments.

What Secrets Are?

In Kubernetes, a Secret is an object used to store and manage sensitive information such as passwords, SSH keys, OAuth tokens, or database credentials. Unlike ConfigMaps—which handle non-sensitive configuration data—Secrets ensure that confidential values are encoded, protected, and separated from application code.

By using Secrets, you avoid hardcoding private data inside Pod definitions or container images. Kubernetes can inject these Secrets into Pods as environment variables or mounted files, keeping your cluster both flexible and secure.


How Kubernetes Secrets Work?

Kubernetes Secrets work by storing sensitive data in a dedicated API object of type Secret, which can then be securely referenced by Pods or other resources. Instead of embedding credentials directly in your Pod specs or container images, you create a Secret and let Kubernetes inject it when needed.

Here’s the basic workflow:

  1. Create the Secret – You can create it from a literal value, file, or YAML manifest using kubectl create secret.
  2. Store in etcd – Kubernetes stores the Secret data (base64-encoded) in its internal key-value store, etcd. With encryption at rest enabled, this data can be encrypted for additional protection.
  3. Reference in Pods – Pods can access the Secret through:
    • Environment variables, or
    • Mounted volumes (as files inside the container).
  4. Access Control – Only users or service accounts with the right RBAC permissions can view or modify Secrets.
  5. Automatic updates – When a Secret changes, Kubernetes can automatically update the Pods that use it (if mounted as a volume).

In short, k8s Secrets separate sensitive data from your app code, control who can access it, and inject it securely into workloads, ensuring both flexibility and confidentiality in your deployments.


Different Ways to Create k8s Secrets

There’s no single way to create a Secret in Kubernetes — it depends on where your sensitive data comes from and how you manage it. Kubernetes gives you multiple options to define and store Secrets, whether that’s directly from the CLI, through YAML or JSON manifests, from environment files, or even via external secret managers like Vault or AWS Secrets Manager.

Next, we’ll explore each approach step-by-step, with practical examples to help you choose the right method for your setup.

Create Kubernetes Secret from a File

When your sensitive data (like API keys or credentials) already exists in a file, you can directly create a Secret from it:

kubectl create secret generic api-secret \
  --from-file=./api-key.txt

Here, the file name becomes the key, and its content becomes the value inside the Secret.
This is ideal when credentials are managed as separate files or mounted during build processes.

From Literal Values

If you just need a quick Secret without external files:

kubectl create secret generic db-secret \
  --from-literal=username=admin \
  --from-literal=password=MyP@ssw0rd

This creates a Secret instantly from key-value pairs provided in the command line — perfect for testing or temporary setups.

From a YAML File

Declarative management is the Kubernetes way.
You can define your Secret as a YAML manifest and apply it:

apiVersion: v1
kind: Secret
metadata:
  name: app-secret
type: Opaque
data:
  username: YWRtaW4=
  password: TXlQQHNzdzByZA==

Apply it using:

kubectl apply -f app-secret.yaml

This approach is best for GitOps, CI/CD pipelines, or when version-controlling your cluster configuration.

From a JSON File

For teams using automation tools or APIs that output JSON:

kubectl create -f secret.json

You can also convert YAML to JSON or vice versa depending on your tooling.
Functionally, both work the same — it’s just a matter of file format preference.

From an Environment File

Kubernetes automatically parses each line of the .env file into a key-value pair inside the Secret.

kubectl create secret generic env-secret \
  --from-env-file=.env

From Another Secret

This copies the data from one Secret and creates a new one — helpful for multi-environment setups (e.g., staging → production).

kubectl get secret old-secret -o yaml | \
  sed 's/name: old-secret/name: new-secret/' | \
  kubectl apply -f -

From a ConfigMap

Sometimes, you might need to convert non-sensitive configuration (ConfigMap) into a Secret:

kubectl get configmap app-config -o jsonpath='{.data}' | \
  kubectl create secret generic configmap-secret --from-literal=data="$(cat)"

This is useful when you later decide certain config values should be handled as sensitive data.

From One Namespace to Another

Secrets are namespace-scoped, so to reuse them across namespaces:

kubectl get secret db-secret -n dev -o yaml | \
  sed 's/namespace: dev/namespace: prod/' | \
  kubectl apply -n prod -f -

From a PEM File (Certificates)

When storing TLS certificates or private keys:

kubectl create secret tls tls-secret \
  --cert=server.crt \
  --key=server.key

This automatically creates a Secret of type kubernetes.io/tls, ideal for Ingress and SSL termination.

From a JKS File (Java KeyStore)

For Java-based apps that use keystores:

kubectl create secret generic jks-secret \
  --from-file=keystore.jks

Mount this Secret as a file in your Pod so your Java app can securely access it.

From HashiCorp Vault

For production-grade secret management, integrate Vault using the External Secrets Operator or CSI Driver.
Example manifest (using External Secrets Operator):

apiVersion: external-secrets.io/v1
kind: ExternalSecret
metadata:
  name: vault-secret
spec:
  secretStoreRef:
    name: vault-backend
    kind: SecretStore
  target:
    name: my-app-secret
  data:
    - secretKey: db-password
      remoteRef:
        key: database/credentials
        property: password

From Azure Key Vault

If you’re on Azure, use the Secrets Store CSI Driver:

apiVersion: secrets-store.csi.x-k8s.io/v1
kind: SecretProviderClass
metadata:
  name: azure-keyvault-provider
spec:
  provider: azure
  parameters:
    keyvaultName: my-keyvault
    objects: |
      array:
        - objectName: app-secret
          objectType: secret

This dynamically mounts Azure Key Vault secrets directly into your Pods without manually creating a Kubernetes Secret.

From Command Line (Direct CLI)

This allows mixing literal and file-based inputs in a single command — handy for quick testing or automation scripts.

kubectl create secret generic my-secret \
  --from-literal=apiKey=123456 \
  --from-file=config.json=./config.json

Using Kubernetes Secrets in Pods

Once you’ve created a Secret, the next step is to make it available to your Pods. Kubernetes allows you to mount Secrets in two primary ways — as environment variables or as files inside a container.

Each approach has its own advantages:

  • Environment variables are simple and best for lightweight use cases.
  • Mounted files provide better control and are ideal when apps expect credentials in file form (e.g., certificates or config files).

Next, we’ll see how to mount Secrets using both methods, along with examples for each scenario.

Mount Secret as a Volume

apiVersion: v1
kind: Pod
metadata:
  name: secret-vol-pod
spec:
  containers:
    - name: app
      image: nginx
      volumeMounts:
        - name: secret-vol
          mountPath: "/etc/secret"
  volumes:
    - name: secret-vol
      secret:
        secretName: app-secret

In this configuration, the Secret named app-secret is mounted as a volume inside the container at /etc/secret.
Each key in the Secret becomes a separate file, and its corresponding value is the file’s content.
For example, if your Secret has keys like username and password, you’ll get two files:
/etc/secret/username and /etc/secret/password.

This method is preferred for TLS certificates, config files, or tokens that your app reads directly from the filesystem.

Mount Secret as Environment Variables

apiVersion: v1
kind: Pod
metadata:
  name: secret-env-pod
spec:
  containers:
    - name: app
      image: nginx
      env:
        - name: DB_USER
          valueFrom:
            secretKeyRef:
              name: db-secret
              key: username
        - name: DB_PASS
          valueFrom:
            secretKeyRef:
              name: db-secret
              key: password

Here, two environment variables — DB_USER and DB_PASS — are populated from the Secret named db-secret.
This makes them accessible to the containerized app using normal environment variable syntax (e.g., process.env.DB_USER in Node.js).

While it’s simple, this method is less secure because environment variables can appear in logs, crash dumps, or monitoring tools.
Use it when speed and simplicity matter more than strict security boundaries.

Mount Secret Using subPath (Single File Mount)

apiVersion: v1
kind: Pod
metadata:
  name: subpath-secret-pod
spec:
  containers:
    - name: app
      image: nginx
      volumeMounts:
        - name: secret-vol
          mountPath: "/etc/app/config.json"
          subPath: "config.json"
  volumes:
    - name: secret-vol
      secret:
        secretName: app-secret

The subPath property lets you mount only one key (in this case, config.json) from the Secret instead of the whole directory.
This is useful when an app expects a single file, like a JSON config, at a fixed path.

It also helps prevent exposing unnecessary Secret keys in the container’s file system.

Mount Secret for Non-Root User

apiVersion: v1
kind: Pod
metadata:
  name: nonroot-secret-pod
spec:
  securityContext:
    runAsUser: 1001
    runAsGroup: 1001
  containers:
    - name: app
      image: nginx
      volumeMounts:
        - name: secret-vol
          mountPath: "/etc/creds"
  volumes:
    - name: secret-vol
      secret:
        secretName: creds-secret

This Pod runs as user 1001, not as root (0).
The mounted Secret (creds-secret) is still accessible at /etc/creds, but the container process has limited privileges.

This reduces security risks, such as accidental overwrites or privilege escalation.
It’s a best practice in production, especially for workloads handling sensitive credentials.

Mount Secret with Custom File Ownership and Permissions

apiVersion: v1
kind: Pod
metadata:
  name: user-secret-pod
spec:
  containers:
    - name: app
      image: nginx
      volumeMounts:
        - name: secret-vol
          mountPath: "/etc/custom-creds"
  volumes:
    - name: secret-vol
      secret:
        secretName: user-secret
        defaultMode: 0640
  securityContext:
    fsGroup: 2000

Here, the defaultMode sets file permissions (0640), and the fsGroup ensures all Secret files belong to group 2000.
This setup ensures only authorized users inside the container can read the Secrets, protecting them from unauthorized access.

It’s ideal in multi-user Pods or when certain processes need restricted access.


Summary

Kubernetes Secrets provide a secure and flexible way to manage sensitive information like passwords, tokens, and certificates without hardcoding them into your application code or container images. By storing confidential data separately, Secrets help you maintain a clear boundary between configuration and logic — a key principle in secure DevOps practices.

You can create Secrets in several ways — from files, literal values, YAML manifests, or even external secret managers like HashiCorp Vault or Azure Key Vault — depending on your workflow and security policies. This flexibility allows seamless integration across environments, CI/CD pipelines, and automation tools.

Once created (added), Secrets can be mounted into Pods either as files (via volumes) or as environment variables, with advanced options like subPath, non-root access, and custom permissions. This ensures your workloads can securely access only the data they need — keeping your K8s deployments both secure and maintainable.

Author

Sharukhan is the founder of Tecktol. He has worked as a software engineer specializing in full-stack web development.