Pregunta 42 | CKS Challenge 2 - Seguridad Multi-Entorno
Ten en cuenta que el estado de competición para los Desafíos CKS ha terminado. Por favor no envíes una solución. No será puntuada.
Se han desplegado varias aplicaciones en los namespaces dev, staging y prod. Hay algunos problemas de seguridad con estas aplicaciones.
Inspecciona los problemas en detalle haciendo clic en los iconos del diagrama de arquitectura interactivo en el laboratorio y completa las tareas para asegurar las aplicaciones. Una vez hecho, haz clic en el botón Check para validar tu trabajo.
Realiza las tareas en este orden:
dockerfile
- Ejecutar como no root (en su lugar, usar el usuario de aplicación correcto)
- Evitar exponer puertos innecesarios
- Evitar copiar el
Dockerfiley otros archivos y directorios innecesarios en la imagen. Mueve los archivos y directorios requeridos (app.py, requirements.txt y el directorio templates) a un subdirectorio llamadoappbajowebappy actualiza la instrucción COPY en elDockerfileen consecuencia. - Una vez que se corrijan los problemas de seguridad, reconstruye esta imagen localmente con la etiqueta
kodekloud/webapp-color:stable
Las primeras dos subtareas implican limpiar el Dockerfile...
cd /root/webapp
vi Dockerfile
Cambia el Dockerfile así:
Se nos pide mover la aplicación al subdirectorio app, así que cambia la instrucción COPY en anticipación a esto
COPY ./app /opt
Ejecutar como no root
Se ha creado un usuario con RUN adduser -D worker, pero no estamos cambiando a él, sino que estamos cambiando a root.
Cambia la línea USER root a USER worker
Evitar exponer puertos innecesarios. No necesitamos el puerto 22 (SSH) para la aplicación, así que elimina las siguientes líneas
## Expose port 22
EXPOSE 22
Ahora guarda y sal de vi
Mueve la aplicación y archivos relacionados a un nuevo subdirectorio app
mkdir app
mv app.py app/
mv requirements.txt app/
mv templates app/
Reconstruir imagen
docker build -t kodekloud/webapp-color:stable .
Volver al directorio home
cd ~
kubesec
- Corrige problemas con el archivo
/root/dev-webapp.yamlque se usó para desplegar el poddev-webappen el namespacedev. - Redesplegar el pod
dev-webappuna vez que los problemas se corrijan con la imagenkodekloud/webapp-color:stable - Corrige problemas con el archivo
/root/staging-webapp.yamlque se usó para desplegar el podstaging-webappen el namespacestaging. - Redesplegar el pod
staging-webappuna vez que los problemas se corrijan con la imagenkodekloud/webapp-color:stable
Al ejecutar kubesec podemos usar jq para extraer la parte de la salida JSON que es relevante para identificar problemas críticos con el manifiesto escaneado. Ejecuta sin | jq y todo después para ver el informe completo.
dev-webapp.yaml
kubesec scan /root/dev-webapp.yaml | jq '.[] | .scoring.critical'
Nota que CapSysAdmin y AllowPrivilegeEscalation están señalados.
Edita el manifiesto:
- Elimina la capacidad
SYS_ADMIN - Establece
allowPrivilegeEscalationafalse - Establece la imagen del contenedor a
kodekloud/webapp-color:stable(que construimos anteriormente)
No recrees el pod aún. Hay más que hacer en la siguiente etapa.
staging-webapp.yaml
kubesec scan /root/dev-webapp.yaml | jq '.[] | .scoring.critical'
Nota que esto tiene exactamente los mismos problemas que dev-webapp.yaml. Realiza exactamente los mismos pasos que para staging-webapp.yaml.
dev-webapp
Asegúrate de que el pod dev-webapp sea inmutable:
- Se puede acceder a este pod usando el comando
kubectl exec. Queremos asegurarnos de que esto no suceda. Usa una startupProbe para eliminar todos los shells antes del inicio del contenedor. UsainitialDelaySecondsyperiodSecondsde5. Pista: ¡Para que esto funcione tendrías que ejecutar el contenedor como root! - Imagen usada:
kodekloud/webapp-color:stable(Ya hemos hecho esto arriba) - Redesplegar el pod según las recomendaciones anteriores y asegurarse de que la aplicación esté funcionando.
Verifica qué shells están presentes en el contenedor - los comandos de shell se encuentran en el directorio /bin y usualmente terminan con sh, por ejemplo sh mismo, bash, etc.
kubectl exec -n dev dev-webapp -- ls /bin | grep sh
Salida:
fdflush no es un shell, pero los otros dos sí. ash es un shell normalmente empaquetado con Alpine Linux.
Crea una startup probe según la especificación, y asegúrate de que la startup probe pueda ejecutarse como root. Ten en cuenta que las probes no se ven afectadas por el comando USER en el Dockerfile.
Edita dev-webapp.yaml
Añade lo siguiente bajo securityContext, si no está ya ahí
runAsUser: 0
Inserta la probe
startupProbe:
exec:
command:
- rm
- /bin/sh
- /bin/ash
initialDelaySeconds: 5
periodSeconds: 5
Ahora recrea el pod en ejecución con todo lo que cambiamos en el paso 2 y este paso
kubectl replace -f dev-webapp.yaml --force
staging-webapp
Asegúrate de que el pod dev-webapp sea inmutable:
- Se puede acceder a este pod usando el comando
kubectl exec. Queremos asegurarnos de que esto no suceda. Usa una startupProbe para eliminar todos los shells antes del inicio del contenedor. UsainitialDelaySecondsyperiodSecondsde5. Pista: ¡Para que esto funcione tendrías que ejecutar el contenedor como root! - Imagen usada:
kodekloud/webapp-color:stable(Ya hemos hecho esto arriba) - Redesplegar el pod según las recomendaciones anteriores y asegurarse de que la aplicación esté funcionando.
Sigue los mismos pasos que para dev-webapp arriba, ajusta staging-webapp.yaml y recrea el pod.
prod-web
- El deployment tiene un secret codificado. En su lugar, crea un secret llamado
prod-dbpara todos los valores codificados y consume los valores del secret como variables de entorno dentro del deployment.
Examina el manifiesto del deployment para ver cuál es este secret
kubectl get deployment -n prod prod-web -o yaml
Podemos ver que hay 3 variables de entorno con valores.
Crea un secret para estas vars
kubectl create secret generic prod-db -n prod \
--from-literal DB_Host=prod-db \
--from-literal DB_User=root \
--from-literal DB_Password=paswrd
Edita el deployment y cambia la sección env para obtener los valores del secret
kubectl edit deployment -n prod prod-web
Reemplaza las variables bajo el bloque env con
- name: DB_User
valueFrom:
secretKeyRef:
key: DB_User
name: prod-db
- name: DB_Host
valueFrom:
secretKeyRef:
key: DB_Host
name: prod-db
- name: DB_Password
valueFrom:
secretKeyRef:
key: DB_Password
name: prod-db
Prueba esto presionando el botón prod-web arriba del terminal. Después de aplicar la network policy a continuación, esto ya no funcionará
prod-netpol
- Usa una network policy llamada
prod-netpolque solo permitirá tráfico dentro del namespaceprod. Todo el tráfico desde otros namespaces debe ser denegado.
Ten en cuenta que todos los namespaces tienen una etiqueta predefinida kubernetes.io/metadata.name que es muy útil al crear network policies restringidas a namespace.
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: prod-netpol
namespace: prod
spec:
podSelector: {} # aplicar a todos los pods en el namespace prod
policyTypes:
- Ingress
ingress:
- from:
- podSelector: {} # cualquier pod...
namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: prod # ...que esté solo en el namespace prod
Una vez que se completen todas las tareas anteriores, haz clic en el botón Check.