El ABC de la seguridad en Kubernetes: autenticación, autorización, auditoría

El ABC de la seguridad en Kubernetes: autenticación, autorización, auditoría

Tarde o temprano, en el funcionamiento de cualquier sistema, surge la cuestión de la seguridad: garantizar la autenticación, la separación de derechos, la auditoría y otras tareas. Ya creado para Kubernetes muchas soluciones, que le permiten lograr el cumplimiento de los estándares incluso en entornos muy exigentes... El mismo material está dedicado a los aspectos básicos de la seguridad implementada dentro de los mecanismos integrados de los K8. En primer lugar, será útil para quienes están empezando a familiarizarse con Kubernetes, como punto de partida para estudiar cuestiones relacionadas con la seguridad.

Autentificación

Hay dos tipos de usuarios en Kubernetes:

  • 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 hay objetos especiales en la API de Kubernetes (se llaman así: ServiceAccounts), que están vinculados a un espacio de nombres y un conjunto de datos de autorización almacenados en el clúster en objetos del tipo Secretos. Dichos usuarios (Cuentas de servicio) están destinados principalmente a administrar los derechos de acceso a la API de Kubernetes de los procesos que se ejecutan en el clúster de Kubernetes.

Los usuarios comunes 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 de API está asociada con una Cuenta de Servicio, un Usuario o se considera anónima.

Los datos de autenticación del usuario incluyen:

  • Usuario - nombre de usuario (¡distingue entre mayúsculas y minúsculas!);
  • UID - una cadena de identificación de usuario legible por máquina que es “más consistente y única que el nombre de usuario”;
  • Grupos — 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 de portador, proxy de autenticación, autenticación básica HTTP. Con estos mecanismos, puede implementar una gran cantidad de esquemas de autorización: desde un archivo estático con contraseñas hasta OpenID OAuth2.

Además, es posible utilizar varios sistemas de autorización simultáneamente. De forma predeterminada, el clúster utiliza:

  • tokens de cuenta de servicio - para Cuentas de Servicio;
  • X509 - para usuarios.

La pregunta sobre la administración de ServiceAccounts está fuera del alcance de este artículo, pero para aquellos que quieran familiarizarse con este tema con más detalle, recomiendo comenzar con páginas de documentación oficial. Analizaremos más de cerca la cuestión de cómo funcionan los certificados X509.

Certificados para usuarios (X.509)

La forma clásica de trabajar con certificados implica:

  • generación de claves:
    mkdir -p ~/mynewuser/.certs/
    openssl genrsa -out ~/.certs/mynewuser.key 2048
  • generando una solicitud de certificado:
    openssl req -new -key ~/.certs/mynewuser.key -out ~/.certs/mynewuser.csr -subj "/CN=mynewuser/O=company"
  • procesar una solicitud de certificado utilizando las claves de CA del clúster de Kubernetes, obtener un certificado de usuario (para obtener un certificado, debe usar una cuenta que tenga acceso a la clave de CA del clúster de Kubernetes, que de forma predeterminada 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
  • creando un archivo de configuración:
    • descripción del clúster (especifique la dirección y ubicación del archivo de certificado de CA para una instalación de clúster específica):
      kubectl config set-cluster kubernetes --certificate-authority=/etc/kubernetes/pki/ca.crt --server=https://192.168.100.200:6443
    • o como noopción recomendada: no es necesario especificar el certificado raíz (entonces kubectl no comprobará la exactitud del servidor API del clúster):
      kubectl config set-cluster kubernetes  --insecure-skip-tls-verify=true --server=https://192.168.100.200:6443
    • agregando 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, en el archivo. .kube/config Se creará una configuración como esta:

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 especificados en ellos usando base64 y registrarlos en la configuración agregando el sufijo al nombre de las claves. -data, es decir. habiendo recibido certificate-authority-data etcétera

Certificados con kubeadm

con el lanzamiento Kubernetes 1.15 trabajar con certificados se ha vuelto mucho más fácil gracias a la versión alfa de su soporte en utilidad kubeadm. Por ejemplo, así es como se vería 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: Requerido anunciar dirección se puede encontrar en la configuración del servidor api, que de forma predeterminada se encuentra en /etc/kubernetes/manifests/kube-apiserver.yaml.

La configuración resultante se enviará a la salida estándar. Necesita ser guardado en ~/.kube/config cuenta de usuario o a un archivo especificado en una variable de entorno KUBECONFIG.

Excavar más hondo

Para aquellos que quieran comprender más a fondo los problemas descritos:

Autorización

La cuenta autorizada predeterminada no tiene derechos para operar en el clúster. Para otorgar permisos, Kubernetes implementa un mecanismo de autorización.

Antes de la versión 1.6, Kubernetes usaba un tipo de autorización llamado ABAC (Control de acceso basado en atributos). Los detalles al respecto se pueden encontrar en documentación oficial. Actualmente, este enfoque se considera heredado, pero aún puede usarlo junto con otros tipos de autenticación.

La forma actual (y más flexible) de dividir los derechos de acceso a un clúster se llama RBAC (Control de acceso basado en roles). Ha sido declarado estable desde la versión. Kubernetes 1.8. RBAC implementa un modelo de derechos en el que todo lo que no esté explícitamente permitido está prohibido.
Para habilitar RBAC, debe iniciar el servidor api de Kubernetes con el parámetro --authorization-mode=RBAC. Los parámetros se establecen en el manifiesto con la configuración del servidor api, que de forma predeterminada se encuentra a lo largo de la ruta /etc/kubernetes/manifests/kube-apiserver.yaml, en la sección command. Sin embargo, RBAC ya está habilitado de forma predeterminada, por lo que lo más probable es que no debas preocuparte por eso: puedes verificar esto mediante el valor authorization-mode (en el ya mencionado kube-apiserver.yaml). Por cierto, entre sus acepciones puede haber otros tipos de autorización (node, webhook, always allow), pero dejaremos su consideración fuera del alcance del material.

Por cierto, ya hemos publicado Artículo con una descripción bastante detallada de 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 en Kubernetes a través de RBAC:

  • Role и ClusterRole — roles que sirven para describir los derechos de acceso:
  • Role le permite describir derechos dentro de un espacio de nombres;
  • ClusterRole - dentro del clúster, incluidos objetos específicos del clúster, como nodos, URL que no son de recursos (es decir, no relacionados con los recursos de Kubernetes; por ejemplo, /version, /logs, /api*);
  • RoleBinding и ClusterRoleBinding - usado para encuadernar Role и ClusterRole a un usuario, grupo de usuarios o cuenta de servicio.

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, un RoleBinding puede hacer referencia a un ClusterRole, lo que le permite crear un conjunto de permisos genéricos y controlar el acceso usándolos.

Los roles describen derechos utilizando conjuntos de reglas que contienen:

  • Grupos de API - ver documentación oficial por apiGroups y salida kubectl api-resources;
  • recursos (digitales: pod, namespace, deployment etcétera.);
  • Verbos (los verbos: set, update etc.).
  • nombres de los recursos (resourceNames) - para el caso en el que necesite proporcionar acceso a un recurso específico y no a todos los recursos de este tipo.

Puede encontrar un análisis más detallado de la autorización en Kubernetes en la página documentación oficial. En lugar de ello (o mejor dicho, además de esto), daré ejemplos que ilustran su trabajo.

Ejemplos de entidades RBAC

Simple Role, que le permite obtener una lista y el estado de los pods 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, 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: secret-reader
rules:
- apiGroups: [""]
  resources: ["secrets"]
  verbs: ["get", "watch", "list"]

ejemplo RoleBinding, que permite al usuario mynewuser "leer" pods 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 # имя пользователя зависимо от регистра!
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: Role # здесь должно быть “Role” или “ClusterRole”
  name: pod-reader # имя Role, что находится в том же namespace,
                   # или имя ClusterRole, использование которой
                   # хотим разрешить пользователю
  apiGroup: rbac.authorization.k8s.io

Auditoría de eventos

Esquemáticamente, la arquitectura de Kubernetes se puede representar de la siguiente manera:

El ABC de la seguridad en Kubernetes: autenticación, autorización, auditoría

El componente clave de Kubernetes responsable de procesar las solicitudes es api-servidor. Todas las operaciones en el clúster pasan por él. Puedes leer más sobre estos mecanismos internos en el artículo “¿Qué sucede en Kubernetes cuando ejecutas kubectl run?".

La auditoría del sistema es una característica interesante de Kubernetes, que está deshabilitada de forma predeterminada. Le permite registrar todas las llamadas a la API de Kubernetes. Como puede imaginar, todas las acciones relacionadas con el monitoreo y el cambio del estado del clúster se realizan a través de esta API. Una buena descripción de sus capacidades se puede encontrar (como es habitual) en documentación oficial K8. A continuación intentaré presentar el tema en un lenguaje más sencillo.

Por lo tanto, para permitir la auditoría, necesitamos pasar tres parámetros requeridos al contenedor en api-server, que se describen 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 webhooks. 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 en ellos con más detalle; puede encontrar todos los detalles en 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 command. Volvamos a los 3 parámetros requeridos y analicémoslos:

  1. audit-policy-file — ruta al archivo YAML que describe la política de auditoría. Volveremos a su contenido más adelante, pero por ahora señalaré que el archivo debe ser legible por el proceso api-server. Por lo tanto, es necesario montarlo dentro del contenedor, para lo cual puedes agregar el siguiente código a 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
  2. audit-log-path — ruta al archivo de registro. La ruta también debe ser accesible para el proceso api-server, por lo que describimos su montaje de la misma manera:
      volumeMounts:
        - mountPath: /var/log/kube-audit
          name: logs
          readOnly: false
      volumes:
      - hostPath:
          path: /var/log/kube-audit
          type: DirectoryOrCreate
        name: logs
  3. audit-log-format — formato de registro de auditoría. El valor predeterminado es json, pero el formato de texto heredado también está disponible (legacy).

Política de auditoría

Ahora sobre el archivo mencionado que describe la política de registro. El primer concepto de política de auditoría es level, nivel de registro. Son los siguientes:

  • None - no iniciar sesión;
  • Metadata — registrar metadatos de solicitud: usuario, hora de solicitud, recurso de destino (pod, espacio de nombres, etc.), tipo de acción (verbo), etc.;
  • Request — registrar metadatos y cuerpo de solicitud;
  • RequestResponse – registrar metadatos, cuerpo de solicitud y cuerpo de respuesta.

Los dos últimos niveles (Request и RequestResponse) no registra solicitudes que no accedieron a recursos (accesos a las llamadas URL que no son de recursos).

También todas las solicitudes pasan varias etapas:

  • RequestReceived — la etapa en la que el procesador recibe la solicitud y aún no se ha transmitido a lo largo de la cadena de procesadores;
  • ResponseStarted — se envían los encabezados de respuesta, pero antes de enviar el cuerpo de la respuesta. Generado para consultas de larga duración (por ejemplo, watch);
  • ResponseComplete — se ha enviado el cuerpo de la respuesta, no se enviará más información;
  • Panic — los eventos se generan cuando se detecta una situación anormal.

Para omitir cualquier paso, puede usar omitStages.

En un archivo de política, podemos describir varias secciones con diferentes niveles de registro. Se aplicará la primera regla coincidente que se encuentre en la descripción de la política.

El demonio kubelet monitorea los cambios en el 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: Los cambios en el archivo de política serán ignorados por este.. Después de realizar cambios en el archivo de política, deberá reiniciar el servidor API manualmente. Dado que api-server se inicia como vaina estática, equipo kubectl delete no hará que se reinicie. Tendrás que hacerlo manualmente. docker stop en 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 la carga en kube-apiserver aumenta. En particular, aumenta el consumo de memoria para almacenar el contexto de la solicitud. El registro comienza solo después de enviar el encabezado de respuesta. La carga también depende de la configuración de la política de auditoría.

Ejemplos de políticas

Veamos la estructura de los archivos de políticas usando ejemplos.

Aquí hay un archivo simple. policypara registrar todo en el nivel Metadata:

apiVersion: audit.k8s.io/v1
kind: Policy
rules:
- level: Metadata

En la política puede especificar una lista de usuarios (Users и ServiceAccounts) y grupos de usuarios. Por ejemplo, así es como ignoraremos a los usuarios del sistema, pero registraremos todo lo demás en el 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: Request

También es posible describir los objetivos:

  • espacios de nombres (namespaces);
  • Verbos (los verbos: get, update, delete y otros);
  • recursos (digitales, Como sigue: pod, configmaps etc.) y grupos de recursos (apiGroups).

Preste atención! Los recursos y grupos de recursos (grupos de API, es decir, apiGroups), así como sus versiones instaladas en el clúster, se pueden obtener usando 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 Documentación de la nube de Alibaba:

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 perfil utilizado en GCE.

Para responder rápidamente a los eventos de auditoría, es posible describir el webhook. Este tema se trata en documentación oficial, lo dejaré fuera del alcance de este artículo.

resultados

El artículo proporciona una descripción general de los mecanismos de seguridad básicos en los clústeres de Kubernetes, que le permiten crear cuentas de usuario personalizadas, separar sus derechos y registrar sus acciones. Espero que sea útil para quienes se enfrentan a este tipo de problemas en la teoría o en la práctica. También le recomiendo que lea la lista de otros materiales sobre el tema de la seguridad en Kubernetes, que se encuentra en “PS”; tal vez entre ellos encuentre los detalles necesarios sobre los problemas que son relevantes para usted.

PS

Lea también en nuestro blog:

Fuente: habr.com

Añadir un comentario