
Tarde o temprano, en la operación de cualquier sistema surge la cuestión de la seguridad: garantizar la autenticación, la separación de privilegios, la auditoría y otras tareas. Para Kubernetes ya se ha creado , que permiten cumplir con los estándares incluso en entornos muy exigentes... Este material se centra en los aspectos fundamentales de la seguridad implementados en los mecanismos integrados de K8s. En primer lugar, será útil para aquellos que están comenzando a familiarizarse con Kubernetes, como un punto de partida para estudiar cuestiones relacionadas con la seguridad.
Autenticación
En Kubernetes, hay dos tipos de usuarios:
- Cuentas de Servicio — cuentas gestionadas por la API de Kubernetes;
- Usuarios — usuarios "normales", gestionados por servicios externos e independientes.
La principal diferencia entre estos tipos es que para las Cuentas de Servicio existen objetos especiales en la API de Kubernetes (que se llaman así — ServiceAccounts), que están vinculados a un espacio de nombres y a un conjunto de credenciales de autorización almacenadas en el clúster en objetos del tipo Secrets. Estos usuarios (Cuentas de Servicio) están destinados principalmente para gestionar los derechos de acceso a la API de Kubernetes de procesos que se ejecutan en el clúster de Kubernetes.
Los usuarios normales, en cambio, no tienen registros en la API de Kubernetes: su gestión debe llevarse a cabo mediante mecanismos externos. Están destinados a personas o procesos que operan fuera del clúster.
Cada solicitud a la API está vinculada ya sea a una Cuenta de Servicio, a un Usuario, o se considera anónima.
Los datos de autenticación del usuario incluyen:
- Nombre de usuario — nombre de usuario (¡sensible a mayúsculas!);
- UID — una cadena de identificación legible por máquina que "es más consistente y única que el nombre de usuario";
- Groups — una lista de grupos a los que pertenece el usuario;
- Extra — campos adicionales que pueden ser utilizados por el mecanismo de autorización.
Kubernetes puede utilizar una gran cantidad de mecanismos de autenticación: certificados X509, tokens Bearer, proxies de autenticación, HTTP Basic Auth. A través de estos mecanismos puedes implementar una gran variedad de esquemas de autorización: desde un archivo estático con contraseñas hasta OpenID OAuth2.
Moreover, the use of multiple authorization schemes is allowed simultaneously. By default, the cluster uses:
- tokens de cuenta de servicio — para Cuentas de Servicio;
- X509 — para Usuarios.
La pregunta sobre la gestión de ServiceAccounts queda fuera del alcance de este artículo, y a quienes deseen profundizar en este tema les recomiendo comenzar con . Sin embargo, aquí examinaremos en detalle el tema de los certificados X509.
Certificados para usuarios (X.509)
El método clásico para trabajar con certificados implica:
- la generación de una clave:
mkdir -p ~/mynewuser/.certs/ openssl genrsa -out ~/.certs/mynewuser.key 2048 - la generación de una solicitud de certificado:
openssl req -new -key ~/.certs/mynewuser.key -out ~/.certs/mynewuser.csr -subj "/CN=mynewuser/O=company" - el procesamiento de la solicitud de certificado mediante las claves del CA del clúster de Kubernetes, obteniendo el certificado del usuario (para obtener el certificado, se debe usar una cuenta que tenga acceso a la clave del centro de certificación del clúster de Kubernetes, que por defecto se encuentra en
/etc/kubernetes/pki/ca.key):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 - la creación de un archivo de configuración:
- una descripción del clúster (especifique la dirección y la ubicación del archivo del certificado CA de la instalación específica del clúster):
kubectl config set-cluster kubernetes --certificate-authority=/etc/kubernetes/pki/ca.crt --server=https://192.168.100.200:6443 - o — como noopción recomendada — se puede omitir el certificado raíz (entonces kubectl no verificará la validez del api-server del clúster):
kubectl config set-cluster kubernetes --insecure-skip-tls-verify=true --server=https://192.168.100.200:6443 - añadiendo el usuario al archivo de configuración:
kubectl config set-credentials mynewuser --client-certificate=.certs/mynewuser.crt --client-key=.certs/mynewuser.key - añadiendo el contexto:
kubectl config set-context mynewuser-context --cluster=kubernetes --namespace=target-namespace --user=mynewuser - estableciendo el contexto por defecto:
kubectl config use-context mynewuser-context
- una descripción del clúster (especifique la dirección y la ubicación del archivo del certificado CA de la instalación específica del clúster):
Después de las manipulaciones anteriores, en el archivo .kube/config se creará un config con el siguiente aspecto:
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.keyPara 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 ello, se pueden codificar los archivos mencionados en base64 y escribirlos en la configuración, añadiendo el sufijo -data, es decir, resultando en certificate-authority-data etc.
Certificados con kubeadm
Con el lanzamiento de El trabajo con certificados se ha vuelto mucho más fácil gracias a la versión alfa de su soporte en . Por ejemplo, así es como puede verse ahora la generación del archivo de configuración con las claves del usuario:
kubeadm alpha kubeconfig user --client-name=mynewuser --apiserver-advertise-address 192.168.100.200 NB: Requerido dirección de publicidad se puede consultar en la configuración del api-server, que por defecto se ubica en /etc/kubernetes/manifests/kube-apiserver.yaml.
La configuración resultante se mostrará en stdout. Debe guardarse en ~/.kube/config la cuenta del usuario o en un archivo especificado en la variable de entorno KUBECONFIG.
Profundizando
Para quienes deseen profundizar más en los temas descritos:
- sobre el trabajo con certificados en la documentación oficial de Kubernetes;
- , que trata el tema de los certificados desde un enfoque práctico.
- sobre la autenticación en Kubernetes.
Autorización
La cuenta autorizada por defecto no tiene derechos de acción en el clúster. Para otorgar permisos en Kubernetes se implementó un mecanismo de autorización.
Hasta la versión 1.6 de Kubernetes, se utilizaba un tipo de autorización llamado ABAC (control de acceso basado en atributos). Los detalles sobre esto se pueden encontrar en . Actualmente, este enfoque se considera obsoleto (legacy), sin embargo, todavía puedes usarlo junto con otros tipos de autorización.
El modo actual (y más flexible) de segmentar los derechos de acceso al clúster se llama RBAC (). Se declaró estable a partir de la versión . RBAC implementa un modelo de derechos en el que se prohíbe todo lo que no esté explícitamente permitido.
Para habilitar RBAC, debes iniciar el api-server de Kubernetes con el parámetro --authorization-mode=RBAC. Los parámetros se establecen en el manifiesto con la configuración del api-server, que por defecto se encuentra en la ruta /etc/kubernetes/manifests/kube-apiserver.yaml, en la sección command. Sin embargo, por defecto, RBAC ya está habilitado, así que probablemente no debas preocuparte por esto: puedes verificarlo por el valor authorization-mode (en el ya mencionado kube-apiserver.yaml). A propósito, entre sus valores también pueden estar otros tipos de autorización (node, webhook, always allow), pero dejaremos su discusión fuera de este material.
A propósito, ya hemos publicado una explicación bastante detallada sobre los principios y características del trabajo con RBAC, así que a continuación me limitaré a enumerar brevemente los fundamentos y ejemplos.
Para gestionar el acceso en Kubernetes a través de RBAC se utilizan las siguientes entidades API:
-
RoleyClusterRole— los roles que se utilizan para describir los derechos de acceso: -
Rolepermite describir derechos dentro del espacio de nombres; -
ClusterRole— dentro del clúster, incluidos objetos específicos del clúster como nodos, URLs no de recursos (es decir, no relacionados con los recursos de Kubernetes — por ejemplo,/version,/logs,/api*); -
RoleBindingyClusterRoleBinding— sirve para vincularRoleyClusterRolea un usuario, grupo de usuarios o ServiceAccount.
Las entidades Role y RoleBinding están limitadas al namespace, es decir, deben estar dentro de un solo espacio de nombres. Sin embargo, RoleBinding puede hacer referencia a ClusterRole, lo que permite crear un conjunto de permisos típicos y gestionar el acceso con ellos.
Los roles describen los derechos mediante conjuntos de reglas que contienen:
- grupos de API — ver por apiGroups y salida
kubectl api-resources; - recursos (resources:
pod,namespace,deploymentetc.); - verbos (verbs:
set,updateetc.). - nombres de recursos (
resourceNames) — en el caso de que sea necesario proporcionar acceso a un recurso específico, y no a todos los recursos de ese tipo.
Una descripción más detallada de la autorización en Kubernetes se puede encontrar en la página . En lugar de esto (más precisamente — además de esto) proporcionaré ejemplos que ilustran su funcionamiento.
Ejemplos de entidades RBAC
Sencillo Role, que permite obtener la lista y el estado de los pod y monitorearlos en el espacio de nombres 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"] Ejemplo ClusterRole, lo que permite obtener la lista y el estado de los pod y monitorearlos en todo el clúster:
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
# no hay sección "namespace", ya que ClusterRole afecta a todo el clúster
name: secret-reader
rules:
- apiGroups: [""]
resources: ["secrets"]
verbs: ["get", "watch", "list"] Ejemplo RoleBinding, lo que permite al usuario mynewuser «leer» pod en el espacio de nombres my-namespace:
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: read-pods
namespace: target-namespace
subjects:
- kind: User
name: mynewuser # nombre de usuario sensible a mayúsculas y minúsculas!
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: Role # aquí debe ser “Role” o “ClusterRole”
name: pod-reader # nombre de Role que está en el mismo namespace,
# o nombre de ClusterRole, cuyo uso
# queremos permitir al usuario
apiGroup: rbac.authorization.k8s.ioAuditar eventos
La arquitectura de Kubernetes se puede representar esquemáticamente de la siguiente manera:

El componente clave de Kubernetes, responsable de procesar las solicitudes, es api-server. Todas las operaciones en el clúster pasan a través de él. Puedes leer más sobre estos mecanismos internos en el artículo «».
La auditoría del sistema es una característica interesante en Kubernetes que está desactivada por defecto. Permite registrar todas las solicitudes al API de Kubernetes. Como se puede adivinar fácilmente, a través de esta API se realizan todas las acciones relacionadas con el control y la modificación del estado del clúster. Una buena descripción de sus capacidades se puede (como suele ser habitual) encontrar en K8s. A continuación, intentaré exponer el tema de manera más sencilla.
Así que, Para habilitar la auditoría, debemos pasar al contenedor en api-server tres parámetros obligatorios, de los cuales se habla con más detalle 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, existen muchas configuraciones adicionales relacionadas con la auditoría: desde la rotación de registros hasta descripciones de webhook. Ejemplo de parámetros de rotación de registros:
-
--audit-log-maxbackup=10 -
--audit-log-maxsize=100 -
--audit-log-maxage=7
Pero no nos detendremos más en ellos: se pueden encontrar todos los detalles en .
Como se mencionó anteriormente, todos los parámetros se configuran en el manifiesto con la configuración del api-server (por defecto /etc/kubernetes/manifests/kube-apiserver.yaml), en la sección command. Volvamos a los 3 parámetros obligatorios y analicémoslos:
-
audit-policy-file— la ruta al archivo YAML que describe la política de auditoría. Volveremos a su contenido más adelante, pero por ahora mencionaré que el archivo debe ser accesible para ser leído por el proceso del api-server. Por lo tanto, es necesario montarlo dentro del contenedor, para lo cual se puede agregar el siguiente código en las secciones correspondientes 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— la ruta al archivo de registro. Esta ruta también debe ser accesible para el proceso del api-server, por lo que describimos su montaje de manera similar:volumeMounts: - mountPath: /var/log/kube-audit name: logs readOnly: false volumes: - hostPath: path: /var/log/kube-audit type: DirectoryOrCreate name: logs -
audit-log-format— el formato del registro de auditoría. Por defecto, esjson., pero también está disponible un formato de texto obsoleto (legacy).
Política de auditoría
Ahora sobre el mencionado archivo que describe la política de registro. El primer concepto de la política de auditoría es level, nivel de registro. Existen los siguientes tipos:
-
None— no registrar; -
Metadata— registrar metadatos de la solicitud: usuario, hora de la solicitud, recurso objetivo (pod, namespace, etc.), tipo de acción (verb) y demás; -
Request— registrar metadatos y el cuerpo de la solicitud; -
RequestResponse— registrar metadatos, el cuerpo de la solicitud y el cuerpo de la respuesta.
Los últimos dos niveles (Request y RequestResponse) no registran solicitudes que no accedieron a los recursos (accesos a URLs no recursos).
Además, todas las solicitudes pasan por varias etapas:
-
RequestReceived— etapa en la que la solicitud es recibida por el manejador y aún no es pasada a la cadena de manejadores; -
ResponseStarted— se han enviado los encabezados de respuesta, pero antes de enviar el cuerpo de la respuesta. Se genera para solicitudes prolongadas (por ejemplo,ver); -
ResponseComplete— el cuerpo de la respuesta ha sido enviado, no se enviará más información; -
Panic— se generan eventos cuando se detecta una situación anómala.
Para omitir alguna etapa se puede usar omitStages.
En el archivo de políticas podemos describir varias secciones con diferentes niveles de registro. Se aplicará la primera regla apropiada encontrada en la descripción de la política.
El demonio kubelet rastrea los cambios en el manifiesto con la configuración del api-server y al detectarlos reinicia el contenedor con el api-server. Pero hay un detalle importante: los cambios en el archivo de política serán ignorados. Después de realizar cambios en el archivo de política, será necesario reiniciar manualmente el api-server. Dado que el api-server se ejecuta como , equipo kubectl delete no llevará a su reinicio. Será necesario ejecutar manualmente docker stop en los kube-masters donde se ha cambiado la política de auditoría:
docker stop $(docker ps | grep k8s_kube-apiserver | awk '{print $1}')Al habilitar la auditoría, es importante recordar que aumenta la carga en el kube-apiserver. En particular, el consumo de memoria para almacenar el contexto de las solicitudes aumenta. El registro en los logs 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 con ejemplos.
Aquí hay un archivo simple policy, para registrar todo a nivel Metadata:
apiVersion: audit.k8s.io/v1
kind: Policy
rules:
- level: Metadata En la política se puede especificar una lista de usuarios (Usuarios y ServiceAccounts) y grupos de usuarios. Por ejemplo, así ignoraremos a los usuarios del sistema, pero registraremos todo lo demás a nivel 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: RequestTambién hay la posibilidad de describir los objetivos:
- espacios de nombres (
namespaces); - verbos (verbs:
get,update,deletey otros); - recursos (resources, a saber:
pod,configmapsetc.) y grupos de recursos (apiGroups).
¡Atención! Los recursos y grupos de recursos (grupos API, es decir, apiGroups), así como sus versiones disponibles en el clúster, se pueden obtener mediante los comandos:
kubectl api-resources
kubectl api-versionsLa siguiente política de auditoría se presenta como una demostración de las mejores prácticas en :
apiVersion: audit.k8s.io/v1beta1
kind: Policy
# No registrar la etapa RequestReceived
omitStages:
- "RequestReceived"
rules:
# No registrar eventos que se consideren poco significativos y no peligrosos:
- level: None
users: ["system:kube-proxy"]
verbs: ["watch"]
resources:
- group: "" # este es el grupo API con un nombre vacío, al que pertenecen
# los recursos básicos de Kubernetes, llamados “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"]
# No registrar accesos a URLs de solo lectura:
- level: None
nonResourceURLs:
- /healthz*
- /version
- /swagger*
# No registrar mensajes relacionados con el tipo de recurso “eventos”:
- level: None
resources:
- group: "" # core
resources: ["events"]
# Los recursos de tipo Secret, ConfigMap y TokenReview pueden contener datos secretos,
# por lo tanto, solo registramos los metadatos de las solicitudes relacionadas con ellos
- level: Metadata
resources:
- group: "" # core
resources: ["secrets", "configmaps"]
- group: authentication.k8s.io
resources: ["tokenreviews"]
# Las acciones de tipo get, list y watch pueden ser intensivas en recursos; no las registramos
- 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"
# Nivel de registro predeterminado para los recursos estándar de la 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"
# Nivel de registro predeterminado para todas las demás solicitudes
- level: MetadataOtro buen ejemplo de política de auditoría — .
Para la respuesta rápida a los eventos de auditoría hay posibilidad de describir un webhook. Este tema se detalla en , lo dejaré fuera del alcance de este artículo.
Resultados
El artículo ofrece una visión general de los mecanismos básicos de seguridad en clústeres de Kubernetes, que permiten crear cuentas personalizadas para los usuarios, dividir sus derechos y registrar sus acciones. Espero que sea útil para quienes se han enfrentado a tales cuestiones en teoría o en la práctica. También recomiendo consultar la lista de otros materiales sobre el tema de la seguridad en Kubernetes, que se presenta en el «P.S.», ya que es posible que encuentren detalles necesarios para los problemas que les preocupan.
P.D.
También puedes leer en nuestro blog:
- «»;
- «»;
- «»;
- «»;
- «».
Fuente: habr.com
