Skip to main content

Pregunta 22 | Análisis Estático Seguridad Manual

(puede resolverse en cualquier contexto kubectl)

El Equipo de Ingeniería de Lanzamiento ha compartido algunos manifiestos YAML y Dockerfiles contigo para revisar. Los archivos están ubicados en /opt/course/22/files.

Como experto en seguridad de contenedores, se te pide realizar un análisis estático manual y encontrar posibles problemas de seguridad con respecto a la exposición no deseada de credenciales. La ejecución de procesos como root no es una preocupación en esta tarea.

Escribe los nombres de archivo que tienen problemas en /opt/course/22/security-issues.

NOTA: En el Dockerfile y los manifiestos YAML, asume que los archivos, carpetas, secretos y montajes de volúmenes referidos están presentes. Ignora errores de sintaxis o lógica.


Respuesta:

Verificamos la ubicación /opt/course/22/files y listamos los archivos.

ls -la /opt/course/22/files
total 48
drwxr-xr-x 2 k8s k8s 4096 Sep 16 19:08 .
drwxr-xr-x 3 k8s k8s 4096 Sep 16 19:08 ..
-rw-r--r-- 1 k8s k8s 692 Sep 16 19:08 Dockerfile-go
-rw-r--r-- 1 k8s k8s 897 Sep 16 19:08 Dockerfile-mysql
-rw-r--r-- 1 k8s k8s 743 Sep 16 19:08 Dockerfile-py
-rw-r--r-- 1 k8s k8s 341 Sep 16 19:08 deployment-nginx.yaml
-rw-r--r-- 1 k8s k8s 705 Sep 16 19:08 deployment-redis.yaml
-rw-r--r-- 1 k8s k8s 392 Sep 16 19:08 pod-nginx.yaml
-rw-r--r-- 1 k8s k8s 228 Sep 16 19:08 pv-manual.yaml
-rw-r--r-- 1 k8s k8s 188 Sep 16 19:08 pvc-manual.yaml
-rw-r--r-- 1 k8s k8s 211 Sep 16 19:08 sc-local.yaml
-rw-r--r-- 1 k8s k8s 902 Sep 16 19:08 statefulset-nginx.yaml

Tenemos 3 Dockerfiles y 7 manifiestos YAML de Recursos de Kubernetes. A continuación debemos revisar cada uno para encontrar problemas de seguridad con la forma en que se han utilizado las credenciales.

NOTA: Deberías sentirte cómodo con las Mejores Prácticas de Docker y las Mejores Prácticas de Configuración de Kubernetes.

Al navegar por los archivos podemos notar:

Número 1

El archivo Dockerfile-mysql podría parecer inocente a primera vista. Copia un archivo secret-token, lo usa y lo elimina después. Pero debido a la forma en que funciona Docker, cada comando RUN, COPY y ADD crea una nueva capa y cada capa persiste en la imagen.

Esto significa que incluso si el archivo secret-token se elimina en la capa Z, todavía está incluido con la imagen en las capas X e Y. En este caso sería mejor usar por ejemplo variables pasadas a Docker.

# /opt/course/22/files/Dockerfile-mysql
FROM ubuntu

# Add MySQL configuration
COPY my.cnf /etc/mysql/conf.d/my.cnf
COPY mysqld_charset.cnf /etc/mysql/conf.d/mysqld_charset.cnf

RUN apt-get update && \
apt-get -yq install mysql-server-5.6 &&

# Add MySQL scripts
COPY import_sql.sh /import_sql.sh
COPY run.sh /run.sh

# Configure credentials
COPY secret-token . # CAPA X
RUN /etc/register.sh ./secret-token # CAPA Y
RUN rm ./secret-token # eliminar secret token nuevamente # CAPA Z

EXPOSE 3306
CMD ["/run.sh"]

Así que hacemos:

echo Dockerfile-mysql >> /opt/course/22/security-issues

Número 2

El archivo deployment-redis.yaml está obteniendo credenciales de un Secret llamado mysecret y escribiéndolas en variables de entorno. Hasta ahí bien, pero en el comando del contenedor está haciendo echo de estas, lo que puede ser leído directamente por cualquier usuario que tenga acceso a los registros.

# /opt/course/22/files/deployment-redis.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
labels:
app: nginx
spec:
replicas: 3
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: mycontainer
image: redis
command: ["/bin/sh"]
args:
- "-c"
- "echo $SECRET_USERNAME && echo $SECRET_PASSWORD && docker-entrypoint.sh" # NO ESTÁ BIEN
env:
- name: SECRET_USERNAME
valueFrom:
secretKeyRef:
name: mysecret
key: username
- name: SECRET_PASSWORD
valueFrom:
secretKeyRef:
name: mysecret
key: password

Las credenciales en registros nunca son una buena idea, por lo tanto hacemos:

echo deployment-redis.yaml >> /opt/course/22/security-issues

Número 3

En el archivo statefulset-nginx.yaml, la contraseña está expuesta directamente en la definición de variable de entorno del contenedor.

# /opt/course/22/files/statefulset-nginx.yaml
...
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: web
spec:
serviceName: "nginx"
replicas: 2
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: k8s.gcr.io/nginx-slim:0.8
env:
- name: Username
value: Administrator
- name: Password
value: MyDiReCtP@sSw0rd # NO ESTÁ BIEN
ports:
- containerPort: 80
name: web
..

Esto debería ser mejor inyectado vía un Secret. Así que hacemos:

echo statefulset-nginx.yaml >> /opt/course/22/security-issues
cat /opt/course/22/security-issues
Dockerfile-mysql
deployment-redis.yaml
statefulset-nginx.yaml