O ABC da seguridade en Kubernetes: autenticación, autorización, auditoría

O ABC da seguridade en Kubernetes: autenticación, autorización, auditoría

Tarde ou cedo, no funcionamento de calquera sistema, xorde a cuestión da seguridade: garantir a autenticación, separación de dereitos, auditoría e outras tarefas. Xa creado para Kubernetes moitas solucións, que permiten acadar o cumprimento dos estándares incluso en ambientes moi esixentes... O mesmo material dedícase aos aspectos básicos de seguridade implementados dentro dos mecanismos integrados dos K8. En primeiro lugar, será útil para aqueles que comezan a familiarizarse con Kubernetes, como punto de partida para estudar problemas relacionados coa seguridade.

Autenticación

Hai dous tipos de usuarios en Kubernetes:

  • Contas de servizo — contas xestionadas pola API de Kubernetes;
  • Usuarios — usuarios “normais” xestionados por servizos externos e independentes.

A principal diferenza entre estes tipos é que para as contas de servizo hai obxectos especiais na API de Kubernetes (chámanse así: ServiceAccounts), que están ligados a un espazo de nomes e a un conxunto de datos de autorización almacenados no clúster en obxectos do tipo Secrets. Estes usuarios (contas de servizo) están destinados principalmente a xestionar os dereitos de acceso á API de Kubernetes dos procesos que se executan no clúster de Kubernetes.

Os usuarios normais non teñen entradas na API de Kubernetes: deben ser xestionadas por mecanismos externos. Están destinados a persoas ou procesos que viven fóra do clúster.

Cada solicitude de API está asociada a unha conta de servizo, a un usuario ou considérase anónima.

Os datos de autenticación do usuario inclúen:

  • Nome de usuario — nome de usuario (sensible a maiúsculas e minúsculas!);
  • UID - unha cadea de identificación de usuario lexible pola máquina que é "máis coherente e única que o nome de usuario";
  • grupos — lista de grupos aos que pertence o usuario;
  • extra — campos adicionais que poden ser utilizados polo mecanismo de autorización.

Kubernetes pode usar unha gran cantidade de mecanismos de autenticación: certificados X509, tokens de portador, proxy de autenticación, autenticación básica HTTP. Usando estes mecanismos, pode implementar un gran número de esquemas de autorización: desde un ficheiro estático con contrasinais ata OpenID OAuth2.

Ademais, é posible utilizar varios esquemas de autorización simultaneamente. Por defecto, o clúster usa:

  • fichas de conta de servizo: para as contas de servizo;
  • X509 - para usuarios.

A pregunta sobre a xestión de ServiceAccounts está fóra do alcance deste artigo, pero para aqueles que queiran familiarizarse con este problema con máis detalle, recoméndolles comezar con páxinas de documentación oficial. Analizaremos máis de cerca o problema de como funcionan os certificados X509.

Certificados para usuarios (X.509)

A forma clásica de traballar cos certificados implica:

  • xeración de claves:
    mkdir -p ~/mynewuser/.certs/
    openssl genrsa -out ~/.certs/mynewuser.key 2048
  • xerando unha solicitude de certificado:
    openssl req -new -key ~/.certs/mynewuser.key -out ~/.certs/mynewuser.csr -subj "/CN=mynewuser/O=company"
  • procesar unha solicitude de certificado utilizando as claves da CA do clúster de Kubernetes, obter un certificado de usuario (para obter un certificado, debes utilizar unha conta que teña acceso á clave da CA do clúster de Kubernetes, que por defecto está situada 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 ficheiro de configuración:
    • descrición do clúster (especifique o enderezo e a localización do ficheiro de certificado de CA para unha 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
    • ou como nonopción recomendada: non tes que especificar o certificado raíz (entón kubectl non comprobará a corrección do servidor api do clúster):
      kubectl config set-cluster kubernetes  --insecure-skip-tls-verify=true --server=https://192.168.100.200:6443
    • engadindo un usuario ao ficheiro de configuración:
      kubectl config set-credentials mynewuser --client-certificate=.certs/mynewuser.crt  --client-key=.certs/mynewuser.key
    • engadindo contexto:
      kubectl config set-context mynewuser-context --cluster=kubernetes --namespace=target-namespace --user=mynewuser
    • asignación de contexto por defecto:
      kubectl config use-context mynewuser-context

Despois das manipulacións anteriores, no ficheiro .kube/config crearase unha 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 a transferencia da configuración entre contas e servidores, é útil editar os valores das seguintes claves:

  • certificate-authority
  • client-certificate
  • client-key

Para iso, pode codificar os ficheiros especificados neles mediante base64 e rexistralos na configuración, engadindo o sufixo ao nome das chaves. -data, é dicir. tendo recibido certificate-authority-data etc

Certificados con kubeadm

Co lanzamento Kubernetes 1.15 traballar con certificados fíxose moito máis sinxelo grazas á versión alfa do seu soporte en utilidade kubeadm. Por exemplo, este é o que agora pode ser xerando un ficheiro de configuración con claves de usuario:

kubeadm alpha kubeconfig user --client-name=mynewuser --apiserver-advertise-address 192.168.100.200

NB: Obrigatorio anunciar enderezo pódese atopar na configuración do servidor api, que por defecto está situada en /etc/kubernetes/manifests/kube-apiserver.yaml.

A configuración resultante enviarase a stdout. Hai que gardar ~/.kube/config conta de usuario ou a un ficheiro especificado nunha variable de ambiente KUBECONFIG.

Cavar máis profundo

Para aqueles que queiran entender os problemas descritos máis a fondo:

Autorización

A conta autorizada predeterminada non ten dereitos para operar no clúster. Para conceder permisos, Kubernetes implementa un mecanismo de autorización.

Antes da versión 1.6, Kubernetes utilizaba un tipo de autorización chamado ABAC (Control de acceso baseado en atributos). Os detalles sobre ela pódense atopar en documentación oficial. Este enfoque actualmente considérase herdado, pero aínda podes utilizalo xunto con outros tipos de autenticación.

A forma actual (e máis flexible) de dividir os dereitos de acceso a un clúster chámase RBAC (Control de acceso baseado en roles). Foi declarado estable desde a versión Kubernetes 1.8. RBAC implementa un modelo de dereitos no que está prohibido todo o que non está expresamente permitido.
Para activar RBAC, cómpre iniciar o servidor api de Kubernetes co parámetro --authorization-mode=RBAC. Os parámetros establécense no manifesto coa configuración do servidor api, que por defecto está situada ao longo da ruta /etc/kubernetes/manifests/kube-apiserver.yaml, na sección command. Non obstante, RBAC xa está activado de forma predeterminada, polo que o máis probable é que non te preocupes por iso: podes verificalo co valor authorization-mode (no xa mencionado kube-apiserver.yaml). Por certo, entre os seus significados pode haber outro tipo de autorización (node, webhook, always allow), pero deixaremos a súa consideración fóra do ámbito do material.

Por certo, xa publicamos un artigo cunha descrición bastante detallada dos principios e características do traballo con RBAC, polo que, ademais, limitareime a unha breve lista dos conceptos básicos e dos exemplos.

As seguintes entidades API úsanse para controlar o acceso en Kubernetes mediante RBAC:

  • Role и ClusterRole — roles que serven para describir dereitos de acceso:
  • Role permítelle describir dereitos dentro dun espazo de nomes;
  • ClusterRole - dentro do clúster, incluídos obxectos específicos do clúster, como nodos, URL que non sexan recursos (é dicir, non relacionados cos recursos de Kubernetes, por exemplo, /version, /logs, /api*);
  • RoleBinding и ClusterRoleBinding - usado para encadernación Role и ClusterRole a un usuario, grupo de usuarios ou ServiceAccount.

As entidades Role e RoleBinding están limitadas polo espazo de nomes, é dicir. debe estar dentro do mesmo espazo de nomes. Non obstante, un RoleBinding pode facer referencia a un ClusterRole, o que lle permite crear un conxunto de permisos xenéricos e controlar o acceso utilizándoos.

Os roles describen dereitos utilizando conxuntos de regras que conteñen:

  • Grupos de API - ver documentación oficial por apiGroups e saída kubectl api-resources;
  • recursos (recursos: pod, namespace, deployment etcétera.);
  • verbos (verbos: set, update etc.).
  • nomes de recursos (resourceNames) - para o caso en que necesites proporcionar acceso a un recurso específico, e non a todos os recursos deste tipo.

Na páxina pódese atopar unha análise máis detallada da autorización en Kubernetes documentación oficial. Pola contra (ou mellor disto, ademais disto), poñerei exemplos que ilustren o seu traballo.

Exemplos de entidades RBAC

Simple Role, que che permite obter unha lista e estado dos pods e supervisalos no espazo de nomes 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"]

Exemplo ClusterRole, que che permite obter unha lista e estado dos pods e supervisalos en todo o clúster:

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  # секции "namespace" нет, так как ClusterRole задействует весь кластер
  name: secret-reader
rules:
- apiGroups: [""]
  resources: ["secrets"]
  verbs: ["get", "watch", "list"]

Exemplo RoleBinding, que permite ao usuario mynewuser "ler" pods no espazo de nomes 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, a arquitectura de Kubernetes pódese representar do seguinte xeito:

O ABC da seguridade en Kubernetes: autenticación, autorización, auditoría

O compoñente clave de Kubernetes responsable de procesar as solicitudes é servidor api. Todas as operacións do clúster pasan por el. Podes ler máis sobre estes mecanismos internos no artigo "Que pasa en Kubernetes cando executas kubectl run?».

A auditoría do sistema é unha función interesante en Kubernetes, que está desactivada por defecto. Permítelle rexistrar todas as chamadas na API de Kubernetes. Como podes adiviñar, todas as accións relacionadas co seguimento e cambio do estado do clúster realízanse a través desta API. Pódese atopar (como de costume) unha boa descrición das súas capacidades en documentación oficial K8s. A continuación, tentarei presentar o tema nunha linguaxe máis sinxela.

Así, para habilitar a auditoría, necesitamos pasar tres parámetros necesarios ao contedor no servidor api, que se describen con máis 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

Ademais destes tres parámetros necesarios, hai moitas opcións adicionais relacionadas coa auditoría: desde a rotación do rexistro ata as descricións dos webhooks. Exemplo de parámetros de rotación do rexistro:

  • --audit-log-maxbackup=10
  • --audit-log-maxsize=100
  • --audit-log-maxage=7

Pero non nos ocuparemos deles con máis detalle: podes atopar todos os detalles en documentación de kube-apserver.

Como xa se mencionou, todos os parámetros están definidos no manifesto coa configuración do servidor api (por defecto /etc/kubernetes/manifests/kube-apiserver.yaml), na sección command. Volvamos aos 3 parámetros necesarios e analízaos:

  1. audit-policy-file — ruta ao ficheiro YAML que describe a política de auditoría. Volveremos ao seu contido máis adiante, pero por agora notarei que o ficheiro debe ser lexible polo proceso do servidor api. Polo tanto, é necesario montalo dentro do contedor, para o que pode engadir o seguinte código ás seccións correspondentes da 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 ao ficheiro de rexistro. O camiño tamén debe ser accesible para o proceso do servidor api, polo que describimos o seu montaxe do mesmo xeito:
      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 rexistro de auditoría. O predeterminado é json, pero o formato de texto herdado tamén está dispoñible (legacy).

Política de auditoría

Agora sobre o ficheiro mencionado que describe a política de rexistro. O primeiro concepto de política de auditoría é level, nivel de rexistro. Son as seguintes:

  • None - non rexistrar;
  • Metadata — metadatos da solicitude de rexistro: usuario, tempo de solicitude, recurso de destino (pod, espazo de nomes, etc.), tipo de acción (verbo), etc.;
  • Request — metadatos de rexistro e corpo da solicitude;
  • RequestResponse — metadatos de rexistro, corpo da solicitude e corpo da resposta.

Os dous últimos niveis (Request и RequestResponse) non rexistra solicitudes que non accederon aos recursos (accesos aos chamados urls que non son recursos).

Tamén todas as solicitudes pasan varias etapas:

  • RequestReceived — a fase na que a solicitude é recibida polo procesador e aínda non foi transmitida máis ao longo da cadea de procesadores;
  • ResponseStarted — envíanse as cabeceiras de resposta, pero antes de enviar o corpo da resposta. Xerado para consultas de longa duración (por exemplo, watch);
  • ResponseComplete — o corpo de resposta foi enviado, non se enviará máis información;
  • Panic — Xéranse eventos cando se detecta unha situación anormal.

Para omitir calquera paso que poida usar omitStages.

Nun ficheiro de políticas, podemos describir varias seccións con diferentes niveis de rexistro. Aplicarase a primeira regra de coincidencia atopada na descrición da política.

O daemon kubelet supervisa os cambios no manifesto coa configuración do servidor api e, se se detecta algún, reinicia o contedor co servidor api. Pero hai un detalle importante: Os cambios no ficheiro de políticas serán ignorados por el. Despois de facer cambios no ficheiro de políticas, terás que reiniciar o servidor api manualmente. Xa que api-server está a executarse como vaina estática, equipo kubectl delete non fará que se reinicie. Terás que facelo manualmente docker stop en kube-masters, onde se cambiou a política de auditoría:

docker stop $(docker ps | grep k8s_kube-apiserver | awk '{print $1}')

Ao habilitar a auditoría, é importante lembralo a carga en kube-apiserver aumenta. En particular, aumenta o consumo de memoria para almacenar o contexto da solicitude. O rexistro comeza só despois de enviar a cabeceira de resposta. A carga tamén depende da configuración da política de auditoría.

Exemplos de políticas

Vexamos a estrutura dos ficheiros de políticas usando exemplos.

Aquí tes un ficheiro sinxelo policypara rexistrar todo no nivel Metadata:

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

Na política pode especificar unha lista de usuarios (Users и ServiceAccounts) e grupos de usuarios. Por exemplo, así é como ignoraremos os usuarios do sistema, pero rexistraremos todo o demais no 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

Tamén é posible describir os obxectivos:

  • espazos de nomes (namespaces);
  • verbos (verbos: get, update, delete e outros);
  • recursos (recursos, a saber: pod, configmaps etc.) e grupos de recursos (apiGroups).

Preste atención! Os recursos e grupos de recursos (grupos API, é dicir, apiGroups), así como as súas versións instaladas no clúster, pódense obter mediante os comandos:

kubectl api-resources
kubectl api-versions

A seguinte política de auditoría ofrécese como unha demostración das mellores prácticas en 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

Outro bo exemplo de política de auditoría é perfil usado en GCE.

Para responder rapidamente aos eventos de auditoría, é posible describir o webhook. Este tema está tratado en documentación oficial, vouno deixar fóra do ámbito deste artigo.

Resultados de

O artigo ofrece unha visión xeral dos mecanismos de seguridade básicos dos clústeres de Kubernetes, que che permiten crear contas de usuario personalizadas, separar os seus dereitos e rexistrar as súas accións. Espero que sexa útil para aqueles que se enfronten a este tipo de problemas na teoría ou na práctica. Tamén recomendo que lea a lista doutros materiais sobre o tema da seguridade en Kubernetes, que se dá en "PS"; quizais entre eles atopes os detalles necesarios sobre os problemas que son relevantes para ti.

PS

Lea tamén no noso blog:

Fonte: www.habr.com

Engadir un comentario