Skaffold’s built-in secrets management is less about generating secrets and more about seamlessly injecting existing secrets into your development containers, making your local development loop feel exactly like your production environment.

Let’s see it in action. Imagine you have a Kubernetes Secret object named my-db-credentials in your development namespace, containing keys username and password. You want your local Go application, running in a dev container managed by Skaffold, to access these.

Here’s a snippet from a skaffold.yaml:

apiVersion: skaffold/v2
kind: Config
build:
  artifacts:
    my-app:
      docker:
        dockerfile: Dockerfile
deploy:
  kubectl:
    manifests:
      - k8s/deployment.yaml
profiles:
  - name: dev
    activation:
      - kubeContext: docker-desktop
    manifests:
      - k8s/development-deployment.yaml
    deploy:
      kubectl:
        flags:
          apply: ["--namespace=development"]
    dev:
      containers:
        - name: my-app
          ports:
            - containerPort: 8080
          sync:
            manual: {}
          # This is the magic:
          secrets:
            - secretName: my-db-credentials
              paths:
                - key: username
                  path: app/config/db_user.txt
                - key: password
                  path: app/config/db_pass.txt

When you run skaffold dev --profile dev, Skaffold will:

  1. Detect the dev profile: It sees you’re targeting the docker-desktop context and activates this profile.

  2. Apply development manifests: It uses k8s/development-deployment.yaml and applies it to the development namespace. This deployment must include a reference to the my-db-credentials secret, either as a volume mount or environment variables. For example, your development-deployment.yaml might look like this:

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: my-app-deployment
      namespace: development
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: my-app
      template:
        metadata:
          labels:
            app: my-app
        spec:
          containers:
            - name: my-app
              image: my-app:latest # Skaffold will manage this image
              ports:
                - containerPort: 8080
              volumeMounts:
                - name: credentials-volume
                  mountPath: /etc/secrets # Or any path your app expects
          volumes:
            - name: credentials-volume
              secret:
                secretName: my-db-credentials
    
  3. Enter Dev Mode: For your my-app container, Skaffold recognizes the secrets configuration.

  4. Inject Secrets: Skaffold doesn’t create the secret itself. It assumes the secret my-db-credentials already exists in the development namespace. When Skaffold starts your dev container, it ensures that the secret data defined in my-db-credentials is available within the container at the specified paths. In our example, the username from the secret will be written to /app/config/db_user.txt inside the container, and the password to /app/config/db_pass.txt.

The core problem this solves is consistency between your local development environment and your deployed environments. Developers often struggle with local setups that don’t mirror production, leading to "it works on my machine" issues. By allowing Skaffold to manage the injection of pre-existing secrets (which you’d typically manage via CI/CD or GitOps in production), you reduce this drift. Your application code can read secrets from standard locations (files or environment variables) without needing special logic for local development.

The secrets block in skaffold.yaml is a declarative way to tell Skaffold: "When you run this container in dev mode, make sure these specific keys from this specific Kubernetes Secret are available at these specific file paths inside the container." Skaffold then orchestrates the mounting or copying of this data. It’s crucial to understand that Skaffold doesn’t create the Kubernetes Secret resource itself; it relies on that resource existing in the cluster. Your k8s/development-deployment.yaml (or similar) is responsible for telling Kubernetes how to expose that secret to the pod (e.g., via volume mounts as shown above). Skaffold then uses this information to ensure the data lands correctly in the dev container.

A common misconception is that Skaffold will create the Secret object in Kubernetes. It will not. It is designed to work with secrets that are already provisioned in your cluster. If the Secret object my-db-credentials doesn’t exist in the development namespace, or if it’s missing the username or password keys, your container will likely start but won’t have the expected credentials, leading to application errors.

The path directive in the secrets configuration is not just for mounting; Skaffold will actually write the secret data to these files within the dev container’s filesystem if they aren’t already mounted by Kubernetes. This is particularly useful if your Kubernetes deployment manifest doesn’t explicitly configure a volume mount for the secret, but your application expects the secret data to be in a file. Skaffold can bridge that gap for you during development.

The next step you’ll encounter is managing how these secrets are created in your cluster for different environments, which often involves tools like Helm, Kustomize, or dedicated secrets management solutions like HashiCorp Vault or AWS Secrets Manager, integrated into your CI/CD pipeline.

Want structured learning?

Take the full Skaffold course →