bookmark_borderSecrets in Kubernetes

Kubernetes Secrets let you store and manage sensitive information, such as passwords, OAuth tokens, and ssh keys. Storing confidential information in a Secret is safer and more flexible than putting it verbatim in a Pod definition or in a container image. See Secrets design document for more information.

https://kubernetes.io/docs/concepts/configuration/secret/

Secrets are used to store sensitive information like passwords.

They are similar to configMap except that they are stored inencoded or hashed format.

  1. Create and check Secrets
  2. Inject Secrets into the pod from Secrets
  3. Create NodePort Service for checking Secret data in a pod

Create and Check Secrets

$ kubectl create secret generic \
  databaseinfo --from-literal=MYSQL_HOST=localhost \
               --from-literal=MYSQL_PASSWORD=1234567890
secret/databaseinfo created
  • –from-literal option is used to specify the key-value pairs in the command itself.

Create Secrets by YAML file

apiVersion: v1
kind: Secret
metadata:
  name: databaseinfo
data:
  MYSQL_HOST: bG9jYWxob3N0OjMzMDY=
  MYSQL_PASSWORD: MTIzNDU2Nzg5MA==
  • If you want to create secrets object using YAML file, you must specify the data encoded format (Base64)
$ kubectl create -f databaseinfo-secrets.yaml
secret/databaseinfo created

$ kubectl get secrets
NAME                  TYPE                                  DATA   AGE
databaseinfo          Opaque                                2      23s

$ kubectl describe secret databaseinfo
Name:         databaseinfo
Namespace:    default
Labels:       <none>
Annotations:  <none>

Type:  Opaque

Data
====
MYSQL_HOST:      14 bytes
MYSQL_PASSWORD:  10 bytes

Encoded data and Decoded data in Linux

$ echo -n "1234567890" | base64
MTIzNDU2Nzg5MA==
$ echo -n "MTIzNDU2Nzg5MA==" | base64 --decode
1234567890

Inject Secrets into the pod(application) from the Secret

apiVersion: v1
kind: Pod
metadata:
  name: k8s-secrets-node-pod
  labels:
    app: k8s-secrets-node
spec:
  containers:
    - name: k8s-secrets-node-container
      image: jayjodev/k8s-node-app:latest

      envFrom:
        # Will save in process.env
        - secretRef:
            name: databaseinfo
      ports:
        - containerPort: 4000
          protocol: TCP
$ kubectl create -f k8s-secrets-node-pod.yaml 
pod/k8s-secrets-node-pod created

$ kubectl get pods
NAME                      READY   STATUS    RESTARTS   AGE
k8s-secrets-node-pod      1/1     Running   0          23s

jayjodev/k8s-node-app image is node application to check k8s Configmaps and Secrets data

Create NodePort Service for checking Secret data in a pod

apiVersion: v1
kind: Service
metadata:
  name: k8s-secrets-node-nodeport-service
spec:
  type: NodePort
  ports:
    - targetPort: 4000
      port: 80
      nodePort: 30002
  selector:
    app: k8s-secrets-node
$ kubectl create -f k8s-secrets-node-nodeport-service.yaml 
service/k8s-secrets-node-nodeport-service created

$ kubectl get services
NAME                                   TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)        AGE
k8s-secrets-node-nodeport-service      NodePort    10.103.172.56   <none>        80:30002/TCP   25s

If you are using Minikube for testing, type, you can access the app and test in Minikube

$ minikube ssh
docker@minikube:~$ curl localhost:30002/api/secrets/mysql-host
localhost:3306
docker@minikube:~$ curl localhost:30002/api/secrets/mysql-password
1234567890

or

Access the app and test outside of Minikube

$ minikube service --url k8s-secrets-node-nodeport-service
🏃  Starting tunnel for service k8s-secrets-node-nodeport-service.
|-----------|-----------------------------------|-------------|------------------------|
| NAMESPACE |               NAME                | TARGET PORT |          URL           |
|-----------|-----------------------------------|-------------|------------------------|
| default   | k8s-secrets-node-nodeport-service |             | http://127.0.0.1:55940 |
|-----------|-----------------------------------|-------------|------------------------|
http://127.0.0.1:55940
❗  Because you are using a Docker driver on darwin, the terminal needs to be open to run it.

at another terminal

$ curl http://127.0.0.1:55940/api/secrets/mysql-host
localhost:3306
$ curl http://127.0.0.1:55940/api/secrets/mysql-password
1234567890
# Environment
envFrom:
  - secretRef:
      name: <secret_name>

# Single Environment
env:
  - name: redis
    valueFrom:
      secretRefKeyRef:
        name: <secret_name>
        key: password1

# Volume
volumes:
  - name: <volume_name>
    secret:
      name: <secret_name>

More Information

Secrets mount using volume

apiVersion: v1
kind: Pod
metadata:
  name: k8s-secrets-volume-node-pod
  labels:
    app: k8s-secrets-volume-node
spec:
  containers:
    - name: k8s-secrets-node-container
      image: jayjodev/k8s-node-app:latest

      volumeMounts:
        - mountPath: "/opt/secrets"
          name: databaseinfo
      ports:
        - containerPort: 4000
          protocol: TCP
  volumes:
    - name: databaseinfo
      secret:
        secretName: databaseinfo
  • image: nginx is used to sample for containing secret-volume
$ kubectl create -f k8s-secrets-volume-node-pod.yaml 
pod/k8s-secrets-volume-node-pod created

$ kubectl get pods
NAME                          READY   STATUS    RESTARTS   AGE
k8s-secrets-volume-node-pod   1/1     Running   0          5s
$ kubectl exec -it k8s-secrets-volume-node-pod sh
/app # cat /opt/secrets/MYSQL_HOST 
localhost:3306
/app # cat /opt/secrets/MYSQL_PASSWORD 
1234567890/
ANOTE.DEV