Projected Volumes

This document describes projected volumes in Kubernetes. Familiarity with volumes is suggested.

Introduction

A projected volume maps several existing volume sources into the same directory.

Currently, the following types of volume sources can be projected:

All sources are required to be in the same namespace as the Pod. For more details, see the all-in-one volume design document.

Example configuration with a secret, a downwardAPI, and a configMap

apiVersion: v1 kind: Pod metadata:   name: volume-test spec:   containers:   - name: container-test     image: busybox:1.28     command: ["sleep", "3600"]     volumeMounts:     - name: all-in-one       mountPath: "/projected-volume"       readOnly: true   volumes:   - name: all-in-one     projected:       sources:       - secret:           name: mysecret           items:             - key: username               path: my-group/my-username       - downwardAPI:           items:             - path: "labels"               fieldRef:                 fieldPath: metadata.labels             - path: "cpu_limit"               resourceFieldRef:                 containerName: container-test                 resource: limits.cpu       - configMap:           name: myconfigmap           items:             - key: config               path: my-group/my-config 

Example configuration: secrets with a non-default permission mode set

apiVersion: v1 kind: Pod metadata:   name: volume-test spec:   containers:   - name: container-test     image: busybox:1.28     command: ["sleep", "3600"]     volumeMounts:     - name: all-in-one       mountPath: "/projected-volume"       readOnly: true   volumes:   - name: all-in-one     projected:       sources:       - secret:           name: mysecret           items:             - key: username               path: my-group/my-username       - secret:           name: mysecret2           items:             - key: password               path: my-group/my-password               mode: 511 

Each projected volume source is listed in the spec under sources. The parameters are nearly the same with two exceptions:

  • For secrets, the secretName field has been changed to name to be consistent with ConfigMap naming.
  • The defaultMode can only be specified at the projected level and not for each volume source. However, as illustrated above, you can explicitly set the mode for each individual projection.

serviceAccountToken projected volumes

You can inject the token for the current service account into a Pod at a specified path. For example:

apiVersion: v1 kind: Pod metadata:   name: sa-token-test spec:   containers:   - name: container-test     image: busybox:1.28     command: ["sleep", "3600"]     volumeMounts:     - name: token-vol       mountPath: "/service-account"       readOnly: true   serviceAccountName: default   volumes:   - name: token-vol     projected:       sources:       - serviceAccountToken:           audience: api           expirationSeconds: 3600           path: token 

The example Pod has a projected volume containing the injected service account token. Containers in this Pod can use that token to access the Kubernetes API server, authenticating with the identity of the pod's ServiceAccount. The audience field contains the intended audience of the token. A recipient of the token must identify itself with an identifier specified in the audience of the token, and otherwise should reject the token. This field is optional and it defaults to the identifier of the API server.

The expirationSeconds is the expected duration of validity of the service account token. It defaults to 1 hour and must be at least 10 minutes (600 seconds). An administrator can also limit its maximum value by specifying the --service-account-max-token-expiration option for the API server. The path field specifies a relative path to the mount point of the projected volume.

clusterTrustBundle projected volumes

FEATURE STATE: Kubernetes v1.33 [beta] (enabled by default: false)

The clusterTrustBundle projected volume source injects the contents of one or more ClusterTrustBundle objects as an automatically-updating file in the container filesystem.

ClusterTrustBundles can be selected either by name or by signer name.

To select by name, use the name field to designate a single ClusterTrustBundle object.

To select by signer name, use the signerName field (and optionally the labelSelector field) to designate a set of ClusterTrustBundle objects that use the given signer name. If labelSelector is not present, then all ClusterTrustBundles for that signer are selected.

The kubelet deduplicates the certificates in the selected ClusterTrustBundle objects, normalizes the PEM representations (discarding comments and headers), reorders the certificates, and writes them into the file named by path. As the set of selected ClusterTrustBundles or their content changes, kubelet keeps the file up-to-date.

By default, the kubelet will prevent the pod from starting if the named ClusterTrustBundle is not found, or if signerName / labelSelector do not match any ClusterTrustBundles. If this behavior is not what you want, then set the optional field to true, and the pod will start up with an empty file at path.

apiVersion: v1 kind: Pod metadata:   name: sa-ctb-name-test spec:   containers:   - name: container-test     image: busybox     command: ["sleep", "3600"]     volumeMounts:     - name: token-vol       mountPath: "/root-certificates"       readOnly: true   serviceAccountName: default   volumes:   - name: token-vol     projected:       sources:       - clusterTrustBundle:           name: example           path: example-roots.pem       - clusterTrustBundle:           signerName: "example.com/mysigner"           labelSelector:             matchLabels:               version: live           path: mysigner-roots.pem           optional: true 

podCertificate projected volumes

FEATURE STATE: Kubernetes v1.34 [alpha] (enabled by default: false)

The podCertificate projected volumes source securely provisions a private key and X.509 certificate chain for pod to use as client or server credentials. Kubelet will then handle refreshing the private key and certificate chain when they get close to expiration. The application just has to make sure that it reloads the file promptly when it changes, with a mechanism like inotify or polling.

Each podCertificate projection supports the following configuration fields:

  • signerName: The signer you want to issue the certificate. Note that signers may have their own access requirements, and may refuse to issue certificates to your pod.
  • keyType: The type of private key that should be generated. Valid values are ED25519, ECDSAP256, ECDSAP384, ECDSAP521, RSA3072, and RSA4096.
  • maxExpirationSeconds: The maximum lifetime you will accept for the certificate issued to the pod. If not set, will be defaulted to 86400 (24 hours). Must be at least 3600 (1 hour), and at most 7862400 (91 days). Kubernetes built-in signers are restricted to a max lifetime of 86400 (1 day). The signer is allowed to issue a certificate with a lifetime shorter than what you've specified.
  • credentialBundlePath: Relative path within the projection where the credential bundle should be written. The credential bundle is a PEM-formatted file, where the first block is a "PRIVATE KEY" block that contains a PKCS#8-serialized private key, and the remaining blocks are "CERTIFICATE" blocks that comprise the certificate chain (leaf certificate and any intermediates).
  • keyPath and certificateChainPath: Separate paths where Kubelet should write just the private key or certificate chain.
# Sample Pod spec that uses a podCertificate projection to request an ED25519 # private key, a certificate from the `coolcert.example.com/foo` signer, and # write the results to `/var/run/my-x509-credentials/credentialbundle.pem`. apiVersion: v1 kind: Pod metadata:   namespace: default   name: podcertificate-pod spec:   serviceAccountName: default   containers:   - image: debian     name: main     command: ["sleep", "infinity"]     volumeMounts:     - name: my-x509-credentials       mountPath: /var/run/my-x509-credentials   volumes:   - name: my-x509-credentials     projected:       defaultMode: 420       sources:       - podCertificate:           keyType: ED25519           signerName: coolcert.example.com/foo           credentialBundlePath: credentialbundle.pem 

SecurityContext interactions

The proposal for file permission handling in projected service account volume enhancement introduced the projected files having the correct owner permissions set.

Linux

In Linux pods that have a projected volume and RunAsUser set in the Pod SecurityContext, the projected files have the correct ownership set including container user ownership.

When all containers in a pod have the same runAsUser set in their PodSecurityContext or container SecurityContext, then the kubelet ensures that the contents of the serviceAccountToken volume are owned by that user, and the token file has its permission mode set to 0600.

Windows

In Windows pods that have a projected volume and RunAsUsername set in the Pod SecurityContext, the ownership is not enforced due to the way user accounts are managed in Windows. Windows stores and manages local user and group accounts in a database file called Security Account Manager (SAM). Each container maintains its own instance of the SAM database, to which the host has no visibility into while the container is running. Windows containers are designed to run the user mode portion of the OS in isolation from the host, hence the maintenance of a virtual SAM database. As a result, the kubelet running on the host does not have the ability to dynamically configure host file ownership for virtualized container accounts. It is recommended that if files on the host machine are to be shared with the container then they should be placed into their own volume mount outside of C:\.

By default, the projected files will have the following ownership as shown for an example projected volume file:

PS C:\> Get-Acl C:\var\run\secrets\kubernetes.io\serviceaccount\..2021_08_31_22_22_18.318230061\ca.crt | Format-List  Path   : Microsoft.PowerShell.Core\FileSystem::C:\var\run\secrets\kubernetes.io\serviceaccount\..2021_08_31_22_22_18.318230061\ca.crt Owner  : BUILTIN\Administrators Group  : NT AUTHORITY\SYSTEM Access : NT AUTHORITY\SYSTEM Allow  FullControl          BUILTIN\Administrators Allow  FullControl          BUILTIN\Users Allow  ReadAndExecute, Synchronize Audit  : Sddl   : O:BAG:SYD:AI(A;ID;FA;;;SY)(A;ID;FA;;;BA)(A;ID;0x1200a9;;;BU) 

This implies all administrator users like ContainerAdministrator will have read, write and execute access while, non-administrator users will have read and execute access.

Last modified August 06, 2025 at 12:35 PM PST: Pod Certificates: Narrow documentation of new feature (f72ccf8d9b)