Seguridad en kubernetes: SecurityContextConstraints en Openshift 4.11
OpenShift permite a los desarrolladores crear, implementar y administrar aplicaciones en contenedores de manera eficiente y escalable. Sin embargo, al trabajar con contenedores, es importante tener en cuenta la seguridad y la protección del sistema operativo subyacente.
En un artículo anterior, hablamos de seccomProfile como mecanismo de seguridad del kernel Linux con restricciones de llamadas al sistema. Hoy abordamos otro componente para mejorar la seguridad de nuestros contenedores en Openshift: los objetos SSC (SecurityContextConstraints).
¿Qué es SecurityContextConstraints?
SecurityContextConstraints (SCC) es una funcionalidad de OpenShift que permite definir políticas de seguridad para los contenedores que se ejecutan en la plataforma.
SCC permite a los administradores de la plataforma controlar los privilegios de los contenedores, limitando el acceso a ciertas acciones desde el contenedor que podrían comprometer la seguridad de la plataforma o de los datos de usuario.
OpenShift implementa un conjunto de SCC predefinidos, que se pueden utilizar como base para definir políticas personalizadas. Los SCC predefinidos más usados son:
- restricted: proporciona un entorno seguro para ejecutar contenedores, con restricciones en las llamadas de sistema, en la capacidad de montar sistemas de archivos y en la capacidad de utilizar privilegios.
- anyuid: permite a los contenedores ejecutarse con el ID de usuario 0, lo que significa que pueden tener acceso a todo el sistema de archivos y a todos los recursos del sistema, manteniendo el resto de restricciones por defecto del namespace y del seccomProfile definido.
- nonroot: este SCC permite a los contenedores ejecutarse sin privilegios de root, evitando realizar acciones que requieren privilegios de superusuario.
No obstante, si los SSC predefinidos no se adaptan a nuestras necesidades, podemos definir un objeto con la configuración personalizada que necesitamos. Veamos un ejemplo de uso:
Creamos el proyecto y un serviceAccount para asociarlo a nuestros deployments:
oc new-project my-project-custom-scc
oc create sa my-service-account-custom-scc
Creamos la política SCC personalizada:
oc apply -f - <<EOF
kind: SecurityContextConstraints
apiVersion: security.openshift.io/v1
metadata:
name: custom-scc
allowPrivilegedContainer: false
allowHostDirVolumePlugin: false
allowHostIPC: false
allowHostNetwork: false
allowHostPID: false
allowHostPorts: false
allowPrivilegeEscalation: false
allowPrivilegeContainer: false
readOnlyRootFilesystem: true
runAsUser:
type: MustRunAsNonRoot
seLinuxContext:
type: MustRunAs
seLinuxOptions:
level: s0:c123,c456
role: system_r
type: container_t
user: system_u
EOF
Esta política de SCC “custom-scc” restringe el acceso a los recursos del sistema y no permite que los contenedores se ejecuten con privilegios. También se especifica que el contenedor debe ejecutarse como un usuario no root y debe tener un contexto SELinux específico.
Permitimos al serviceAccount creado utilizar la política SCC:
oc adm policy add-scc-to-user -n my-project-custom-scc -z my-service-account-custom-scc custom-scc
Creamos un Role asociado a nuestra SCC:
oc create -f - <<EOF
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: my-role-custom-scc
namespace: my-project-custom-scc
rules:
- apiGroups:
- security.openshift.io
resourceNames:
- custom-scc
resources:
- securitycontextconstraints
verbs:
- use
EOF
Y un RoleBinding para asociar el Role anterior a nuestro serviceAccount:
oc create -f - <<EOF
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: my-rb-custom-scc
namespace: my-project-custom-scc
subjects:
- kind: ServiceAccount
name: my-service-account-custom-scc
roleRef:
kind: Role
name: my-role-custom-scc
apiGroup: rbac.authorization.k8s.io
EOF
Por último, asociamos a nuestro deployment el serviceAccount configurado y restringido:
oc apply -f - <<EOF
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-deployment-custom-scc
namespace: my-project-custom-scc
spec:
replicas: 1
selector:
matchLabels:
app: my-app-custom-scc
template:
metadata:
labels:
app: my-app-custom-scc
spec:
serviceAccount: my-service-account-custom-scc
serviceAccountName: my-service-account-custom-scc
containers:
- name: my-container
image: my-image
ports:
- containerPort: 8080
EOF
Si todo ha ido bien, podemos comprobar como el pod configurado desde el deployment tiene aplicada la política SSC personalizada:
$ oc get pods -l deployment -o "custom-columns=NAME:.metadata.name,SCC:.metadata.annotations.openshift\.io/scc,SERVICEACCOUNT:.spec.serviceAccountName"
NAME SCC SERVICEACCOUNT
my-deployment-custom-scc-xuttxr custom-scc my-service-account-custom-scc