Merge pull request #41936 from shannonxtreme/secret-use-cases
Improve and clean up use cases for Secrets
This commit is contained in:
commit
aa40dc7aae
|
|
@ -55,18 +55,75 @@ See [Information security for Secrets](#information-security-for-secrets) for mo
|
||||||
|
|
||||||
## Uses for Secrets
|
## Uses for Secrets
|
||||||
|
|
||||||
There are three main ways for a Pod to use a Secret:
|
You can use Secrets for purposes such as the following:
|
||||||
|
|
||||||
- As [files](#using-secrets-as-files-from-a-pod) in a
|
- [Set environment variables for a container](/docs/tasks/inject-data-application/distribute-credentials-secure/#define-container-environment-variables-using-secret-data).
|
||||||
{{< glossary_tooltip text="volume" term_id="volume" >}} mounted on one or more of
|
- [Provide credentials such as SSH keys or passwords to Pods](/docs/tasks/inject-data-application/distribute-credentials-secure/#provide-prod-test-creds).
|
||||||
its containers.
|
- [Allow the kubelet to pull container images from private registries](/docs/tasks/configure-pod-container/pull-image-private-registry/).
|
||||||
- As [container environment variable](#using-secrets-as-environment-variables).
|
|
||||||
- By the [kubelet when pulling images](#using-imagepullsecrets) for the Pod.
|
|
||||||
|
|
||||||
The Kubernetes control plane also uses Secrets; for example,
|
The Kubernetes control plane also uses Secrets; for example,
|
||||||
[bootstrap token Secrets](#bootstrap-token-secrets) are a mechanism to
|
[bootstrap token Secrets](#bootstrap-token-secrets) are a mechanism to
|
||||||
help automate node registration.
|
help automate node registration.
|
||||||
|
|
||||||
|
### Use case: dotfiles in a secret volume
|
||||||
|
|
||||||
|
You can make your data "hidden" by defining a key that begins with a dot.
|
||||||
|
This key represents a dotfile or "hidden" file. For example, when the following secret
|
||||||
|
is mounted into a volume, `secret-volume`, the volume will contain a single file,
|
||||||
|
called `.secret-file`, and the `dotfile-test-container` will have this file
|
||||||
|
present at the path `/etc/secret-volume/.secret-file`.
|
||||||
|
|
||||||
|
{{< note >}}
|
||||||
|
Files beginning with dot characters are hidden from the output of `ls -l`;
|
||||||
|
you must use `ls -la` to see them when listing directory contents.
|
||||||
|
{{< /note >}}
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Secret
|
||||||
|
metadata:
|
||||||
|
name: dotfile-secret
|
||||||
|
data:
|
||||||
|
.secret-file: dmFsdWUtMg0KDQo=
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Pod
|
||||||
|
metadata:
|
||||||
|
name: secret-dotfiles-pod
|
||||||
|
spec:
|
||||||
|
volumes:
|
||||||
|
- name: secret-volume
|
||||||
|
secret:
|
||||||
|
secretName: dotfile-secret
|
||||||
|
containers:
|
||||||
|
- name: dotfile-test-container
|
||||||
|
image: registry.k8s.io/busybox
|
||||||
|
command:
|
||||||
|
- ls
|
||||||
|
- "-l"
|
||||||
|
- "/etc/secret-volume"
|
||||||
|
volumeMounts:
|
||||||
|
- name: secret-volume
|
||||||
|
readOnly: true
|
||||||
|
mountPath: "/etc/secret-volume"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Use case: Secret visible to one container in a Pod
|
||||||
|
|
||||||
|
Consider a program that needs to handle HTTP requests, do some complex business
|
||||||
|
logic, and then sign some messages with an HMAC. Because it has complex
|
||||||
|
application logic, there might be an unnoticed remote file reading exploit in
|
||||||
|
the server, which could expose the private key to an attacker.
|
||||||
|
|
||||||
|
This could be divided into two processes in two containers: a frontend container
|
||||||
|
which handles user interaction and business logic, but which cannot see the
|
||||||
|
private key; and a signer container that can see the private key, and responds
|
||||||
|
to simple signing requests from the frontend (for example, over localhost networking).
|
||||||
|
|
||||||
|
With this partitioned approach, an attacker now has to trick the application
|
||||||
|
server into doing something rather arbitrary, which may be harder than getting
|
||||||
|
it to read a file.
|
||||||
|
|
||||||
### Alternatives to Secrets
|
### Alternatives to Secrets
|
||||||
|
|
||||||
Rather than using a Secret to protect confidential data, you can pick from alternatives.
|
Rather than using a Secret to protect confidential data, you can pick from alternatives.
|
||||||
|
|
@ -108,8 +165,8 @@ These types vary in terms of the validations performed and the constraints
|
||||||
Kubernetes imposes on them.
|
Kubernetes imposes on them.
|
||||||
|
|
||||||
| Built-in Type | Usage |
|
| Built-in Type | Usage |
|
||||||
| ------------------------------------- | --------------------------------------- |
|
| ------------------------------------- |---------------------------------------- |
|
||||||
| `Opaque` | arbitrary user-defined data |
|
| `Opaque` | arbitrary user-defined data |
|
||||||
| `kubernetes.io/service-account-token` | ServiceAccount token |
|
| `kubernetes.io/service-account-token` | ServiceAccount token |
|
||||||
| `kubernetes.io/dockercfg` | serialized `~/.dockercfg` file |
|
| `kubernetes.io/dockercfg` | serialized `~/.dockercfg` file |
|
||||||
| `kubernetes.io/dockerconfigjson` | serialized `~/.docker/config.json` file |
|
| `kubernetes.io/dockerconfigjson` | serialized `~/.docker/config.json` file |
|
||||||
|
|
@ -576,17 +633,17 @@ metadata:
|
||||||
name: mypod
|
name: mypod
|
||||||
spec:
|
spec:
|
||||||
containers:
|
containers:
|
||||||
- name: mypod
|
- name: mypod
|
||||||
image: redis
|
image: redis
|
||||||
volumeMounts:
|
volumeMounts:
|
||||||
- name: foo
|
|
||||||
mountPath: "/etc/foo"
|
|
||||||
readOnly: true
|
|
||||||
volumes:
|
|
||||||
- name: foo
|
- name: foo
|
||||||
secret:
|
mountPath: "/etc/foo"
|
||||||
secretName: mysecret
|
readOnly: true
|
||||||
optional: true
|
volumes:
|
||||||
|
- name: foo
|
||||||
|
secret:
|
||||||
|
secretName: mysecret
|
||||||
|
optional: true
|
||||||
```
|
```
|
||||||
|
|
||||||
By default, Secrets are required. None of a Pod's containers will start until
|
By default, Secrets are required. None of a Pod's containers will start until
|
||||||
|
|
@ -697,269 +754,6 @@ for a detailed explanation of that process.
|
||||||
|
|
||||||
You cannot use ConfigMaps or Secrets with {{< glossary_tooltip text="static Pods" term_id="static-pod" >}}.
|
You cannot use ConfigMaps or Secrets with {{< glossary_tooltip text="static Pods" term_id="static-pod" >}}.
|
||||||
|
|
||||||
## Use cases
|
|
||||||
|
|
||||||
### Use case: As container environment variables {#use-case-as-container-environment-variables}
|
|
||||||
|
|
||||||
You can create a Secret and use it to
|
|
||||||
[set environment variables for a container](/docs/tasks/inject-data-application/distribute-credentials-secure/#define-container-environment-variables-using-secret-data).
|
|
||||||
|
|
||||||
### Use case: Pod with SSH keys
|
|
||||||
|
|
||||||
Create a Secret containing some SSH keys:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
kubectl create secret generic ssh-key-secret --from-file=ssh-privatekey=/path/to/.ssh/id_rsa --from-file=ssh-publickey=/path/to/.ssh/id_rsa.pub
|
|
||||||
```
|
|
||||||
|
|
||||||
The output is similar to:
|
|
||||||
|
|
||||||
```
|
|
||||||
secret "ssh-key-secret" created
|
|
||||||
```
|
|
||||||
|
|
||||||
You can also create a `kustomization.yaml` with a `secretGenerator` field containing ssh keys.
|
|
||||||
|
|
||||||
{{< caution >}}
|
|
||||||
Think carefully before sending your own SSH keys: other users of the cluster may have access
|
|
||||||
to the Secret.
|
|
||||||
|
|
||||||
You could instead create an SSH private key representing a service identity that you want to be
|
|
||||||
accessible to all the users with whom you share the Kubernetes cluster, and that you can revoke
|
|
||||||
if the credentials are compromised.
|
|
||||||
{{< /caution >}}
|
|
||||||
|
|
||||||
Now you can create a Pod which references the secret with the SSH key and
|
|
||||||
consumes it in a volume:
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
apiVersion: v1
|
|
||||||
kind: Pod
|
|
||||||
metadata:
|
|
||||||
name: secret-test-pod
|
|
||||||
labels:
|
|
||||||
name: secret-test
|
|
||||||
spec:
|
|
||||||
volumes:
|
|
||||||
- name: secret-volume
|
|
||||||
secret:
|
|
||||||
secretName: ssh-key-secret
|
|
||||||
containers:
|
|
||||||
- name: ssh-test-container
|
|
||||||
image: mySshImage
|
|
||||||
volumeMounts:
|
|
||||||
- name: secret-volume
|
|
||||||
readOnly: true
|
|
||||||
mountPath: "/etc/secret-volume"
|
|
||||||
```
|
|
||||||
|
|
||||||
When the container's command runs, the pieces of the key will be available in:
|
|
||||||
|
|
||||||
```
|
|
||||||
/etc/secret-volume/ssh-publickey
|
|
||||||
/etc/secret-volume/ssh-privatekey
|
|
||||||
```
|
|
||||||
|
|
||||||
The container is then free to use the secret data to establish an SSH connection.
|
|
||||||
|
|
||||||
### Use case: Pods with prod / test credentials
|
|
||||||
|
|
||||||
This example illustrates a Pod which consumes a secret containing production credentials and
|
|
||||||
another Pod which consumes a secret with test environment credentials.
|
|
||||||
|
|
||||||
You can create a `kustomization.yaml` with a `secretGenerator` field or run
|
|
||||||
`kubectl create secret`.
|
|
||||||
|
|
||||||
```shell
|
|
||||||
kubectl create secret generic prod-db-secret --from-literal=username=produser --from-literal=password=Y4nys7f11
|
|
||||||
```
|
|
||||||
|
|
||||||
The output is similar to:
|
|
||||||
|
|
||||||
```
|
|
||||||
secret "prod-db-secret" created
|
|
||||||
```
|
|
||||||
|
|
||||||
You can also create a secret for test environment credentials.
|
|
||||||
|
|
||||||
```shell
|
|
||||||
kubectl create secret generic test-db-secret --from-literal=username=testuser --from-literal=password=iluvtests
|
|
||||||
```
|
|
||||||
|
|
||||||
The output is similar to:
|
|
||||||
|
|
||||||
```
|
|
||||||
secret "test-db-secret" created
|
|
||||||
```
|
|
||||||
|
|
||||||
{{< note >}}
|
|
||||||
Special characters such as `$`, `\`, `*`, `=`, and `!` will be interpreted by your
|
|
||||||
[shell](https://en.wikipedia.org/wiki/Shell_(computing)) and require escaping.
|
|
||||||
|
|
||||||
In most shells, the easiest way to escape the password is to surround it with single quotes (`'`).
|
|
||||||
For example, if your actual password is `S!B\*d$zDsb=`, you should execute the command this way:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
kubectl create secret generic dev-db-secret --from-literal=username=devuser --from-literal=password='S!B\*d$zDsb='
|
|
||||||
```
|
|
||||||
|
|
||||||
You do not need to escape special characters in passwords from files (`--from-file`).
|
|
||||||
{{< /note >}}
|
|
||||||
|
|
||||||
Now make the Pods:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
cat <<EOF > pod.yaml
|
|
||||||
apiVersion: v1
|
|
||||||
kind: List
|
|
||||||
items:
|
|
||||||
- kind: Pod
|
|
||||||
apiVersion: v1
|
|
||||||
metadata:
|
|
||||||
name: prod-db-client-pod
|
|
||||||
labels:
|
|
||||||
name: prod-db-client
|
|
||||||
spec:
|
|
||||||
volumes:
|
|
||||||
- name: secret-volume
|
|
||||||
secret:
|
|
||||||
secretName: prod-db-secret
|
|
||||||
containers:
|
|
||||||
- name: db-client-container
|
|
||||||
image: myClientImage
|
|
||||||
volumeMounts:
|
|
||||||
- name: secret-volume
|
|
||||||
readOnly: true
|
|
||||||
mountPath: "/etc/secret-volume"
|
|
||||||
- kind: Pod
|
|
||||||
apiVersion: v1
|
|
||||||
metadata:
|
|
||||||
name: test-db-client-pod
|
|
||||||
labels:
|
|
||||||
name: test-db-client
|
|
||||||
spec:
|
|
||||||
volumes:
|
|
||||||
- name: secret-volume
|
|
||||||
secret:
|
|
||||||
secretName: test-db-secret
|
|
||||||
containers:
|
|
||||||
- name: db-client-container
|
|
||||||
image: myClientImage
|
|
||||||
volumeMounts:
|
|
||||||
- name: secret-volume
|
|
||||||
readOnly: true
|
|
||||||
mountPath: "/etc/secret-volume"
|
|
||||||
EOF
|
|
||||||
```
|
|
||||||
|
|
||||||
Add the pods to the same `kustomization.yaml`:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
cat <<EOF >> kustomization.yaml
|
|
||||||
resources:
|
|
||||||
- pod.yaml
|
|
||||||
EOF
|
|
||||||
```
|
|
||||||
|
|
||||||
Apply all those objects on the API server by running:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
kubectl apply -k .
|
|
||||||
```
|
|
||||||
|
|
||||||
Both containers will have the following files present on their filesystems with the values
|
|
||||||
for each container's environment:
|
|
||||||
|
|
||||||
```
|
|
||||||
/etc/secret-volume/username
|
|
||||||
/etc/secret-volume/password
|
|
||||||
```
|
|
||||||
|
|
||||||
Note how the specs for the two Pods differ only in one field; this facilitates
|
|
||||||
creating Pods with different capabilities from a common Pod template.
|
|
||||||
|
|
||||||
You could further simplify the base Pod specification by using two service accounts:
|
|
||||||
|
|
||||||
1. `prod-user` with the `prod-db-secret`
|
|
||||||
1. `test-user` with the `test-db-secret`
|
|
||||||
|
|
||||||
The Pod specification is shortened to:
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
apiVersion: v1
|
|
||||||
kind: Pod
|
|
||||||
metadata:
|
|
||||||
name: prod-db-client-pod
|
|
||||||
labels:
|
|
||||||
name: prod-db-client
|
|
||||||
spec:
|
|
||||||
serviceAccount: prod-db-client
|
|
||||||
containers:
|
|
||||||
- name: db-client-container
|
|
||||||
image: myClientImage
|
|
||||||
```
|
|
||||||
|
|
||||||
### Use case: dotfiles in a secret volume
|
|
||||||
|
|
||||||
You can make your data "hidden" by defining a key that begins with a dot.
|
|
||||||
This key represents a dotfile or "hidden" file. For example, when the following secret
|
|
||||||
is mounted into a volume, `secret-volume`:
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
apiVersion: v1
|
|
||||||
kind: Secret
|
|
||||||
metadata:
|
|
||||||
name: dotfile-secret
|
|
||||||
data:
|
|
||||||
.secret-file: dmFsdWUtMg0KDQo=
|
|
||||||
---
|
|
||||||
apiVersion: v1
|
|
||||||
kind: Pod
|
|
||||||
metadata:
|
|
||||||
name: secret-dotfiles-pod
|
|
||||||
spec:
|
|
||||||
volumes:
|
|
||||||
- name: secret-volume
|
|
||||||
secret:
|
|
||||||
secretName: dotfile-secret
|
|
||||||
containers:
|
|
||||||
- name: dotfile-test-container
|
|
||||||
image: registry.k8s.io/busybox
|
|
||||||
command:
|
|
||||||
- ls
|
|
||||||
- "-l"
|
|
||||||
- "/etc/secret-volume"
|
|
||||||
volumeMounts:
|
|
||||||
- name: secret-volume
|
|
||||||
readOnly: true
|
|
||||||
mountPath: "/etc/secret-volume"
|
|
||||||
```
|
|
||||||
|
|
||||||
The volume will contain a single file, called `.secret-file`, and
|
|
||||||
the `dotfile-test-container` will have this file present at the path
|
|
||||||
`/etc/secret-volume/.secret-file`.
|
|
||||||
|
|
||||||
{{< note >}}
|
|
||||||
Files beginning with dot characters are hidden from the output of `ls -l`;
|
|
||||||
you must use `ls -la` to see them when listing directory contents.
|
|
||||||
{{< /note >}}
|
|
||||||
|
|
||||||
### Use case: Secret visible to one container in a Pod
|
|
||||||
|
|
||||||
Consider a program that needs to handle HTTP requests, do some complex business
|
|
||||||
logic, and then sign some messages with an HMAC. Because it has complex
|
|
||||||
application logic, there might be an unnoticed remote file reading exploit in
|
|
||||||
the server, which could expose the private key to an attacker.
|
|
||||||
|
|
||||||
This could be divided into two processes in two containers: a frontend container
|
|
||||||
which handles user interaction and business logic, but which cannot see the
|
|
||||||
private key; and a signer container that can see the private key, and responds
|
|
||||||
to simple signing requests from the frontend (for example, over localhost networking).
|
|
||||||
|
|
||||||
With this partitioned approach, an attacker now has to trick the application
|
|
||||||
server into doing something rather arbitrary, which may be harder than getting
|
|
||||||
it to read a file.
|
|
||||||
|
|
||||||
## Immutable Secrets {#secret-immutable}
|
## Immutable Secrets {#secret-immutable}
|
||||||
|
|
||||||
{{< feature-state for_k8s_version="v1.21" state="stable" >}}
|
{{< feature-state for_k8s_version="v1.21" state="stable" >}}
|
||||||
|
|
|
||||||
|
|
@ -335,6 +335,131 @@ This functionality is available in Kubernetes v1.6 and later.
|
||||||
password: 39528$vdg7Jb
|
password: 39528$vdg7Jb
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Example: Provide prod/test credentials to Pods using Secrets {#provide-prod-test-creds}
|
||||||
|
|
||||||
|
This example illustrates a Pod which consumes a secret containing production credentials and
|
||||||
|
another Pod which consumes a secret with test environment credentials.
|
||||||
|
|
||||||
|
1. Create a secret for prod environment credentials:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
kubectl create secret generic prod-db-secret --from-literal=username=produser --from-literal=password=Y4nys7f11
|
||||||
|
```
|
||||||
|
|
||||||
|
The output is similar to:
|
||||||
|
|
||||||
|
```
|
||||||
|
secret "prod-db-secret" created
|
||||||
|
```
|
||||||
|
|
||||||
|
1. Create a secret for test environment credentials.
|
||||||
|
|
||||||
|
```shell
|
||||||
|
kubectl create secret generic test-db-secret --from-literal=username=testuser --from-literal=password=iluvtests
|
||||||
|
```
|
||||||
|
|
||||||
|
The output is similar to:
|
||||||
|
|
||||||
|
```
|
||||||
|
secret "test-db-secret" created
|
||||||
|
```
|
||||||
|
|
||||||
|
{{< note >}}
|
||||||
|
Special characters such as `$`, `\`, `*`, `=`, and `!` will be interpreted by your
|
||||||
|
[shell](https://en.wikipedia.org/wiki/Shell_(computing)) and require escaping.
|
||||||
|
|
||||||
|
In most shells, the easiest way to escape the password is to surround it with single quotes (`'`).
|
||||||
|
For example, if your actual password is `S!B\*d$zDsb=`, you should execute the command as follows:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
kubectl create secret generic dev-db-secret --from-literal=username=devuser --from-literal=password='S!B\*d$zDsb='
|
||||||
|
```
|
||||||
|
|
||||||
|
You do not need to escape special characters in passwords from files (`--from-file`).
|
||||||
|
{{< /note >}}
|
||||||
|
|
||||||
|
1. Create the Pod manifests:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
cat <<EOF > pod.yaml
|
||||||
|
apiVersion: v1
|
||||||
|
kind: List
|
||||||
|
items:
|
||||||
|
- kind: Pod
|
||||||
|
apiVersion: v1
|
||||||
|
metadata:
|
||||||
|
name: prod-db-client-pod
|
||||||
|
labels:
|
||||||
|
name: prod-db-client
|
||||||
|
spec:
|
||||||
|
volumes:
|
||||||
|
- name: secret-volume
|
||||||
|
secret:
|
||||||
|
secretName: prod-db-secret
|
||||||
|
containers:
|
||||||
|
- name: db-client-container
|
||||||
|
image: myClientImage
|
||||||
|
volumeMounts:
|
||||||
|
- name: secret-volume
|
||||||
|
readOnly: true
|
||||||
|
mountPath: "/etc/secret-volume"
|
||||||
|
- kind: Pod
|
||||||
|
apiVersion: v1
|
||||||
|
metadata:
|
||||||
|
name: test-db-client-pod
|
||||||
|
labels:
|
||||||
|
name: test-db-client
|
||||||
|
spec:
|
||||||
|
volumes:
|
||||||
|
- name: secret-volume
|
||||||
|
secret:
|
||||||
|
secretName: test-db-secret
|
||||||
|
containers:
|
||||||
|
- name: db-client-container
|
||||||
|
image: myClientImage
|
||||||
|
volumeMounts:
|
||||||
|
- name: secret-volume
|
||||||
|
readOnly: true
|
||||||
|
mountPath: "/etc/secret-volume"
|
||||||
|
EOF
|
||||||
|
```
|
||||||
|
Note how the specs for the two Pods differ only in one field; this facilitates creating Pods with different capabilities from a common Pod template.
|
||||||
|
|
||||||
|
1. Apply all those objects on the API server by running:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
kubectl create -f pod.yaml
|
||||||
|
```
|
||||||
|
|
||||||
|
Both containers will have the following files present on their filesystems with the values
|
||||||
|
for each container's environment:
|
||||||
|
|
||||||
|
```
|
||||||
|
/etc/secret-volume/username
|
||||||
|
/etc/secret-volume/password
|
||||||
|
```
|
||||||
|
|
||||||
|
You could further simplify the base Pod specification by using two service accounts:
|
||||||
|
|
||||||
|
1. `prod-user` with the `prod-db-secret`
|
||||||
|
1. `test-user` with the `test-db-secret`
|
||||||
|
|
||||||
|
The Pod specification is shortened to:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Pod
|
||||||
|
metadata:
|
||||||
|
name: prod-db-client-pod
|
||||||
|
labels:
|
||||||
|
name: prod-db-client
|
||||||
|
spec:
|
||||||
|
serviceAccount: prod-db-client
|
||||||
|
containers:
|
||||||
|
- name: db-client-container
|
||||||
|
image: myClientImage
|
||||||
|
```
|
||||||
|
|
||||||
### References
|
### References
|
||||||
|
|
||||||
- [Secret](/docs/reference/generated/kubernetes-api/{{< param "version" >}}/#secret-v1-core)
|
- [Secret](/docs/reference/generated/kubernetes-api/{{< param "version" >}}/#secret-v1-core)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue