
Cedo ou tarde, a operação de qualquer sistema levanta a questão da segurança: garantir autenticação, separação de direitos, auditoria e outras tarefas.
Muitas soluções já foram criadas para o Kubernetes que podem alcançar a conformidade com os padrões, mesmo em ambientes muito exigentes ... O mesmo material é dedicado aos aspectos básicos de segurança implementados na estrutura dos mecanismos internos do K8s. Antes de tudo, será útil para quem começa a se familiarizar com o Kubernetes, como ponto de partida para o estudo de problemas de segurança.
Autenticação
O Kubernetes possui dois tipos de usuários:
- Contas de serviço - contas gerenciadas pela API Kubernetes;
- Usuários - usuários "normais" controlados por serviços externos independentes.
A principal diferença entre esses tipos é que, para Contas de Serviço, existem objetos especiais na API do Kubernetes (chamados
ServiceAccounts
) que estão vinculados ao espaço para nome e ao conjunto de dados de autorização armazenados no cluster em objetos do tipo Segredos. Esses usuários (contas de serviço) destinam-se principalmente ao gerenciamento de direitos de acesso aos processos da API Kubernetes em execução em um cluster Kubernetes.
Usuários comuns não têm entradas na API do Kubernetes: eles devem ser gerenciados por mecanismos externos. Eles são destinados a pessoas ou processos que vivem fora do cluster.
Cada solicitação para a API está vinculada à conta de serviço ou ao usuário ou é considerada anônima.
Os dados de autenticação do usuário incluem:
- Nome de usuário - 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 é "mais consistente e exclusiva que o nome de usuário";
- Grupos - uma lista de grupos aos quais o usuário pertence;
- Campos extras - adicionais que podem ser usados pelo mecanismo de autorização.
O Kubernetes pode usar um grande número de mecanismos de autenticação: certificados X509, tokens do portador, proxies de autenticação, autenticação básica HTTP. Usando esses mecanismos, um grande número de esquemas de autorização pode ser implementado: de um arquivo estático com senhas ao OpenID OAuth2.
Além disso, vários esquemas de autorização são permitidos ao mesmo tempo. Por padrão, o cluster usa:
- tokens de conta de serviço - para contas de serviço;
- X509 - para usuários.
A pergunta sobre o gerenciamento de ServiceAccounts está além do escopo deste artigo, mas recomendo começar a aprender mais sobre esse problema na
página de documentação oficial . Consideraremos mais detalhadamente a questão do trabalho dos certificados X509.
Certificados para usuários (X.509)
A maneira clássica de trabalhar com certificados envolve:
- geração de chaves:
mkdir -p ~/mynewuser/.certs/ openssl genrsa -out ~/.certs/mynewuser.key 2048
- geração de solicitação de certificado:
openssl req -new -key ~/.certs/mynewuser.key -out ~/.certs/mynewuser.csr -subj "/CN=mynewuser/O=company"
- processando a solicitação de certificado usando chaves CA do cluster Kubernetes, obtendo um certificado de usuário (para obter um certificado, você precisa usar uma conta que tenha acesso à chave de autoridade de certificação do cluster Kubernetes, localizada em
/etc/kubernetes/pki/ca.key
por padrão):
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 da CA da instalação específica do cluster):
kubectl config set-cluster kubernetes --certificate-authority=/etc/kubernetes/pki/ca.crt --server=https://192.168.100.200:6443
- ou - se não for a opção recomendada - você pode omitir o certificado raiz (o kubectl não verificará a exatidão do cluster da api-server):
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, uma configuração do formulário será criada no arquivo
.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 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 indicados neles usando base64 e registrá-los na configuração adicionando o sufixo
-data
ao nome das chaves, ou seja, obtendo
certificate-authority-data
etc.
Certificados com kubeadm
Com o lançamento do
Kubernetes 1.15, o trabalho com certificados tornou-se muito mais fácil, graças à versão alfa de seu suporte no
utilitário kubeadm . Por exemplo, eis a aparência da geração de um arquivo de configuração com chaves de usuário agora:
kubeadm alpha kubeconfig user --client-name=mynewuser --apiserver-advertise-address 192.168.100.200
Nota : O endereço de publicidade necessário pode ser visualizado na configuração do servidor api, localizada em /etc/kubernetes/manifests/kube-apiserver.yaml
por padrão.A configuração resultante será impressa no stdout. Ele deve ser salvo em
~/.kube/config
conta
~/.kube/config
usuário ou no arquivo especificado na
KUBECONFIG
ambiente
KUBECONFIG
.
Aprofundar
Para aqueles que desejam entender completamente os problemas descritos:
Entrar
Uma conta autenticada não tem permissão para atuar em um cluster por padrão. O Kubernetes possui um mecanismo de autorização para conceder permissões.
Antes da versão 1.6, o Kubernetes usava um tipo de autenticação chamado
ABAC (controle de acesso baseado em atributos). Detalhes sobre isso podem ser encontrados na
documentação oficial . Atualmente, essa abordagem é considerada herdada, mas você ainda pode usá-la ao mesmo tempo que outros tipos de autorização.
A maneira real (e mais flexível) de dividir os direitos de acesso ao cluster é chamada
RBAC (
controle de acesso baseado em função ). Foi declarado estável desde o
Kubernetes 1.8 . O RBAC implementa um modelo de direitos que proíbe qualquer coisa que não seja explicitamente permitida.
Para habilitar o RBAC , você precisa executar o api-server do
--authorization-mode=RBAC
com a opção
--authorization-mode=RBAC
. Os parâmetros são definidos no manifesto com a configuração da api-server, que por padrão está localizada no caminho
/etc/kubernetes/manifests/kube-apiserver.yaml
, na seção de
command
. No entanto, o RBAC já está ativado por padrão, portanto, você provavelmente não deve se preocupar com isso: é possível verificar isso pelo valor do
authorization-mode
de
authorization-mode
(no já mencionado
kube-apiserver.yaml
). A propósito, entre seus valores, pode haver outros tipos de autorização (
node
,
webhook
,
always allow
), mas vamos deixá-los fora do escopo do material.
A propósito, já publicamos
um artigo com uma história bastante detalhada sobre os princípios e recursos do trabalho com o RBAC; portanto, vou me limitar ainda mais a uma breve lista dos princípios e exemplos.
As seguintes entidades da API são usadas para controlar o acesso ao Kubernetes via RBAC:
Role
e ClusterRole
são funções que descrevem privilégios:Role
permite descrever direitos dentro de um espaço para nome;ClusterRole
- dentro do cluster, incluindo objetos específicos do cluster, como nós, URLs sem recursos (ou seja, não relacionados aos recursos do Kubernetes - por exemplo, /version
, /logs
, /api*
);RoleBinding
e ClusterRoleBinding
- serve para vincular Role
e ClusterRole
a um usuário, grupo de usuários ou ServiceAccount.
As entidades Role e RoleBinding são limitadas pelo namespace, ou seja, deve estar no mesmo espaço para nome. No entanto, RoleBinding pode se referir a ClusterRole, que permite criar um conjunto de permissões padrão e controlar o acesso usando-as.
As funções descrevem direitos usando conjuntos de regras que contêm:
- Grupos de API - consulte a documentação oficial do apiGroups e a saída do
kubectl api-resources
; - recursos ( recursos :
pod
, namespace
, deployment
etc.); - 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 discussão mais detalhada da autorização no Kubernetes pode ser encontrada na página de
documentação oficial . Em vez disso (ou melhor, além disso), darei exemplos que ilustram seu trabalho.
Exemplos de entidades RBAC
Uma
Role
simples que permite que você obtenha a lista e o status dos pods e monitore-os no
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"]
Um exemplo de
ClusterRole
, que permite obter uma lista e status dos pods e monitorá-los em todo o cluster:
apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: # "namespace" , ClusterRole name: pod-reader rules: - apiGroups: [""] resources: ["pods"] verbs: ["get", "watch", "list"]
Exemplo
RoleBinding
, que permite ao usuário
mynewuser
"ler" pods no
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
Esquematicamente, a arquitetura do Kubernetes pode ser representada da seguinte maneira:

O principal componente do Kubernetes, responsável pelo processamento de solicitações, é
um servidor de API . Todas as operações no cluster passam por ele. Leia mais sobre esses mecanismos internos no artigo “
O que acontece no Kubernetes quando o kubectl run é iniciado? "
A auditoria do sistema é um recurso interessante no Kubernetes, que está desativado por padrão. Ele permite que você registre todas as chamadas na API do Kubernetes. Como você pode adivinhar facilmente, por meio dessa API, todas as ações relacionadas ao monitoramento e alteração do estado do cluster são executadas. Uma boa descrição de seus recursos pode (como de costume) ser encontrada na
documentação oficial do K8s. Em seguida, tentarei apresentar o tópico em um idioma mais simples.
Portanto,
para habilitar a auditoria , precisamos passar três parâmetros necessários para o contêiner no servidor de API, mais sobre o que está descrito 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: da rotação do log às descrições de webhook. Parâmetros de rotação de log de exemplo:
--audit-log-maxbackup=10
--audit-log-maxsize=100
--audit-log-maxage=7
Mas não vamos nos aprofundar neles com mais detalhes - você pode encontrar todos os detalhes na
documentação do kube-apiserver .
Como já mencionado, todos os parâmetros são definidos no manifesto com a configuração da api-server (por padrão
/etc/kubernetes/manifests/kube-apiserver.yaml
), na seção de
command
. Vamos voltar aos 3 parâmetros necessários e analisá-los:
audit-policy-file
- caminho para o arquivo YAML com a descrição da política de auditoria. Voltaremos ao seu conteúdo, mas por enquanto observo que o arquivo deve estar acessível para leitura pelo processo da api-server. Portanto, é necessário montá-lo dentro do contêiner, 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
audit-log-path
- caminho para o arquivo de log. O caminho também deve estar acessível ao processo api-server, portanto, descrevemos de maneira semelhante sua montagem:
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 do log de auditoria. Por padrão, esse é json
, mas o formato de texto herdado também está disponível.
Política de auditoria
Agora, sobre o arquivo mencionado, com a descrição da política de log. O primeiro conceito de política de auditoria é
level
, o
nível de log . Eles são os seguintes:
None
- não faça logon;Metadata
- metadados de solicitação de log: usuário, hora da solicitação, recurso de destino (pod, espaço para nome, etc.), tipo de ação (verbo), etc;Request
- metadados de log e corpo da solicitação;RequestResponse
- RequestResponse
metadados, corpo da solicitação e corpo da resposta.
Os dois últimos níveis (
Request
e
RequestResponse
) não registram solicitações que não
RequestResponse
recursos (chamadas para os chamados URLs sem recursos).
Além disso, todos os pedidos passam por
vários estágios :
RequestReceived
- o estágio em que a solicitação é recebida pelo manipulador e ainda não foi transferida ao longo da cadeia de manipuladores;ResponseStarted
- cabeçalhos de resposta enviados, mas antes de enviar o corpo da resposta. Gerado para consultas longas (por exemplo, watch
);ResponseComplete
- corpo da resposta enviado, mais informações não serão enviadas;Panic
- eventos são gerados quando uma emergência é detectada.
Você pode usar
omitStages
para ignorar qualquer estágio.
No arquivo de políticas, podemos descrever várias seções com diferentes níveis de log. A primeira regra correspondente encontrada na descrição da política será aplicada.
O daemon kubelet monitora a alteração do manifesto com a configuração da api-server e, se houver alguma, é detectada, reinicia o contêiner com a api-server. Mas há um detalhe importante:
eles ignoram as alterações no arquivo de políticas . Depois de fazer alterações no arquivo de políticas, você precisará reiniciar o api-server manualmente. Como o api-server está sendo executado como um
pod estático , o comando
kubectl delete
não o reinicia. Você precisará manualmente
docker stop
nos kube-masters nos quais a política de auditoria foi alterada:
docker stop $(docker ps | grep k8s_kube-apiserver | awk '{print $1}')
Quando você ativa a auditoria, é importante lembrar que o
kube-apiserver tem uma carga maior . Em particular, o consumo de memória para armazenar o contexto de solicitações está aumentando. O registro inicia somente após o envio do cabeçalho de resposta. Além disso, a carga depende da configuração da política de auditoria.
Exemplos de política
Vamos analisar a estrutura dos arquivos de políticas usando exemplos.
Aqui está um arquivo de
policy
simples para registrar tudo no nível de
Metadata
:
apiVersion: audit.k8s.io/v1 kind: Policy rules: - level: Metadata
Você pode especificar uma lista de usuários (
Users
e
ServiceAccounts
) e grupos de usuários na política. Por exemplo, é assim que ignoraremos os usuários do sistema, mas registramos tudo o mais no nível 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
Também é possível descrever o destino:
namespaces
- verbos ( verbos :
get
, update
, delete
e outros); - recursos ( recursos , nomeadamente:
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 política de auditoria a seguir é fornecida como uma demonstração das melhores práticas na
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 é o
perfil usado no GCE .
Para uma resposta rápida a eventos de auditoria, é possível
descrever um webhook . Esse problema é divulgado na
documentação oficial , deixarei de fora do escopo deste artigo.
Sumário
O artigo fornece uma visão geral dos mecanismos básicos de segurança nos clusters do Kubernetes que permitem criar contas de usuário personalizadas, compartilhar seus direitos e registrar suas ações. Espero que seja útil para aqueles que enfrentam essas questões na teoria ou na prática. Também recomendo que você analise a lista de outros materiais sobre o tópico de segurança no Kubernetes, listados no "PS" - talvez entre eles você encontre os detalhes necessários sobre questões relevantes para você.
PS
Leia também em nosso blog: