Kubernetes Secrets Operations: Difference between revisions

From NovaOrdis Knowledge Base
Jump to navigation Jump to search
Line 137: Line 137:
Declare and deploy the "blue" secret as described in the [[#From_a_Manifest|Create a Secret from a Manifest]] section.
Declare and deploy the "blue" secret as described in the [[#From_a_Manifest|Create a Secret from a Manifest]] section.


Modify the pod to add a new .spec.volumes[] volume, whose .spec.volumes[].secret.secretName must match the name of the secret to be exposed to the pod. Then under the container's "volumeMounts" add a volume mount whose name is the name of the "secret" volume. Specify spec.containers[].volumeMounts[].readOnly = true. <font color=darkgray>Even if I don't specify readOnly=true, when trying to edit the content of the file I get "Warning: Changing a readonly file".</font> If there are multiple containers in the pod, each container will need its own volumeMounts mount, but only one .spec.volumes[] volume is needed per pod.
Modify the pod to add a new <code>.spec.volumes[]</code> volume, whose .spec.volumes[].secret.secretName must match the name of the secret to be exposed to the pod. Then under the container's "volumeMounts" add a volume mount whose name is the name of the "secret" volume. Specify spec.containers[].volumeMounts[].readOnly = true. <font color=darkgray>Even if I don't specify readOnly=true, when trying to edit the content of the file I get "Warning: Changing a readonly file".</font> If there are multiple containers in the pod, each container will need its own volumeMounts mount, but only one .spec.volumes[] volume is needed per pod.


When the pod deploys, each key/value entry of the secret's [[Kubernetes Cluster Configuration Concepts#Secret_Data_Map|data map]]  is exposed as a file <font color=darkgray>where, in what directory?</font>, where the file name is given by the key and the file content is filled with decoded value from the secret.  
When the pod deploys, each key/value entry of the secret's [[Kubernetes Cluster Configuration Concepts#Secret_Data_Map|data map]]  is exposed as a file <font color=darkgray>where, in what directory?</font>, where the file name is given by the key and the file content is filled with decoded value from the secret.  

Revision as of 19:41, 29 January 2020

Internal

Inspecting Secrets

kubectl get secrets
kubectl get secret mysecret -o yaml

The value of the secret is base64-encoded and it can be retrieved with:

echo '....' | base64 --decode
kubectl describe secret secret-name

Create a Secret

With kubectl CLI

Creating a Secret Using kubectl create secret

From File

Declare the secret content in one (or more) file(s) on the local filesystem. The file name will become a secret's data map key. Multiple files can be added to the same secret. When the secret is exposed to a pod, the content will be available as volume files with the same name.

echo -n "test-user" > ./username.txt
echo -p "test-password" > ./password.txt
kubectl create secret generic username-and-password --from-file=./username.txt --from-file=./password.txt

This will create the following secret:

Name:         username-and-password
Namespace:    test
Labels:       <none>
Annotations:  <none>

Type:  Opaque

Data
====
password.txt:  17 bytes
username.txt:  9 bytes

From Literal

The secret's data map key followed by "=" followed by value can be specified on command line with --from-literal=.

kubectl create secret generic red --from-literal=key1=somevalue --from-literal=key2=someothervalue

From Env File

A key-value (env) file can be used as source for secrets with --from-env-file=. The keys in the key-value file become the keys in the secret's data map.

kubectl create secret generic green --from-env-file=./test.txt

where test.txt:

key1=value1
key2=value2

Special Character Handling

Special characters such as '$', '*' and '!' require escaping (\).

From a Manifest

Creating a Secret Manually

The secret's data map key/value pairs can be specified in the manifest. The value must be base64-encoded before being written in the manifest.

apiVersion: v1
kind: Secret
metadata:
  name: blue
type: Opaque
data:
  shape: c3F1YXJl
  size: bGFyZ2U=

Alternatively, the values can be specified in clear as part of the "stringData" map; they will be encoded by Kubernetes when the secret is created:

apiVersion: v1
kind: Secret
metadata:
  name: blue
type: Opaque
stringData:
  shape: square
  size: large

Assuming that the secret was declared into a blue-secret.yaml file, it can be deployed as follows:

kubectl apply -f ./blue-secret.yaml

It then can be queried with:

kubectl -o yaml get secret blue
apiVersion: v1
data:
  shape: c3F1YXJl
  size: bGFyZ2U=
kind: Secret
metadata:
  annotations:
    kubectl.kubernetes.io/last-applied-configuration: |
      {"apiVersion":"v1","data":{"shape":"c3F1YXJl","size":"bGFyZ2U="},"kind":"Secret","metadata":{"annotations":{},"name":"blue","namespace":"default"},"type":"Opaque"}
  creationTimestamp: "2020-01-29T18:37:40Z"
  name: blue
  namespace: default
  resourceVersion: "3993231"
  selfLink: /api/v1/namespaces/default/secrets/blue
  uid: 6def1f72-42c6-11ea-87aa-025000000001
type: Opaque

Creating Secrets with a Generator

Creating a Secret from Generator

TODO

Consume a Secret

Consume a Secret as a File

Playground - Consume a Secret as File

Declare and deploy the "blue" secret as described in the Create a Secret from a Manifest section.

Modify the pod to add a new .spec.volumes[] volume, whose .spec.volumes[].secret.secretName must match the name of the secret to be exposed to the pod. Then under the container's "volumeMounts" add a volume mount whose name is the name of the "secret" volume. Specify spec.containers[].volumeMounts[].readOnly = true. Even if I don't specify readOnly=true, when trying to edit the content of the file I get "Warning: Changing a readonly file". If there are multiple containers in the pod, each container will need its own volumeMounts mount, but only one .spec.volumes[] volume is needed per pod.

When the pod deploys, each key/value entry of the secret's data map is exposed as a file where, in what directory?, where the file name is given by the key and the file content is filled with decoded value from the secret.

In the example below, assuming that the "blue" secret has a key named "shape" with a "large" value, the pod sees a /etc/blue/shape file and the content of the file is "large" text.

kind: Pod
...
spec:
  containers:
  - name: ...
    volumeMounts:    
    - name: secret-volume
      mountPath: /etc/blue
      readOnly: true
  volumes:
  - name: secret-volume
    secret:
      secretName: blue
      defaultMode: 0400

Projection of Keys to Specific Paths with Specific Permissions

By default, all keys of the map are projected in the root of the volume corresponding to the secret. However, individual keys can be mapped on arbitrary relative paths by using spec.volumes[].secret.items[].key[]. Not only an arbitrary path, but also arbitrary permissions under which the file will be exposed can be specified:

kind: Pod
...
spec:
  ...
  volumes:
  - name: secret-volume
    secret:
      secretName: blue
      defaultMode: 0400
      items:
      - key: shape
         path: dir-A/dir-B/secret-shape
         mode: 0440

If the secret contains multiple keys, and the "items[]" element is used, only the keys specified under "items:" will be projected, and the rest will be ignored. Also, if a key that does not exist in the secret is specified, the volume is not created.

Consume a Secret as an Environment Variable

kind: Pod
...
spec:
  containers:
  - name: ...
    volumeMounts:    
    - name: secret-volume
      env:
      - name: SECRET_SHAPE
        valueFrom:
          secretKeyRef:
            name: blue
            key: shape
~

Project a Secret Key to a Specific Path

TODO: Projection of secret keys to specific paths Also addresses secret file permissions.