
Tarde o temprano, el funcionamiento de cualquier sistema plantea la cuestión de la seguridad: garantizar la autenticación, la separación de derechos, la auditoría y otras tareas. Ya se han creado
muchas soluciones para Kubernetes que pueden lograr el cumplimiento de las normas incluso en entornos muy exigentes ... El mismo material está dedicado a los aspectos básicos de seguridad implementados en el marco de los mecanismos integrados de K8. En primer lugar, será útil para aquellos que comienzan a familiarizarse con Kubernetes, como punto de partida para estudiar problemas de seguridad.
Autenticación
Kubernetes tiene dos tipos de usuarios:
- Cuentas de servicio : cuentas administradas por la API de Kubernetes;
- Usuarios : usuarios "normales" controlados por servicios externos e independientes.
La principal diferencia entre estos tipos es que para las Cuentas de servicio hay objetos especiales en la API de Kubernetes (se llaman Cuentas de servicio) que están vinculados a un espacio de nombres y a un conjunto de datos de autorización almacenados en un clúster en objetos de tipo Secretos. Dichos usuarios (Cuentas de servicio) están destinados principalmente a administrar los derechos de acceso a los procesos API de Kubernetes que se ejecutan en un clúster de Kubernetes.
Los usuarios ordinarios no tienen entradas en la API de Kubernetes: deben ser administrados por mecanismos externos. Están destinados a personas o procesos que viven fuera del clúster.
Cada solicitud a la API está vinculada a la cuenta de servicio o al usuario, o se considera anónima.
Los datos de autenticación del usuario incluyen:
- Nombre de usuario - nombre de usuario (mayúsculas y minúsculas);
- UID es una cadena de identificación de usuario legible por máquina que es "más coherente y única que el nombre de usuario";
- Grupos : una lista de grupos a los que pertenece el usuario;
- Extra : campos adicionales que puede utilizar el mecanismo de autorización.
Kubernetes puede utilizar una gran cantidad de mecanismos de autenticación: certificados X509, tokens de portador, proxies de autenticación, autenticación básica HTTP. Con estos mecanismos, se puede implementar una gran cantidad de esquemas de autorización: desde un archivo estático con contraseñas hasta OpenID OAuth2.
Además, se permiten múltiples esquemas de autorización al mismo tiempo. Por defecto, el clúster usa:
- tokens de cuenta de servicio - para Cuentas de servicio;
- X509 - para usuarios.
La pregunta sobre la administración de ServiceAccounts está más allá del alcance de este artículo, pero recomiendo comenzar a aprender más sobre este tema en la
página de documentación oficial . Consideraremos con más detalle el tema del trabajo de los certificados X509.
Certificados para usuarios (X.509)
La forma clásica de trabajar con certificados implica:
- generación clave:
mkdir -p ~/mynewuser/.certs/ openssl genrsa -out ~/.certs/mynewuser.key 2048
- generación de solicitud de certificado:
openssl req -new -key ~/.certs/mynewuser.key -out ~/.certs/mynewuser.csr -subj "/CN=mynewuser/O=company"
- procesando la solicitud de certificado utilizando las claves de CA del clúster de Kubernetes, obteniendo un certificado de usuario (para obtener un certificado, debe usar una cuenta que tenga acceso a la clave de autoridad de certificado del clúster de Kubernetes, que se encuentra en
/etc/kubernetes/pki/ca.key
de forma predeterminada):
openssl x509 -req -in ~/.certs/mynewuser.csr -CA /etc/kubernetes/pki/ca.crt -CAkey /etc/kubernetes/pki/ca.key -CAcreateserial -out ~/.certs/mynewuser.crt -days 500
- creando un archivo de configuración:
- Descripción del clúster (especifique la dirección y ubicación del archivo de certificado de CA de la instalación particular del clúster):
kubectl config set-cluster kubernetes --certificate-authority=/etc/kubernetes/pki/ca.crt --server=https://192.168.100.200:6443
- o, si no es la opción recomendada, puede omitir el certificado raíz (entonces kubectl no verificará la corrección del clúster del servidor api):
kubectl config set-cluster kubernetes --insecure-skip-tls-verify=true --server=https://192.168.100.200:6443
- Agregar un usuario al archivo de configuración:
kubectl config set-credentials mynewuser --client-certificate=.certs/mynewuser.crt --client-key=.certs/mynewuser.key
- agregando contexto:
kubectl config set-context mynewuser-context --cluster=kubernetes --namespace=target-namespace --user=mynewuser
- asignación de contexto predeterminada:
kubectl config use-context mynewuser-context
Después de las manipulaciones anteriores, se creará una configuración del formulario en el archivo
.kube/config
:
apiVersion: v1 clusters: - cluster: certificate-authority: /etc/kubernetes/pki/ca.crt server: https://192.168.100.200:6443 name: kubernetes contexts: - context: cluster: kubernetes namespace: target-namespace user: mynewuser name: mynewuser-context current-context: mynewuser-context kind: Config preferences: {} users: - name: mynewuser user: client-certificate: /home/mynewuser/.certs/mynewuser.crt client-key: /home/mynewuser/.certs/mynewuser.key
Para facilitar la transferencia de la configuración entre cuentas y servidores, es útil editar los valores de las siguientes claves:
certificate-authority
client-certificate
client-key
Para hacer esto, puede codificar los archivos indicados en ellos usando base64 y registrarlos en la configuración agregando el sufijo
-data
al nombre de las claves, es decir. obtener
certificate-authority-data
, etc.
Certificados con kubeadm
Con el lanzamiento de
Kubernetes 1.15, trabajar con certificados se ha vuelto mucho más fácil gracias a la versión alfa de su soporte en
la utilidad kubeadm . Por ejemplo, así es como puede verse ahora la generación de un archivo de configuración con claves de usuario:
kubeadm alpha kubeconfig user --client-name=mynewuser --apiserver-advertise-address 192.168.100.200
NB : la dirección de publicidad requerida se puede ver en la configuración del servidor api, que se encuentra en /etc/kubernetes/manifests/kube-apiserver.yaml
de forma predeterminada.La configuración resultante se enviará a stdout. Debe guardarse en
~/.kube/config
cuenta de usuario o en el archivo especificado en la
KUBECONFIG
entorno
KUBECONFIG
.
Cavar más profundo
Para aquellos que desean comprender a fondo los problemas descritos:
Iniciar sesión
Una cuenta autenticada no tiene permiso para actuar en un clúster de forma predeterminada. Kubernetes tiene un mecanismo de autorización para otorgar permisos.
Antes de la versión 1.6, Kubernetes usaba un tipo de autenticación llamado
ABAC (control de acceso basado en atributos). Los detalles al respecto se pueden encontrar en la
documentación oficial . Actualmente, este enfoque se considera heredado, pero aún puede usarlo al mismo tiempo que otros tipos de autorización.
La forma real (y más flexible) de dividir los derechos de acceso al clúster se denomina
RBAC (
control de acceso basado en roles ). Se ha declarado estable desde
Kubernetes 1.8 . RBAC implementa un modelo de derechos que prohíbe todo lo que no esté explícitamente permitido.
Para habilitar RBAC , debe ejecutar el servidor de API Kubernetes con la
--authorization-mode=RBAC
. Los parámetros se establecen en el manifiesto con la configuración del servidor api, que por defecto se encuentra en la ruta
/etc/kubernetes/manifests/kube-apiserver.yaml
, en la sección de
command
. Sin embargo, RBAC ya está habilitado de forma predeterminada, por lo que probablemente no debería preocuparse por esto: puede verificar esto mediante el valor del
authorization-mode
de
authorization-mode
(en el ya mencionado
kube-apiserver.yaml
). Por cierto, entre sus valores puede haber otros tipos de autorización (
node
,
webhook
,
always allow
), pero los dejaremos fuera del alcance del material.
Por cierto, ya hemos publicado
un artículo con una historia bastante detallada sobre los principios y características de trabajar con RBAC, por lo que me limitaré a una breve lista de los conceptos básicos y ejemplos.
Las siguientes entidades API se utilizan para controlar el acceso a Kubernetes a través de RBAC:
Role
y ClusterRole
son roles que describen privilegios:Role
permite describir los derechos dentro de un espacio de nombres;ClusterRole
: dentro del clúster, incluidos los objetos específicos del clúster, como nodos, URL que no son recursos (es decir, no están relacionados con los recursos de Kubernetes, por ejemplo, /version
, /logs
, /api*
);RoleBinding
y ClusterRoleBinding
: sirve para vincular Role
y ClusterRole
a un usuario, grupo de usuarios o ServiceAccount.
Las entidades Role y RoleBinding están limitadas por el espacio de nombres, es decir debe estar dentro del mismo espacio de nombres. Sin embargo, RoleBinding puede referirse a ClusterRole, que le permite crear un conjunto de permisos estándar y controlar el acceso con ellos.
Los roles describen derechos utilizando conjuntos de reglas que contienen:
- Grupos de API: consulte la documentación oficial de apiGroups y la salida de
kubectl api-resources
; - recursos ( recursos :
pod
, namespace
, deployment
, etc.); - verbos ( verbos :
set
, update
, etc.). - nombres de recursos (
resourceNames
): para el caso en que necesita proporcionar acceso a un recurso específico y no a todos los recursos de este tipo.
Puede encontrar una discusión más detallada sobre la autorización en Kubernetes en la página de
documentación oficial . En cambio (o más bien, además de esto) daré ejemplos que ilustran su trabajo.
Ejemplos de entidades RBAC
Un
Role
simple que le permite obtener la lista y el estado de los pods y monitorearlos en el
target-namespace
:
apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: namespace: target-namespace name: pod-reader rules: - apiGroups: [""] resources: ["pods"] verbs: ["get", "watch", "list"]
Un ejemplo de
ClusterRole
, que le permite obtener una lista y el estado de los pods y monitorearlos en todo el clúster:
apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: # "namespace" , ClusterRole name: pod-reader rules: - apiGroups: [""] resources: ["pods"] verbs: ["get", "watch", "list"]
Ejemplo
RoleBinding
, que permite al usuario
mynewuser
"leer" pods en el
my-namespace
:
apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: name: read-pods namespace: target-namespace subjects: - kind: User name: mynewuser # ! apiGroup: rbac.authorization.k8s.io roleRef: kind: Role # “Role” “ClusterRole” name: pod-reader # Role, namespace, # ClusterRole, # apiGroup: rbac.authorization.k8s.io
Auditoria de eventos
Esquemáticamente, la arquitectura de Kubernetes se puede representar de la siguiente manera:

El componente clave de Kubernetes, que se encarga de procesar las solicitudes, es
api-server . Todas las operaciones en el clúster pasan a través de él. Lea más sobre estos mecanismos internos en el artículo "
¿Qué sucede en Kubernetes cuando comienza la ejecución de kubectl? ".
La auditoría del sistema es una característica interesante en Kubernetes, que está desactivada de forma predeterminada. Le permite registrar todas las llamadas a la API de Kubernetes. Como puede adivinar fácilmente, a través de esta API se realizan todas las acciones relacionadas con la supervisión y el cambio del estado del clúster. Una buena descripción de sus características se puede encontrar (como de costumbre) en la
documentación oficial de K8. A continuación, intentaré presentar el tema en un lenguaje más simple.
Entonces,
para habilitar la auditoría , necesitamos pasar tres parámetros requeridos al contenedor en el servidor api, más sobre el cual se describe a continuación:
--audit-policy-file=/etc/kubernetes/policies/audit-policy.yaml
--audit-log-path=/var/log/kube-audit/audit.log
--audit-log-format=json
Además de estos tres parámetros necesarios, hay muchas configuraciones adicionales relacionadas con la auditoría: desde la rotación de registros hasta las descripciones de webhook. Parámetros de rotación de registro de ejemplo:
--audit-log-maxbackup=10
--audit-log-maxsize=100
--audit-log-maxage=7
Pero no nos detendremos en ellos con más detalle: puede encontrar todos los detalles en la
documentación de kube-apiserver .
Como ya se mencionó, todos los parámetros se establecen en el manifiesto con la configuración del servidor api (por defecto
/etc/kubernetes/manifests/kube-apiserver.yaml
), en la sección de
command
. Volvamos a los 3 parámetros requeridos y analícelos:
audit-policy-file
: ruta al archivo YAML con la descripción de la política de auditoría. Volveremos a su contenido, pero por ahora noto que el archivo debe ser accesible para que el proceso api-server pueda leerlo. Por lo tanto, es necesario montarlo dentro del contenedor, para lo cual puede agregar el siguiente código a las secciones apropiadas de la configuración:
volumeMounts: - mountPath: /etc/kubernetes/policies name: policies readOnly: true volumes: - hostPath: path: /etc/kubernetes/policies type: DirectoryOrCreate name: policies
audit-log-path
: ruta al archivo de registro. La ruta también debe ser accesible para el proceso del servidor api, por lo tanto, describimos de manera similar su montaje:
volumeMounts: - mountPath: /var/log/kube-audit name: logs readOnly: false volumes: - hostPath: path: /var/log/kube-audit type: DirectoryOrCreate name: logs
audit-log-format
: formato del registro de auditoría. Por defecto, esto es json
, pero el formato de texto heredado también está disponible.
Política de auditoría
Ahora sobre el archivo mencionado con la descripción de la política de registro. El primer concepto de política de auditoría es el
level
, el
nivel de registro . Son los siguientes:
None
: no inicie sesión;Metadata
: metadatos de solicitud de registro: usuario, tiempo de solicitud, recurso de destino (pod, espacio de nombres, etc.), tipo de acción (verbo), etc.Request
: registrar metadatos y cuerpo de solicitud;RequestResponse
: RequestResponse
metadatos, cuerpo de solicitud y cuerpo de respuesta.
Los dos últimos niveles (
Request
y
RequestResponse
) no registran las solicitudes que no tuvieron acceso a los recursos (llamadas a las llamadas URL sin recursos).
Además, todas las solicitudes pasan por
varias etapas :
RequestReceived
: la etapa en la que el controlador recibe la solicitud y aún no se ha transferido a lo largo de la cadena de controladores;ResponseStarted
: encabezados de respuesta enviados, pero antes de enviar el cuerpo de respuesta. Generado para consultas largas (por ejemplo, watch
);ResponseComplete
- cuerpo de respuesta enviado, no se enviará más información;Panic
: los eventos se generan cuando se detecta una emergencia.
Puede usar
omitStages
para omitir cualquier etapa.
En el archivo de políticas, podemos describir varias secciones con diferentes niveles de registro. Se aplicará la primera regla coincidente encontrada en la descripción de la política.
El demonio kubelet monitorea el cambio de manifiesto con la configuración del servidor api y, si se detecta alguno, reinicia el contenedor con el servidor api. Pero hay un detalle importante:
ignorarán los cambios en el archivo de políticas . Después de realizar cambios en el archivo de políticas, deberá reiniciar api-server manualmente. Dado que api-server se ejecuta como un
pod estático , el
kubectl delete
no lo reiniciará. Tendrá que hacer que
docker stop
manualmente en kube-masters donde se ha cambiado la política de auditoría:
docker stop $(docker ps | grep k8s_kube-apiserver | awk '{print $1}')
Cuando habilita la auditoría, es importante recordar que
kube-apiserver tiene una carga más alta . En particular, el consumo de memoria para almacenar el contexto de las solicitudes está aumentando. El registro comienza solo después de enviar el encabezado de respuesta. Además, la carga depende de la configuración de la política de auditoría.
Ejemplos de políticas
Analicemos la estructura de los archivos de políticas utilizando ejemplos.
Aquí hay un archivo de
policy
simple para registrar todo en el nivel de
Metadata
:
apiVersion: audit.k8s.io/v1 kind: Policy rules: - level: Metadata
Puede especificar una lista de usuarios (
Users
y
ServiceAccounts
) y grupos de usuarios en la política. Por ejemplo, así es como ignoraremos a los usuarios del sistema, pero registraremos todo lo demás en el nivel de
Request
:
apiVersion: audit.k8s.io/v1 kind: Policy rules: - level: None userGroups: - "system:serviceaccounts" - "system:nodes" users: - "system:anonymous" - "system:apiserver" - "system:kube-controller-manager" - "system:kube-scheduler" - level: Request
También es posible describir el objetivo:
namespaces
- verbos ( verbos :
get
, update
, delete
y otros); - recursos ( recursos , a saber:
pod
, configmaps
, etc.) y grupos de recursos ( apiGroups
).
¡Presta atención! Los recursos y grupos de recursos (grupos API, es decir, apiGroups), así como sus versiones instaladas en el clúster, se pueden obtener mediante los comandos:
kubectl api-resources kubectl api-versions
La siguiente política de auditoría se proporciona como una demostración de las mejores prácticas en la
documentación de Alibaba Cloud :
apiVersion: audit.k8s.io/v1beta1 kind: Policy # RequestReceived omitStages: - "RequestReceived" rules: # , : - level: None users: ["system:kube-proxy"] verbs: ["watch"] resources: - group: "" # api group , # Kubernetes, “core” resources: ["endpoints", "services"] - level: None users: ["system:unsecured"] namespaces: ["kube-system"] verbs: ["get"] resources: - group: "" # core resources: ["configmaps"] - level: None users: ["kubelet"] verbs: ["get"] resources: - group: "" # core resources: ["nodes"] - level: None userGroups: ["system:nodes"] verbs: ["get"] resources: - group: "" # core resources: ["nodes"] - level: None users: - system:kube-controller-manager - system:kube-scheduler - system:serviceaccount:kube-system:endpoint-controller verbs: ["get", "update"] namespaces: ["kube-system"] resources: - group: "" # core resources: ["endpoints"] - level: None users: ["system:apiserver"] verbs: ["get"] resources: - group: "" # core resources: ["namespaces"] # read-only URLs: - level: None nonResourceURLs: - /healthz* - /version - /swagger* # , “”: - level: None resources: - group: "" # core resources: ["events"] # Secret, ConfigMap TokenReview , # - level: Metadata resources: - group: "" # core resources: ["secrets", "configmaps"] - group: authentication.k8s.io resources: ["tokenreviews"] # get, list watch ; - level: Request verbs: ["get", "list", "watch"] resources: - group: "" # core - group: "admissionregistration.k8s.io" - group: "apps" - group: "authentication.k8s.io" - group: "authorization.k8s.io" - group: "autoscaling" - group: "batch" - group: "certificates.k8s.io" - group: "extensions" - group: "networking.k8s.io" - group: "policy" - group: "rbac.authorization.k8s.io" - group: "settings.k8s.io" - group: "storage.k8s.io" # API - level: RequestResponse resources: - group: "" # core - group: "admissionregistration.k8s.io" - group: "apps" - group: "authentication.k8s.io" - group: "authorization.k8s.io" - group: "autoscaling" - group: "batch" - group: "certificates.k8s.io" - group: "extensions" - group: "networking.k8s.io" - group: "policy" - group: "rbac.authorization.k8s.io" - group: "settings.k8s.io" - group: "storage.k8s.io" # - level: Metadata
Otro buen ejemplo de política de auditoría es el
perfil utilizado en GCE .
Para una respuesta rápida a los eventos de auditoría, es posible
describir un webhook . Este problema se revela en la
documentación oficial , lo dejaré fuera del alcance de este artículo.
Resumen
El artículo proporciona una descripción general de los mecanismos básicos de seguridad en los grupos de Kubernetes que le permiten crear cuentas de usuario personalizadas, compartir sus derechos y registrar sus acciones. Espero que sea útil para aquellos que enfrentan tales preguntas en teoría o ya en la práctica. También le recomiendo que consulte la lista de otros materiales sobre el tema de la seguridad en Kubernetes, que se encuentra en el "PS", tal vez entre ellos encontrará los detalles necesarios sobre temas que son relevantes para usted.
PS
Lea también en nuestro blog: