mirror of
				https://github.com/k3s-io/kubernetes.git
				synced 2025-10-30 21:30:16 +00:00 
			
		
		
		
	Secrets proposal
This commit is contained in:
		
							
								
								
									
										547
									
								
								docs/design/secrets.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										547
									
								
								docs/design/secrets.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,547 @@ | ||||
| # Secret Distribution | ||||
|  | ||||
| ## Abstract | ||||
|  | ||||
| A proposal for the distribution of secrets (passwords, keys, etc) to the Kubelet and to | ||||
| containers inside Kubernetes using a custom volume type. | ||||
|  | ||||
| ## Motivation | ||||
|  | ||||
| Secrets are needed in containers to access internal resources like the Kubernetes master or | ||||
| external resources such as git repositories, databases, etc.  Users may also want behaviors in the | ||||
| kubelet that depend on secret data (credentials for image pull from a docker registry) associated | ||||
| with pods. | ||||
|  | ||||
| Goals of this design: | ||||
|  | ||||
| 1.  Describe a secret resource | ||||
| 2.  Define the various challenges attendant to managing secrets on the node | ||||
| 3.  Define a mechanism for consuming secrets in containers without modification | ||||
|  | ||||
| ## Constraints and Assumptions | ||||
|  | ||||
| *  This design does not prescribe a method for storing secrets; storage of secrets should be | ||||
|    pluggable to accomodate different use-cases | ||||
| *  Encryption of secret data and node security are orthogonal concerns | ||||
| *  It is assumed that node and master are secure and that compromising their security could also | ||||
|    compromise secrets: | ||||
|    *  If a node is compromised, the only secrets that could potentially be exposed should be the | ||||
|       secrets belonging to containers scheduled onto it | ||||
|    *  If the master is compromised, all secrets in the cluster may be exposed | ||||
| *  Secret rotation is an orthogonal concern, but it should be facilitated by this proposal | ||||
|  | ||||
| ## Use Cases | ||||
|  | ||||
| 1.  As a user, I want to store secret artifacts for my applications and consume them securely in | ||||
|     containers, so that I can keep the configuration for my applications separate from the images | ||||
|     that use them: | ||||
|     1.  As a cluster operator, I want to allow a pod to access the Kubernetes master using a custom | ||||
|         `.kubeconfig` file, so that I can securely reach the master | ||||
|     2.  As a cluster operator, I want to allow a pod to access a Docker registry using credentials | ||||
|         from a `.dockercfg` file, so that containers can push images | ||||
|     3.  As a cluster operator, I want to allow a pod to access a git repository using SSH keys, | ||||
|         so that I can push and fetch to and from the repository | ||||
| 2.  As a user, I want to allow containers to consume supplemental information about services such | ||||
|     as username and password which should be kept secret, so that I can share secrets about a | ||||
|     service amongst the containers in my application securely | ||||
| 3.  As a user, I want to associate a pod with a `ServiceAccount` that consumes a secret and have | ||||
|     the kubelet implement some reserved behaviors based on the types of secrets the service account | ||||
|     consumes: | ||||
|     1.  Use credentials for a docker registry to pull the pod's docker image | ||||
|     2.  Present kubernetes auth token to the pod or transparently decorate traffic between the pod | ||||
|         and master service | ||||
| 4.  As a user, I want to be able to indicate that a secret expires and for that secret's value to | ||||
|     be rotated once it expires, so that the system can help me follow good practices | ||||
|  | ||||
| ### Use-Case: Configuration artifacts | ||||
|  | ||||
| Many configuration files contain secrets intermixed with other configuration information.  For | ||||
| example, a user's application may contain a properties file than contains database credentials, | ||||
| SaaS API tokens, etc.  Users should be able to consume configuration artifacts in their containers | ||||
| and be able to control the path on the container's filesystems where the artifact will be | ||||
| presented. | ||||
|  | ||||
| ### Use-Case: Metadata about services | ||||
|  | ||||
| Most pieces of information about how to use a service are secrets.  For example, a service that | ||||
| provides a MySQL database needs to provide the username, password, and database name to consumers | ||||
| so that they can authenticate and use the correct database. Containers in pods consuming the MySQL | ||||
| service would also consume the secrets associated with the MySQL service. | ||||
|  | ||||
| ### Use-Case: Secrets associated with service accounts | ||||
|  | ||||
| [Service Accounts](https://github.com/GoogleCloudPlatform/kubernetes/pull/2297) are proposed as a | ||||
| mechanism to decouple capabilities and security contexts from individual human users.  A | ||||
| `ServiceAccount` contains references to some number of secrets.  A `Pod` can specify that it is | ||||
| associated with a `ServiceAccount`.  Secrets should have a `Type` field to allow the Kubelet and | ||||
| other system components to take action based on the secret's type. | ||||
|  | ||||
| #### Example: service account consumes auth token secret | ||||
|  | ||||
| As an example, the service account proposal discusses service accounts consuming secrets which | ||||
| contain kubernetes auth tokens.  When a Kubelet starts a pod associated with a service account | ||||
| which consumes this type of secret, the Kubelet may take a number of actions: | ||||
|  | ||||
| 1.  Expose the secret in a `.kubernetes_auth` file in a well-known location in the container's | ||||
|     file system | ||||
| 2.  Configure that node's `kube-proxy` to decorate HTTP requests from that pod to the  | ||||
|     `kubernetes-master` service with the auth token, e. g. by adding a header to the request | ||||
|     (see the [LOAS Daemon](https://github.com/GoogleCloudPlatform/kubernetes/issues/2209) proposal) | ||||
|  | ||||
| #### Example: service account consumes docker registry credentials | ||||
|  | ||||
| Another example use case is where a pod is associated with a secret containing docker registry | ||||
| credentials.  The Kubelet could use these credentials for the docker pull to retrieve the image. | ||||
|  | ||||
| ### Use-Case: Secret expiry and rotation | ||||
|  | ||||
| Rotation is considered a good practice for many types of secret data.  It should be possible to | ||||
| express that a secret has an expiry date; this would make it possible to implement a system | ||||
| component that could regenerate expired secrets.  As an example, consider a component that rotates | ||||
| expired secrets.  The rotator could periodically regenerate the values for expired secrets of | ||||
| common types and update their expiry dates. | ||||
|  | ||||
| ## Deferral: Consuming secrets as environment variables | ||||
|  | ||||
| Some images will expect to receive configuration items as environment variables instead of files. | ||||
| We should consider what the best way to allow this is; there are a few different options: | ||||
|  | ||||
| 1.  Force the user to adapt files into environment variables.  Users can store secrets that need to | ||||
|     be presented as environment variables in a format that is easy to consume from a shell: | ||||
|  | ||||
|         $ cat /etc/secrets/my-secret.txt | ||||
|         export MY_SECRET_ENV=MY_SECRET_VALUE | ||||
|  | ||||
|     The user could `source` the file at `/etc/secrets/my-secret` prior to executing the command for | ||||
|     the image either inline in the command or in an init script,  | ||||
|  | ||||
| 2.  Give secrets an attribute that allows users to express the intent that the platform should | ||||
|     generate the above syntax in the file used to present a secret.  The user could consume these | ||||
|     files in the same manner as the above option. | ||||
|  | ||||
| 3.  Give secrets attributes that allow the user to express that the secret should be presented to | ||||
|     the container as an environment variable.  The container's environment would contain the | ||||
|     desired values and the software in the container could use them without accomodation the | ||||
|     command or setup script. | ||||
|  | ||||
| For our initial work, we will treat all secrets as files to narrow the problem space.  There will | ||||
| be a future proposal that handles exposing secrets as environment variables. | ||||
|  | ||||
| ## Flow analysis of secret data with respect to the API server | ||||
|  | ||||
| There are two fundamentally different use-cases for access to secrets: | ||||
|  | ||||
| 1.  CRUD operations on secrets by their owners | ||||
| 2.  Read-only access to the secrets needed for a particular node by the kubelet | ||||
|  | ||||
| ### Use-Case: CRUD operations by owners | ||||
|  | ||||
| In use cases for CRUD operations, the user experience for secrets should be no different than for | ||||
| other API resources. | ||||
|  | ||||
| #### Data store backing the REST API | ||||
|  | ||||
| The data store backing the REST API should be pluggable because different cluster operators will | ||||
| have different preferences for the central store of secret data.  Some possibilities for storage: | ||||
|  | ||||
| 1.  An etcd collection alongside the storage for other API resources | ||||
| 2.  A collocated [HSM](http://en.wikipedia.org/wiki/Hardware_security_module) | ||||
| 3.  An external datastore such as an external etcd, RDBMS, etc. | ||||
|  | ||||
| #### Size limit for secrets | ||||
|  | ||||
| There should be a size limit for secrets in order to: | ||||
|  | ||||
| 1.  Prevent DOS attacks against the API server | ||||
| 2.  Allow kubelet implementations that prevent secret data from touching the node's filesystem | ||||
|  | ||||
| The size limit should satisfy the following conditions: | ||||
|  | ||||
| 1.  Large enough to store common artifact types (encryption keypairs, certificates, small | ||||
|     configuration files) | ||||
| 2.  Small enough to avoid large impact on node resource consumption (storage, RAM for tmpfs, etc) | ||||
|  | ||||
| To begin discussion, we propose an initial value for this size limit of **1MB**. | ||||
|  | ||||
| #### Other limitations on secrets | ||||
|  | ||||
| Defining a policy for limitations on how a secret may be referenced by another API resource and how | ||||
| constraints should be applied throughout the cluster is tricky due to the number of variables | ||||
| involved: | ||||
|  | ||||
| 1.  Should there be a maximum number of secrets a pod can reference via a volume? | ||||
| 2.  Should there be a maximum number of secrets a service account can reference? | ||||
| 3.  Should there be a total maximum number of secrets a pod can reference via its own spec and its | ||||
|     associated service account? | ||||
| 4.  Should there be a total size limit on the amount of secret data consumed by a pod? | ||||
| 5.  How will cluster operators want to be able to configure these limits? | ||||
| 6.  How will these limits impact API server validations? | ||||
| 7.  How will these limits affect scheduling? | ||||
|  | ||||
| For now, we will not implement validations around these limits.  Cluster operators will decide how | ||||
| much node storage is allocated to secrets. It will be the operator's responsibility to ensure that | ||||
| the allocated storage is sufficient for the workload scheduled onto a node. | ||||
|  | ||||
| ### Use-Case: Kubelet read of secrets for node | ||||
|  | ||||
| The use-case where the kubelet reads secrets has several additional requirements: | ||||
|  | ||||
| 1.  Kubelets should only be able to receive secret data which is required by pods scheduled onto | ||||
|     the kubelet's node | ||||
| 2.  Kubelets should have read-only access to secret data | ||||
| 3.  Secret data should not be transmitted over the wire insecurely | ||||
| 4.  Kubelets must ensure pods do not have access to each other's secrets | ||||
|  | ||||
| #### Read of secret data by the Kubelet | ||||
|  | ||||
| The Kubelet should only be allowed to read secrets which are consumed by pods scheduled onto that | ||||
| Kubelet's node and their associated service accounts.  Authorization of the Kubelet to read this | ||||
| data would be delegated to an authorization plugin and associated policy rule. | ||||
|  | ||||
| #### Secret data on the node: data at rest | ||||
|  | ||||
| Consideration must be given to whether secret data should be allowed to be at rest on the node: | ||||
|  | ||||
| 1.  If secret data is not allowed to be at rest, the size of secret data becomes another draw on | ||||
|     the node's RAM - should it affect scheduling? | ||||
| 2.  If secret data is allowed to be at rest, should it be encrypted? | ||||
|     1.  If so, how should be this be done? | ||||
|     2.  If not, what threats exist?  What types of secret are appropriate to store this way? | ||||
|  | ||||
| For the sake of limiting complexity, we propose that initially secret data should not be allowed | ||||
| to be at rest on a node; secret data should be stored on a node-level tmpfs filesystem.  This | ||||
| filesystem can be subdivided into directories for use by the kubelet and by the volume plugin. | ||||
|  | ||||
| #### Secret data on the node: resource consumption | ||||
|  | ||||
| The Kubelet will be responsible for creating the per-node tmpfs file system for secret storage. | ||||
| It is hard to make a prescriptive declaration about how much storage is appropriate to reserve for | ||||
| secrets because different installations will vary widely in available resources, desired pod to | ||||
| node density, overcommit policy, and other operation dimensions.  That being the case, we propose | ||||
| for simplicity that the amount of secret storage be controlled by a new parameter to the kubelet | ||||
| with a default value of **64MB**.  It is the cluster operator's responsibility to handle choosing | ||||
| the right storage size for their installation and configuring their Kubelets correctly. | ||||
|  | ||||
| Configuring each Kubelet is not the ideal story for operator experience; it is more intuitive that | ||||
| the cluster-wide storage size be readable from a central configuration store like the one proposed | ||||
| in [#1553](https://github.com/GoogleCloudPlatform/kubernetes/issues/1553).  When such a store | ||||
| exists, the Kubelet could be modified to read this configuration item from the store. | ||||
|  | ||||
| When the Kubelet is modified to advertise node resources (as proposed in | ||||
| [#4441](https://github.com/GoogleCloudPlatform/kubernetes/issues/4441)), the capacity calculation | ||||
| for available memory should factor in the potential size of the node-level tmpfs in order to avoid | ||||
| memory overcommit on the node. | ||||
|  | ||||
| #### Secret data on the node: isolation | ||||
|  | ||||
| Every pod will have a [security context](https://github.com/GoogleCloudPlatform/kubernetes/pull/3910). | ||||
| Secret data on the node should be isolated according to the security context of the container.  The | ||||
| Kubelet volume plugin API will be changed so that a volume plugin receives the security context of | ||||
| a volume along with the volume spec.  This will allow volume plugins to implement setting the | ||||
| security context of volumes they manage. | ||||
|  | ||||
| ## Community work: | ||||
|  | ||||
| Several proposals / upstream patches are notable as background for this proposal: | ||||
|  | ||||
| 1.  [Docker vault proposal](https://github.com/docker/docker/issues/10310) | ||||
| 2.  [Specification for image/container standardization based on volumes](https://github.com/docker/docker/issues/9277) | ||||
| 3.  [Kubernetes service account proposal](https://github.com/GoogleCloudPlatform/kubernetes/pull/2297) | ||||
| 4.  [Secrets proposal for docker (1)](https://github.com/docker/docker/pull/6075) | ||||
| 5.  [Secrets proposal for docker (2)](https://github.com/docker/docker/pull/6697) | ||||
|  | ||||
| ## Proposed Design | ||||
|  | ||||
| We propose a new `Secret` resource which is mounted into containers with a new volume type. Secret | ||||
| volumes will be handled by a volume plugin that does the actual work of fetching the secret and | ||||
| storing it. Secrets contain multiple pieces of data that are presented as different files within | ||||
| the secret volume (example: SSH key pair). | ||||
|  | ||||
| In order to remove the burden from the end user in specifying every file that a secret consists of, | ||||
| it should be possible to mount all files provided by a secret with a single ```VolumeMount``` entry | ||||
| in the container specification. | ||||
|  | ||||
| ### Secret API Resource | ||||
|  | ||||
| A new resource for secrets will be added to the API: | ||||
|  | ||||
| ```go | ||||
| type Secret struct { | ||||
|     TypeMeta | ||||
|     ObjectMeta | ||||
|  | ||||
|     // Keys in this map are the paths relative to the volume | ||||
|     // presented to a container for this secret data. | ||||
|     Data map[string][]byte | ||||
|     Type SecretType | ||||
| } | ||||
|  | ||||
| type SecretType string | ||||
|  | ||||
| const ( | ||||
|     SecretTypeOpaque              SecretType = "opaque"           // Opaque (arbitrary data; default) | ||||
|     SecretTypeKubernetesAuthToken SecretType = "kubernetes-auth"  // Kubernetes auth token | ||||
|     SecretTypeDockerRegistryAuth  SecretType = "docker-reg-auth"  // Docker registry auth | ||||
|     // FUTURE: other type values | ||||
| ) | ||||
|  | ||||
| const MaxSecretSize = 1 * 1024 * 1024 | ||||
| ``` | ||||
|  | ||||
| A Secret can declare a type in order to provide type information to system components that work | ||||
| with secrets.  The default type is `opaque`, which represents arbitrary user-owned data. | ||||
|  | ||||
| Secrets are validated against `MaxSecretSize`. | ||||
|  | ||||
| A new REST API and registry interface will be added to accompany the `Secret` resource.  The | ||||
| default implementation of the registry will store `Secret` information in etcd.  Future registry | ||||
| implementations could store the `TypeMeta` and `ObjectMeta` fields in etcd and store the secret | ||||
| data in another data store entirely, or store the whole object in another data store. | ||||
|  | ||||
| #### Other validations related to secrets | ||||
|  | ||||
| Initially there will be no validations for the number of secrets a pod references, or the number of | ||||
| secrets that can be associated with a service account.  These may be added in the future as the | ||||
| finer points of secrets and resource allocation are fleshed out. | ||||
|  | ||||
| ### Secret Volume Source | ||||
|  | ||||
| A new `SecretSource` type of volume source will be added to the ```VolumeSource``` struct in the | ||||
| API: | ||||
|  | ||||
| ```go | ||||
| type VolumeSource struct { | ||||
|     // Other fields omitted | ||||
|  | ||||
|     // SecretSource represents a secret that should be presented in a volume | ||||
|     SecretSource *SecretSource `json:"secret"` | ||||
| } | ||||
|  | ||||
| type SecretSource struct { | ||||
|     Target ObjectReference | ||||
| } | ||||
| ``` | ||||
|  | ||||
| Secret volume sources are validated to ensure that the specified object reference actually points | ||||
| to an object of type `Secret`. | ||||
|  | ||||
| ### Secret Volume Plugin | ||||
|  | ||||
| A new Kubelet volume plugin will be added to handle volumes with a secret source.  This plugin will | ||||
| require access to the API server to retrieve secret data and therefore the volume `Host` interface | ||||
| will have to change to expose a client interface: | ||||
|  | ||||
| ```go | ||||
| type Host interface { | ||||
|     // Other methods omitted | ||||
|  | ||||
|     // GetKubeClient returns a client interface | ||||
|     GetKubeClient() client.Interface | ||||
| } | ||||
| ``` | ||||
|  | ||||
| The secret volume plugin will be responsible for: | ||||
|  | ||||
| 1.  Returning a `volume.Builder` implementation from `NewBuilder` that: | ||||
|     1.  Retrieves the secret data for the volume from the API server | ||||
|     2.  Places the secret data onto the container's filesystem | ||||
|     3.  Sets the correct security attributes for the volume based on the pod's `SecurityContext` | ||||
| 2.  Returning a `volume.Cleaner` implementation from `NewClear` that cleans the volume from the | ||||
|     container's filesystem | ||||
|  | ||||
| ### Kubelet: Node-level secret storage | ||||
|  | ||||
| The Kubelet must be modified to accept a new parameter for the secret storage size and to create | ||||
| a tmpfs file system of that size to store secret data.  Rough accounting of specific changes: | ||||
|  | ||||
| 1.  The Kubelet should have a new field added called `secretStorageSize`; units are megabytes | ||||
| 2.  `NewMainKubelet` should accept a value for secret storage size | ||||
| 3.  The Kubelet server should have a new flag added for secret storage size | ||||
| 4.  The Kubelet's `setupDataDirs` method should be changed to create the secret storage | ||||
|  | ||||
| ### Kubelet: New behaviors for secrets associated with service accounts | ||||
|  | ||||
| For use-cases where the Kubelet's behavior is affected by the secrets associated with a pod's | ||||
| `ServiceAccount`, the Kubelet will need to be changed.  For example, if secrets of type | ||||
| `docker-reg-auth` affect how the pod's images are pulled, the Kubelet will need to be changed | ||||
| to accomodate this.  Subsequent proposals can address this on a type-by-type basis. | ||||
|  | ||||
| ## Examples | ||||
|  | ||||
| For clarity, let's examine some detailed examples of some common use-cases in terms of the | ||||
| suggested changes.  All of these examples are assumed to be created in a namespace called | ||||
| `example`. | ||||
|  | ||||
| ### Use-Case: Pod with ssh keys | ||||
|  | ||||
| To create a pod that uses an ssh key stored as a secret, we first need to create a secret: | ||||
|  | ||||
| ```json | ||||
| { | ||||
|   "apiVersion": "v1beta2", | ||||
|   "kind": "Secret", | ||||
|   "id": "ssh-key-secret", | ||||
|   "data": { | ||||
|     "id_rsa.pub": "dmFsdWUtMQ0K", | ||||
|     "id_rsa": "dmFsdWUtMg0KDQo=" | ||||
|   } | ||||
| } | ||||
| ``` | ||||
|  | ||||
| **Note:** The values of secret data are encoded as base64-encoded strings. | ||||
|  | ||||
| Now we can create a pod which references the secret with the ssh key and consumes it in a volume: | ||||
|  | ||||
| ```json | ||||
| { | ||||
|   "id": "secret-test-pod", | ||||
|   "kind": "Pod", | ||||
|   "apiVersion":"v1beta2", | ||||
|   "labels": { | ||||
|     "name": "secret-test" | ||||
|   }, | ||||
|   "desiredState": { | ||||
|     "manifest": { | ||||
|       "version": "v1beta1", | ||||
|       "id": "secret-test-pod", | ||||
|       "containers": [{ | ||||
|         "name": "ssh-test-container", | ||||
|         "image": "mySshImage", | ||||
|         "volumeMounts": [{ | ||||
|           "name": "secret-volume", | ||||
|           "mountPath": "/etc/secret-volume", | ||||
|           "readOnly": true | ||||
|         }] | ||||
|       }], | ||||
|       "volumes": [{ | ||||
|         "name": "secret-volume", | ||||
|         "source": { | ||||
|           "secret": { | ||||
|             "target": { | ||||
|               "kind": "Secret", | ||||
|               "namespace": "example", | ||||
|               "name": "ssh-key-secret" | ||||
|             } | ||||
|           } | ||||
|         } | ||||
|       }] | ||||
|     } | ||||
|   } | ||||
| } | ||||
| ``` | ||||
|  | ||||
| When the container's command runs, the pieces of the key will be available in: | ||||
|  | ||||
|     /etc/secret-volume/id_rsa.pub | ||||
|     /etc/secret-volume/id_rsa | ||||
|  | ||||
| The container is then free to use the secret data to establish an ssh connection. | ||||
|  | ||||
| ### Use-Case: Pods with pod / test credentials | ||||
|  | ||||
| Let's compare examples where a pod consumes a secret containing prod credentials and another pod | ||||
| consumes a secret with test environment credentials. | ||||
|  | ||||
| The secrets: | ||||
|  | ||||
| ```json | ||||
| [{ | ||||
|   "apiVersion": "v1beta2", | ||||
|   "kind": "Secret", | ||||
|   "id": "prod-db-secret", | ||||
|   "data": { | ||||
|     "username": "dmFsdWUtMQ0K", | ||||
|     "password": "dmFsdWUtMg0KDQo=" | ||||
|   } | ||||
| }, | ||||
| { | ||||
|   "apiVersion": "v1beta2", | ||||
|   "kind": "Secret", | ||||
|   "id": "test-db-secret", | ||||
|   "data": { | ||||
|     "username": "dmFsdWUtMQ0K", | ||||
|     "password": "dmFsdWUtMg0KDQo=" | ||||
|   } | ||||
| }] | ||||
| ``` | ||||
|  | ||||
| The pods: | ||||
|  | ||||
| ```json | ||||
| [{ | ||||
|   "id": "prod-db-client-pod", | ||||
|   "kind": "Pod", | ||||
|   "apiVersion":"v1beta2", | ||||
|   "labels": { | ||||
|     "name": "prod-db-client" | ||||
|   }, | ||||
|   "desiredState": { | ||||
|     "manifest": { | ||||
|       "version": "v1beta1", | ||||
|       "id": "prod-db-pod", | ||||
|       "containers": [{ | ||||
|         "name": "db-client-container", | ||||
|         "image": "myClientImage", | ||||
|         "volumeMounts": [{ | ||||
|           "name": "secret-volume", | ||||
|           "mountPath": "/etc/secret-volume", | ||||
|           "readOnly": true | ||||
|         }] | ||||
|       }], | ||||
|       "volumes": [{ | ||||
|         "name": "secret-volume", | ||||
|         "source": { | ||||
|           "secret": { | ||||
|             "target": { | ||||
|               "kind": "Secret", | ||||
|               "namespace": "example", | ||||
|               "name": "prod-db-secret" | ||||
|             } | ||||
|           } | ||||
|         } | ||||
|       }] | ||||
|     } | ||||
|   } | ||||
| }, | ||||
| { | ||||
|   "id": "test-db-client-pod", | ||||
|   "kind": "Pod", | ||||
|   "apiVersion":"v1beta2", | ||||
|   "labels": { | ||||
|     "name": "test-db-client" | ||||
|   }, | ||||
|   "desiredState": { | ||||
|     "manifest": { | ||||
|       "version": "v1beta1", | ||||
|       "id": "test-db-pod", | ||||
|       "containers": [{ | ||||
|         "name": "db-client-container", | ||||
|         "image": "myClientImage", | ||||
|         "volumeMounts": [{ | ||||
|           "name": "secret-volume", | ||||
|           "mountPath": "/etc/secret-volume", | ||||
|           "readOnly": true | ||||
|         }] | ||||
|       }], | ||||
|       "volumes": [{ | ||||
|         "name": "secret-volume", | ||||
|         "source": { | ||||
|           "secret": { | ||||
|             "target": { | ||||
|               "kind": "Secret", | ||||
|               "namespace": "example", | ||||
|               "name": "test-db-secret" | ||||
|             } | ||||
|           } | ||||
|         } | ||||
|       }] | ||||
|     } | ||||
|   } | ||||
| }] | ||||
| ``` | ||||
|  | ||||
| The specs for the two pods differ only in the value of the object referred to by the secret volume | ||||
| source.  Both containers will have the following files present on their filesystems: | ||||
|  | ||||
|     /etc/secret-volume/username | ||||
|     /etc/secret-volume/password | ||||
		Reference in New Issue
	
	Block a user