Secrets

Secrets

Es un objeto muy parecido a ConfigMap, con la diferencia que secrets se utiliza para pasar datos sensibles, como tockens, usuarios, contraseñás, etc... La forma de pasar los datos es la misma que con configMap a trabes de volumenes o variables de entorno.

Secrets no encripta solo codifica los datos pasados a base64.

Consola

He creado un archivo que contiene datos sensibles y voy a crear un secret con ellos dentro.

sudo kubectl create secret generic mysecret --from-file=./secrets/secrets-files/secret.txt
secret/mysecret created

➜  sudo kubectl get secret mysecret
NAME       TYPE     DATA   AGE
mysecret   Opaque   1      61s

Como se puede ver a continuación el secret se crea con el contenido codificado a base64, que no es nada seguro, pero es lo que ofrece kubernetes.

➜  sudo kubectl describe secret mysecret
Name:         mysecret
Namespace:    default
Labels:       <none>
Annotations:  <none>

Type:  Opaque

Data
====
secret.txt:  29 bytes

➜ sudo kubectl get secret mysecret -o yaml
apiVersion: v1
data:
  secret.txt: c2VjcmV0bzE9aG9sYQpzZWNyZXRvMj1hZGlvcwo=
kind: Secret
metadata:
  creationTimestamp: "2020-04-10T08:23:30Z"
  name: mysecret
  namespace: default
  resourceVersion: "235029"
  selfLink: /api/v1/namespaces/default/secrets/mysecret
  uid: d28711a2-8954-44f3-a50b-0df3282762e4
type: Opaque

# se puede decodificar  revirtiendo el base64 y ver l contenido del archivo.echo c2VjcmV0bzE9aG9sYQpzZWNyZXRvMj1hZGlvcwo= | base64 --decode 
secreto1=hola
secreto2=adios

Template

desde un template yaml se puede pasar los datos de diferentes modos con:

  • data : en esta opción se pasaran en base64 directamente
  • stringData: con esta opción se pasan los datos literales para luego kubernetes haga el codificado a base64.
apiVersion: v1
kind: Secret
metadata:
  name: mysecret2
type: Opaque
stringData:
    username: admin
    password: "12345"
---
apiVersion: v1
kind: Secret
metadata:
  name: mysecret
type: Opaque
data:
  username: YWRtaW4=
  password: MWYyZDFlMmU2N2Rm

En los dos templates anteriores el resultado es el mismo.

➜ sudo kubectl apply -f secrets/secret-stringdata.yml
secret/mysecret2 created

➜ sudo kubectl get secret mysecret2 -o yaml          
[sudo] password for debian: 
apiVersion: v1
data:
  password: MTIzNDU=
  username: YWRtaW4=
kind: Secret
...

Seguro

Como podemos ver esta opción que proporciona kubernetes muy segura no es, pero se puede jugar con ella para mantener versiones en el git, utilizando variables de entorno.

Suponemos que tenemos un git y no queremos exponer las contraseñas, puedes asignar variables de entorno a la versión de git, para después remplazarlas con envsubst, sed u otro, para finalmente desplegar el secret.

apiVersion: v1
kind: Secret
metadata:
  name: mysecret3
type: Opaque
stringData:
  username: $USER
  password: $PASSWORD

remplazar variables y desplegar secret.

# creo variablesexport PASSWORD=contrasena
➜  export USER=jorge

# remplazo variables
➜  envsubst < secrets/secure.yml > tmp.yml

# jemplo final
➜  cat tmp.yml                            
apiVersion: v1
kind: Secret
metadata:
  name: mysecret3
type: Opaque
stringData:
  username: jorge
  password: contrasena

# y desplego con el nuevo yaml
➜ sudo kubectl apply -f tmp.yml
secret/mysecret3 created

➜ sudo kubectl get secret mysecret3 -o yaml
apiVersion: v1
data:
  password: Y29udHJhc2VuYQ==
  username: am9yZ2U=
kind: Secret

Utilizarlos

La manera de poder utilizar los secrets en un contenedor o pod es mediante volumenes o variables de entorno o mediante ambos.

Volumen

En el siguiente yaml estoy incorporando tanto el secret como el pod, no es necesario que estén juntos solo es por visualización.

se muestra como a volumes se le asigna el valor del secret secretName mysecret y este sera montado en la ruta /opt/ con permisos read only.

apiVersion: v1
kind: Secret
metadata:
  name: mysecret
type: Opaque
stringData:
  username: admin
  password: "12345"
---
apiVersion: v1
kind: Pod
metadata:
  name: mypod
spec:
  containers:
  - name: mypod
    image: nginx:alpine
    volumeMounts:
    - name: test
      mountPath: "/opt"
      readOnly: true
  volumes:
  - name: test
    secret:
      secretName: mysecret

una vez desplegado se ve como efectivamente en /opt/ se han montado dos archivos con los valores del secret.

➜ sudo kubectl apply -f secrets/pod-vol-secret.yml 
secret/mysecret created
pod/mypod created

➜ sudo kubectl exec -it mypod -- sh                           
/ # ls /opt/
password  username

items

En los volumenes, si añadimos el valor de items se puede especificar que nombre tendrá el archivo una vez dentro del contenedor.

apiVersion: v1
kind: Pod
metadata:
  name: mypod
spec:
  containers:
  - name: mypod
    image: nginx:alpine
    volumeMounts:
    - name: test
      mountPath: "/opt"
      readOnly: true
  volumes:
  - name: test
    secret:
      secretName: mysecret
      items:
      - key: username
        path: user.txt
      - key: password
        path: pass.txt
➜ sudo kubectl apply -f secrets/pod-vol-secret.yml
secret/mysecret configured
pod/mypod created

➜ sudo kubectl exec -it mypod -- sh
/ # ls /opt/
pass.txt  user.txt

Variables entorno

otra manera de asignar los datos de secret dentro de un pod son con las variables de entorno, donde se asigna cada valor del secret a una variable de entorno. No es necesario asignar todos los valores, si se quiere se puede asignar solo uno o mas.

apiVersion: v1
kind: Secret
metadata:
  name: mysecret
type: Opaque
stringData:
  username: admin
  password: "12345"
---
apiVersion: v1
kind: Pod
metadata:
  name: mypod
spec:
  containers:
  - name: mypod
    image: nginx:alpine
    env:
      - name: SECRET_USER
        valueFrom:
          secretKeyRef:
            name: mysecret
            key: username
      - name: SECRET_PASSWORD
        valueFrom:
          secretKeyRef:
            name: mysecret
            key: password
➜ sudo kubectl apply -f secrets/pod-env-secret.yml 
secret/mysecret configured
pod/mypod created

➜ sudo kubectl exec -it mypod -- sh               
/ # echo $SECRET_USER
admin
/ # echo $SECRET_PASSWORD
12345
/ #