O ABC da segurança no Kubernetes: autenticação, autorização, auditoria

O ABC da segurança no Kubernetes: autenticação, autorização, auditoria

Mais cedo ou mais tarde, no funcionamento de qualquer sistema, surge a questão da segurança: garantia de autenticação, separação de direitos, auditoria e outras tarefas. Já criado para Kubernetes muitas soluções, que permitem atingir a conformidade com os padrões mesmo em ambientes muito exigentes... O mesmo material é dedicado aos aspectos básicos de segurança implementados nos mecanismos integrados dos K8s. Em primeiro lugar, será útil para quem está começando a se familiarizar com o Kubernetes - como ponto de partida para estudar questões relacionadas à segurança.

Autenticação

Existem dois tipos de usuários no Kubernetes:

  • Contas de serviço — contas gerenciadas pela API Kubernetes;
  • Utilizadores — utilizadores “normais” geridos por serviços externos e independentes.

A principal diferença entre esses tipos é que para contas de serviço existem objetos especiais na API do Kubernetes (eles são chamados assim - ServiceAccounts), que estão vinculados a um namespace e a um conjunto de dados de autorização armazenados no cluster em objetos do tipo Secrets. Esses usuários (contas de serviço) destinam-se principalmente a gerenciar direitos de acesso à API Kubernetes de processos em execução no cluster Kubernetes.

Usuários comuns não possuem entradas na API Kubernetes: eles devem ser gerenciados por mecanismos externos. Destinam-se a pessoas ou processos que vivem fora do cluster.

Cada solicitação de API está associada a uma conta de serviço, a um usuário ou é considerada anônima.

Os dados de autenticação do usuário incluem:

  • Nome de Utilizador — nome de usuário (diferencia maiúsculas de minúsculas!);
  • UID - uma cadeia de identificação de usuário legível por máquina que seja “mais consistente e exclusiva que o nome de usuário”;
  • Grupos — lista de grupos aos quais o usuário pertence;
  • Extra — campos adicionais que podem ser usados ​​pelo mecanismo de autorização.

Kubernetes pode usar um grande número de mecanismos de autenticação: certificados X509, tokens de portador, proxy de autenticação, autenticação básica HTTP. Usando esses mecanismos, você pode implementar um grande número de esquemas de autorização: desde um arquivo estático com senhas até OpenID OAuth2.

Além disso, é possível utilizar vários regimes de autorização simultaneamente. Por padrão, o cluster usa:

  • tokens de conta de serviço – para contas de serviço;
  • X509 - para usuários.

A questão sobre como gerenciar ServiceAccounts está além do escopo deste artigo, mas para quem deseja se familiarizar com esse assunto com mais detalhes, recomendo começar com páginas de documentação oficial. Examinaremos mais de perto a questão de como funcionam os certificados X509.

Certificados para usuários (X.509)

A forma clássica de trabalhar com certificados envolve:

  • geração de chaves:
    mkdir -p ~/mynewuser/.certs/
    openssl genrsa -out ~/.certs/mynewuser.key 2048
  • gerando uma solicitação de certificado:
    openssl req -new -key ~/.certs/mynewuser.key -out ~/.certs/mynewuser.csr -subj "/CN=mynewuser/O=company"
  • processar uma solicitação de certificado usando as chaves CA do cluster Kubernetes, obter um certificado de usuário (para obter um certificado, você deve usar uma conta que tenha acesso à chave CA do cluster Kubernetes, que por padrão está localizada em /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
  • criando um arquivo de configuração:
    • descrição do cluster (especifique o endereço e o local do arquivo de certificado CA para uma instalação de cluster específica):
      kubectl config set-cluster kubernetes --certificate-authority=/etc/kubernetes/pki/ca.crt --server=https://192.168.100.200:6443
    • ou como nãoopção recomendada - você não precisa especificar o certificado raiz (então o kubectl não verificará a exatidão do servidor API do cluster):
      kubectl config set-cluster kubernetes  --insecure-skip-tls-verify=true --server=https://192.168.100.200:6443
    • adicionando um usuário ao arquivo de configuração:
      kubectl config set-credentials mynewuser --client-certificate=.certs/mynewuser.crt  --client-key=.certs/mynewuser.key
    • adicionando contexto:
      kubectl config set-context mynewuser-context --cluster=kubernetes --namespace=target-namespace --user=mynewuser
    • atribuição de contexto padrão:
      kubectl config use-context mynewuser-context

Após as manipulações acima, no arquivo .kube/config uma configuração como esta será criada:

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 transferência da configuração entre contas e servidores, é útil editar os valores das seguintes chaves:

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

Para fazer isso, você pode codificar os arquivos neles especificados usando base64 e registrá-los na configuração adicionando um sufixo ao nome das chaves -data, ou seja tendo recebido certificate-authority-data и т.п.

Certificados com kubeadm

Com o lançamento Kubernetes 1.15 trabalhar com certificados ficou muito mais fácil graças à versão alfa de seu suporte em utilitário kubeadm. Por exemplo, a geração de um arquivo de configuração com chaves de usuário pode ser assim:

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

NB: Obrigatório anunciar endereço pode ser encontrado na configuração do api-server, que por padrão está localizado em /etc/kubernetes/manifests/kube-apiserver.yaml.

A configuração resultante será enviada para stdout. Precisa ser salvo em ~/.kube/config conta de usuário ou para um arquivo especificado em uma variável de ambiente KUBECONFIG.

Vá mais fundo

Para aqueles que desejam entender as questões descritas mais detalhadamente:

Autorização

A conta autorizada padrão não tem direitos para operar no cluster. Para conceder permissões, o Kubernetes implementa um mecanismo de autorização.

Antes da versão 1.6, o Kubernetes usava um tipo de autorização chamado ABAC (Controle de acesso baseado em atributos). Detalhes sobre isso podem ser encontrados em documentação oficial. Atualmente, essa abordagem é considerada legada, mas você ainda pode usá-la junto com outros tipos de autenticação.

A forma atual (e mais flexível) de dividir os direitos de acesso a um cluster é chamada RBAC (Controle de acesso baseado em função). Foi declarado estável desde a versão Kubernetes 1.8. O RBAC implementa um modelo de direitos em que tudo o que não é explicitamente permitido é proibido.
Para ativar o RBAC, você precisa iniciar o api-server do Kubernetes com o parâmetro --authorization-mode=RBAC. Os parâmetros são definidos no manifesto com a configuração do api-server, que por padrão está localizada ao longo do caminho /etc/kubernetes/manifests/kube-apiserver.yaml, na seção command. No entanto, o RBAC já está habilitado por padrão, então provavelmente você não deve se preocupar com isso: você pode verificar isso pelo valor authorization-mode (no já mencionado kube-apiserver.yaml). Aliás, entre seus significados podem existir outros tipos de autorização (node, webhook, always allow), mas deixaremos sua consideração fora do escopo do material.

Aliás, já publicamos статью com uma descrição bastante detalhada dos princípios e características do trabalho com o RBAC, então me limitarei a uma breve lista de princípios básicos e exemplos.

As seguintes entidades API são usadas para controlar o acesso no Kubernetes via RBAC:

  • Role и ClusterRole — funções que servem para descrever direitos de acesso:
  • Role permite descrever direitos dentro de um namespace;
  • ClusterRole - dentro do cluster, inclusive para objetos específicos do cluster, como nós, URLs que não são de recursos (ou seja, não relacionados aos recursos do Kubernetes - por exemplo, /version, /logs, /api*);
  • RoleBinding и ClusterRoleBinding - usado para encadernação Role и ClusterRole para um usuário, grupo de usuários ou ServiceAccount.

As entidades Role e RoleBinding são limitadas por namespace, ou seja, deve estar dentro do mesmo namespace. No entanto, um RoleBinding pode fazer referência a um ClusterRole, que permite criar um conjunto de permissões genéricas e controlar o acesso usando-as.

As funções descrevem direitos usando conjuntos de regras contendo:

  • Grupos de API - consulte documentação oficial por apiGroups e saída kubectl api-resources;
  • recursos (recursos: pod, namespace, deployment e assim por diante.);
  • Verbos (verbos: set, update etc.)
  • nomes de recursos (resourceNames) - para o caso em que você precisa fornecer acesso a um recurso específico, e não a todos os recursos desse tipo.

Uma análise mais detalhada da autorização no Kubernetes pode ser encontrada na página documentação oficial. Em vez disso (ou melhor, além disso), darei exemplos que ilustram o seu trabalho.

Exemplos de entidades RBAC

Simples Role, que permite obter uma lista e o status dos pods e monitorá-los no namespace 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 permite obter uma lista e o status dos pods e monitorá-los em todo o cluster:

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 usuário mynewuser pods "ler" no namespace 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 evento

Esquematicamente, a arquitetura Kubernetes pode ser representada da seguinte forma:

O ABC da segurança no Kubernetes: autenticação, autorização, auditoria

O principal componente do Kubernetes responsável pelo processamento de solicitações é servidor API. Todas as operações no cluster passam por ele. Você pode ler mais sobre esses mecanismos internos no artigo “O que acontece no Kubernetes quando você executa o kubectl run?".

A auditoria do sistema é um recurso interessante do Kubernetes, que está desabilitado por padrão. Ele permite registrar todas as chamadas para a API Kubernetes. Como você pode imaginar, todas as ações relacionadas ao monitoramento e alteração do estado do cluster são realizadas por meio desta API. Uma boa descrição de suas capacidades pode (como sempre) ser encontrada em documentação oficial K8. A seguir, tentarei apresentar o tema em uma linguagem mais simples.

Assim, para permitir a auditoria, precisamos passar três parâmetros obrigatórios para o contêiner no api-server, que são descritos com mais detalhes abaixo:

  • --audit-policy-file=/etc/kubernetes/policies/audit-policy.yaml
  • --audit-log-path=/var/log/kube-audit/audit.log
  • --audit-log-format=json

Além desses três parâmetros necessários, há muitas configurações adicionais relacionadas à auditoria: desde rotação de log até descrições de webhook. Exemplo de parâmetros de rotação de log:

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

Mas não vamos nos debruçar sobre eles com mais detalhes - você pode encontrar todos os detalhes em documentação do kube-apiserver.

Como já mencionado, todos os parâmetros são definidos no manifesto com a configuração do api-server (por padrão /etc/kubernetes/manifests/kube-apiserver.yaml), na seção command. Vamos voltar aos 3 parâmetros necessários e analisá-los:

  1. audit-policy-file — caminho para o arquivo YAML que descreve a política de auditoria. Voltaremos ao seu conteúdo mais tarde, mas por enquanto observarei que o arquivo deve ser legível pelo processo api-server. Portanto, é necessário montá-lo dentro do container, para o qual você pode adicionar o seguinte código às seções apropriadas da configuração:
      volumeMounts:
        - mountPath: /etc/kubernetes/policies
          name: policies
          readOnly: true
      volumes:
      - hostPath:
          path: /etc/kubernetes/policies
          type: DirectoryOrCreate
        name: policies
  2. audit-log-path — caminho para o arquivo de log. O caminho também deve ser acessível ao processo api-server, por isso descrevemos sua montagem da mesma forma:
      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 auditoria. O padrão é json, mas o formato de texto legado também está disponível (legacy).

Política de auditoria

Agora, sobre o arquivo mencionado que descreve a política de log. O primeiro conceito de política de auditoria é level, nível de registro. Eles são os seguintes:

  • None - não registre;
  • Metadata — metadados de solicitação de log: usuário, hora da solicitação, recurso de destino (pod, namespace, etc.), tipo de ação (verbo), etc.;
  • Request — registrar metadados e corpo da solicitação;
  • RequestResponse — registrar metadados, corpo da solicitação e corpo da resposta.

Os dois últimos níveis (Request и RequestResponse) não registram solicitações que não acessaram recursos (acessos aos chamados URLs que não são de recursos).

Além disso, todas as solicitações passam várias etapas:

  • RequestReceived — a fase em que o pedido é recebido pelo processador e ainda não foi transmitido ao longo da cadeia de processadores;
  • ResponseStarted — os cabeçalhos de resposta são enviados, mas antes do corpo da resposta ser enviado. Gerado para consultas de longa duração (por exemplo, watch);
  • ResponseComplete — o corpo da resposta foi enviado, não serão enviadas mais informações;
  • Panic — os eventos são gerados quando uma situação anormal é detectada.

Para pular qualquer etapa que você possa usar omitStages.

Em um arquivo de política, podemos descrever diversas seções com diferentes níveis de registro. A primeira regra correspondente encontrada na descrição da política será aplicada.

O daemon kubelet monitora alterações no manifesto com a configuração do api-server e, se alguma for detectada, reinicia o contêiner com o api-server. Mas há um detalhe importante: alterações no arquivo de políticas serão ignoradas por ele. Depois de fazer alterações no arquivo de políticas, você precisará reiniciar o api-server manualmente. Como o api-server é iniciado como pod estático, equipe kubectl delete não fará com que ele reinicie. Você terá que fazer isso manualmente docker stop no kube-masters, onde a política de auditoria foi alterada:

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

Ao habilitar a auditoria, é importante lembrar que a carga no kube-apiserver aumenta. Em particular, o consumo de memória para armazenar o contexto da solicitação aumenta. O registro em log começa somente após o envio do cabeçalho de resposta. A carga também depende da configuração da política de auditoria.

Exemplos de políticas

Vejamos a estrutura dos arquivos de políticas usando exemplos.

Aqui está um arquivo simples policypara registrar tudo no nível Metadata:

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

Na política você pode especificar uma lista de usuários (Users и ServiceAccounts) e grupos de usuários. Por exemplo, é assim que ignoraremos os usuários do sistema, mas registraremos todo o resto no nível 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

Também é possível descrever os alvos:

  • espaços para nome (namespaces);
  • Verbos (verbos: get, update, delete e outros);
  • recursos (recursos, Como segue: pod, configmaps etc.) e grupos de recursos (apiGroups).

Preste atenção! Recursos e grupos de recursos (grupos de API, ou seja, apiGroups), bem como suas versões instaladas no cluster, podem ser obtidos usando os comandos:

kubectl api-resources
kubectl api-versions

A seguinte política de auditoria é fornecida como uma demonstração das melhores práticas em Documentação do 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 bom exemplo de política de auditoria é perfil usado no GCE.

Para responder rapidamente aos eventos de auditoria, é possível descrever o webhook. Esta questão é abordada em documentação oficial, deixarei isso fora do escopo deste artigo.

Resultados de

O artigo fornece uma visão geral dos mecanismos básicos de segurança em clusters Kubernetes, que permitem criar contas de usuário personalizadas, separar seus direitos e registrar suas ações. Espero que seja útil para aqueles que enfrentam tais questões na teoria ou na prática. Recomendo também que você leia a lista de outros materiais sobre o tema segurança no Kubernetes, que se encontra em “PS” - talvez entre eles você encontre os detalhes necessários sobre os problemas que são relevantes para você.

PS

Leia também em nosso blog:

Fonte: habr.com

Adicionar um comentário