
Mais cedo ou mais tarde, em qualquer sistema, a questão da segurança se torna essencial: garantia de autenticação, separação de permissões, auditoria e outras tarefas. Para Kubernetes, já existem , que permitem atender aos padrões mesmo em ambientes altamente exigentes… Este material se concentra nos aspectos básicos de segurança implementados nos mecanismos incorporados do K8s. Ele será principalmente útil para aqueles que estão começando a se familiarizar com Kubernetes, como um ponto de partida para estudar questões relacionadas à segurança.
Autenticação
No Kubernetes, existem dois tipos de usuários:
- Service Accounts — contas gerenciadas pela API do Kubernetes;
- Usuários — usuários "normais", gerenciados por serviços externos e independentes.
A principal diferença entre esses tipos é que para Service Accounts existem objetos especiais na API do Kubernetes (que são chamados de ServiceAccounts), que estão ligados ao espaço de nomes e a um conjunto de credenciais de autorização armazenadas no cluster em objetos do tipo Secrets. Esses usuários (Service Accounts) são destinados principalmente à gestão dos direitos de acesso à API do Kubernetes para processos que operam no cluster Kubernetes.
Por outro lado, os Users não têm registros na API do Kubernetes: a gestão deles deve ser realizada por mecanismos externos. Eles são destinados a pessoas ou processos que estão fora do cluster.
Cada solicitação à API está vinculada a uma Service Account, a um User ou é considerada anônima.
Os dados de autenticação do usuário incluem:
- Nome de usuário — nome de usuário (sensible a maiúsculas e minúsculas!);
- UID — uma string de identificação legível por máquina que é "mais consistente e única do que o nome de usuário";
- Groups — uma lista de grupos a que o usuário pertence;
- Extra — campos adicionais que podem ser utilizados pelo mecanismo de autorização.
Kubernetes pode utilizar uma ampla variedade de mecanismos de autenticação: certificados X509, tokens Bearer, proxies de autenticação, HTTP Basic Auth. Com esses mecanismos, é possível implementar diversas esquemas de autorização: de um arquivo estático com senhas a OpenID OAuth2.
Além disso, é permitido o uso de vários esquemas de autorização ao mesmo tempo. Por padrão, no cluster são utilizados:
- tokens de conta de serviço — para Service Accounts;
- X509 — para Users.
A questão sobre a gestão de ServiceAccounts está além do escopo deste artigo, e para aqueles que desejam entender melhor esta questão, recomendo começar pela . Vamos nos concentrar na questão do funcionamento dos certificados X509.
Certificados para usuários (X.509)
O método clássico de trabalhar com certificados implica em:
- geração de chave:
mkdir -p ~/mynewuser/.certs/ openssl genrsa -out ~/.certs/mynewuser.key 2048 - geração de uma solicitação de certificado:
openssl req -new -key ~/.certs/mynewuser.key -out ~/.certs/mynewuser.csr -subj "/CN=mynewuser/O=company" - processamento da solicitação de certificado usando as chaves CA do cluster Kubernetes, recebendo o certificado do usuário (para obter o certificado, você deve usar uma conta que tenha acesso à chave do centro de certificação do cluster Kubernetes, que por padrão está 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 - criação do arquivo de configuração:
- descrição do cluster (indique o endereço e a localização do arquivo do certificado 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 — como nãouma opção recomendada — você pode não indicar o certificado raiz (neste caso, o kubectl não verificará a validade do api-server do cluster):
kubectl config set-cluster kubernetes --insecure-skip-tls-verify=true --server=https://192.168.100.200:6443 - adição do usuário ao arquivo de configuração:
kubectl config set-credentials mynewuser --client-certificate=.certs/mynewuser.crt --client-key=.certs/mynewuser.key - adição do contexto:
kubectl config set-context mynewuser-context --cluster=kubernetes --namespace=target-namespace --user=mynewuser - definição do contexto padrão:
kubectl config use-context mynewuser-context
- descrição do cluster (indique o endereço e a localização do arquivo do certificado CA da instalação específica do cluster):
Após as manipulações acima, o arquivo .kube/config será criado com a seguinte configuração:
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 a transferência da configuração entre contas e servidores, é útil editar os valores das seguintes chaves:
-
certificate-authority -
client-certificate -
client-key
Para isso, você pode codificar os arquivos mencionados usando base64 e inseri-los na configuração, adicionando o sufixo ao nome das chaves -data, ou seja, resultando em certificate-authority-data etc.
Certificados com kubeadm
Com o lançamento O trabalho com certificados tornou-se significativamente mais fácil graças à versão alfa do seu suporte em . Por exemplo, veja como agora pode parecer a geração de um arquivo de configuração com as chaves do usuário:
kubeadm alpha kubeconfig user --client-name=mynewuser --apiserver-advertise-address 192.168.100.200 NB: O endereço advertise pode ser visualizado no arquivo de configuração do api-server, que por padrão está localizado em /etc/kubernetes/manifests/kube-apiserver.yaml.
O arquivo de configuração resultante será exibido no stdout. Ele deve ser salvo em ~/.kube/config uma conta de usuário ou em um arquivo indicado na variável de ambiente KUBECONFIG.
Aprofundar-se
Para aqueles que desejam entender mais profundamente as questões descritas:
- sobre o trabalho com certificados na documentação oficial do Kubernetes;
- , onde a questão dos certificados é abordada de uma perspectiva prática.
- sobre autenticação no Kubernetes.
Autorização
A conta autorizada por padrão não possui direitos para realizar ações no cluster. Para conceder permissões no Kubernetes, foi implementado um mecanismo de autorização.
Até a versão 1.6, o Kubernetes utilizava um tipo de autorização chamado ABAC (controle de acesso baseado em atributos). Detalhes sobre ele podem ser encontrados em . Atualmente, essa abordagem é considerada obsoleta (legada), porém você ainda pode utilizá-la simultaneamente com outros tipos de autorização.
O método atual (e mais flexível) de separação de permissões de acesso ao cluster é chamado de RBAC (). Ele foi considerado estável a partir da versão . O RBAC implementa um modelo de permissões no qual tudo que não é explicitamente permitido é proibido.
Para habilitar o RBAC, é necessário 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 no caminho /etc/kubernetes/manifests/kube-apiserver.yaml, na seção command. No entanto, por padrão, o RBAC já está habilitado, portanto, provavelmente não é necessário se preocupar com isso: você pode verificar isso pelo valor authorization-mode no já mencionado kube-apiserver.yaml). Vale mencionar que entre seus valores podem estar outros tipos de autorização (node, webhook, always allow), mas deixaremos a análise deles de fora do material.
Por falar nisso, já publicamos um relato bastante detalhado sobre os princípios e características do trabalho com o RBAC, portanto, a seguir, limitarei a uma breve listagem de fundamentos e exemplos.
Para controlar o acesso no Kubernetes através do RBAC, são usadas as seguintes entidades da API:
-
RoleeClusterRole— papéis que servem para descrever os direitos de acesso: -
Rolepermite descrever permissões dentro de um namespace; -
ClusterRole— dentro do cluster, incluindo objetos específicos do cluster como nós, URLs não relacionados a recursos (ou seja, não vinculados a recursos do Kubernetes — por exemplo,/version,/logs,/api*); -
RoleBindingeClusterRoleBinding— serve para a vinculaçãoRoleeClusterRolea um usuário, grupo de usuários ou ServiceAccount.
As entidades Role e RoleBinding são limitadas ao namespace, ou seja, devem estar dentro do mesmo espaço de nomes. No entanto, o RoleBinding pode referenciar um ClusterRole, o que permite criar um conjunto comum de permissões e gerenciar o acesso com base nele.
As roles descrevem permissões usando conjuntos de regras, que contêm:
- grupos de API — veja sobre apiGroups e saída
kubectl api-resources; - recursos (resources:
pod,namespace,deploymentetc.); - verbos (verbs:
set,atualizaretc.). - nomes de recursos (
resourceNames) — nos casos em que é necessário conceder acesso a um recurso específico, em vez de a todos os recursos desse tipo.
Uma análise mais detalhada da autorização no Kubernetes pode ser encontrada na página . Em vez disso (ou melhor — além disso), apresentarei exemplos que ilustram seu funcionamento.
Exemplos de entidades RBAC
Simples Role, que permite obter a 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, o que permite obter a lista e o status dos pods e monitorá-los em todo o cluster:
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
# a seção "namespace" não existe, pois o ClusterRole abrange todo o cluster
name: secret-reader
rules:
- apiGroups: [""]
resources: ["secrets"]
verbs: ["get", "watch", "list"] Exemplo RoleBinding, o que permite que o usuário mynewuser «leia» os pods no namespace my-namespace:
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: read-pods
namespace: target-namespace
subjects:
- kind: User
name: mynewuser # o nome do usuário é sensível a maiúsculas e minúsculas!
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: Role # deve ser “Role” ou “ClusterRole”
name: pod-reader # nome da Role, que está no mesmo namespace,
# ou nome da ClusterRole, cujo uso
# queremos permitir ao usuário
apiGroup: rbac.authorization.k8s.ioAuditoria de eventos
Esquematicamente, a arquitetura do Kubernetes pode ser representada da seguinte forma:

O componente central do Kubernetes responsável por processar solicitações é api-server. Todas as operações no cluster passam por ele. Mais detalhes sobre esses mecanismos internos podem ser encontrados no artigo «».
A auditoria do sistema é um recurso interessante no Kubernetes que, por padrão, está desativado. Ela permite registrar todas as chamadas à API do Kubernetes. Como é fácil deduzir, por meio dessa API são realizadas todas as ações relacionadas ao controle e à alteração do estado do cluster. Uma boa descrição de suas possibilidades pode ser encontrada em K8s. A seguir, vou tentar abordar o tema de forma mais simples.
Então, Para habilitar a auditoria, precisamos passar três parâmetros obrigatórios para o contêiner no api-server, sobre os quais falarei em detalhes a seguir:
-
--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, existem muitas configurações adicionais relacionadas à auditoria: desde a rotação de logs até as descrições de webhook. Um exemplo de parâmetros para rotação de logs:
-
--audit-log-maxbackup=10 -
--audit-log-maxsize=100 -
--audit-log-maxage=7
Mas não vamos nos aprofundar mais nisso — você pode encontrar todos os detalhes na .
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 três parâmetros obrigatórios e analisá-los:
-
audit-policy-file— o caminho para o arquivo YAML com a descrição da política de auditoria. Voltaremos ao seu conteúdo em breve, mas, por enquanto, note que o arquivo deve ser acessível para leitura pelo processo do api-server. Portanto, é necessário montá-lo dentro do contêiner, para o que podemos adicionar o seguinte código nas seções apropriadas do config:volumeMounts: - mountPath: /etc/kubernetes/policies name: policies readOnly: true volumes: - hostPath: path: /etc/kubernetes/policies type: DirectoryOrCreate name: policies -
audit-log-path— o caminho para o arquivo de log. O caminho também deve ser acessível pelo processo do api-server, então igual fazemos a descrição da montação:volumeMounts: - mountPath: /var/log/kube-audit name: logs readOnly: false volumes: - hostPath: path: /var/log/kube-audit type: DirectoryOrCreate name: logs -
audit-log-format— o formato do log de auditoria. Por padrão, isso éjson, mas um formato de texto obsoleto 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 da política de auditoria é o level, nível de log.Eles podem ser os seguintes:
-
Nenhum— não registrar; -
Metadata— registrar metadados da solicitação: usuário, hora da solicitação, recurso alvo (pod, namespace, etc.), tipo de ação (verb) e assim por diante; -
Request— registrar metadados e o corpo da solicitação; -
RequestResponse— registrar metadados, corpo da solicitação e corpo da resposta.
Os últimos dois níveis (Request e RequestResponse) não registram solicitações que não acessaram recursos (acessos a URLs chamadas de non-resources).
Além disso, todas as solicitações passam por várias etapas:
-
RequestReceived— fase em que a solicitação é recebida pelo manipulador e ainda não foi passada adiante na cadeia de manipuladores; -
ResponseStarted— os cabeçalhos da resposta foram enviados, mas antes do envio do corpo da resposta. É gerado para solicitações longas (por exemplo,observar); -
ResponseComplete— corpo da resposta enviado, mais informações não serão enviadas; -
Panic— eventos são gerados quando uma situação anômala é detectada.
Para pular quaisquer etapas, pode-se usar omitStages.
No arquivo de políticas, podemos descrever várias seções com diferentes níveis de registro. A primeira regra apropriada encontrada na descrição da política será aplicada.
O demon kubelet monitora a alteração do manifesto com a configuração do api-server e, ao detectar tais alterações, reinicia o contêiner do api-server. Mas há um detalhe importante: as alterações no arquivo de políticas serão ignoradas por ele. Após fazer alterações no arquivo de políticas, será necessário reiniciar o api-server manualmente. Como o api-server é executado como , equipe kubectl delete não resultará em seu reinício. Teremos que fazer manualmente docker stop nos 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 sobre o kube-apiserver aumenta. Em particular, há um aumento no consumo de memória para armazenar o contexto das solicitações. O registro em log começa apenas após o envio do cabeçalho da resposta. Além disso, a carga depende da configuração da política de auditoria.
Exemplos de políticas
Vamos analisar a estrutura dos arquivos de políticas por meio de exemplos.
Aqui está um arquivo simples policy, para registrar tudo no nível Metadata:
apiVersion: audit.k8s.io/v1
kind: Policy
rules:
- level: Metadata Na política, é possível especificar uma lista de usuários (Usuários e ServiceAccounts) e grupos de usuários. Por exemplo, assim estaremos ignorando os usuários do sistema, mas registrando 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: RequestTambém há a possibilidade de descrever os alvos:
- namespaces (
namespaces); - verbos (verbs:
get,atualizar,deletee outros); - recursos (resources, a saber:
pod,configmapse assim por diante.) e grupos de recursos (apiGroups).
Atenção! Os recursos e grupos de recursos (grupos de API, ou seja, apiGroups), bem como suas versões instaladas no cluster, podem ser obtidos através dos comandos:
kubectl api-resources
kubectl api-versionsA seguinte política de auditoria é apresentada como uma demonstração de melhores práticas na :
apiVersion: audit.k8s.io/v1beta1
kind: Policy
# Não registrar a fase RequestReceived
omitStages:
- "RequestReceived"
rules:
# Não registrar eventos considerados de pouco significado e não perigosos:
- level: None
users: ["system:kube-proxy"]
verbs: ["watch"]
resources:
- group: "" # este é o grupo de API com nome vazio, ao qual pertencem
# os recursos básicos do Kubernetes, chamados de “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"]
# Não registrar acessos a URLs de leitura apenas:
- level: None
nonResourceURLs:
- /healthz*
- /version
- /swagger*
# Não registrar mensagens referentes ao tipo de recurso “eventos”:
- level: None
resources:
- group: "" # core
resources: ["events"]
# Recursos do tipo Secret, ConfigMap e TokenReview podem conter dados secretos,
# portanto, registramos apenas os metadados dos pedidos relacionados a eles
- level: Metadata
resources:
- group: "" # core
resources: ["secrets", "configmaps"]
- group: authentication.k8s.io
resources: ["tokenreviews"]
# Ações do tipo get, list e watch podem ser dispendiosas; não as 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"
# Nível de registro padrão para recursos de API padrão
- 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"
# Nível de registro padrão para todos os outros pedidos
- level: MetadataOutro bom exemplo da política de auditoria — .
Para resposta rápida a eventos de auditoria, existe a possibilidade de descrever um webhook. Essa questão é abordada em , deixarei de fora deste artigo.
Resultados
Este artigo fornece uma visão geral dos mecanismos básicos de segurança em clusters Kubernetes, permitindo a criação de contas de usuário personalizadas, a divisão de seus direitos e o registro de suas ações. Espero que seja útil para aqueles que se deparam com essas questões, seja na teoria ou na prática. Recomendo também revisar a lista de outros materiais sobre segurança em Kubernetes que aparece no "P.S.", pois talvez você encontre detalhes relevantes para as suas questões.
P.S.
Confira também em nosso blog:
- «»;
- «»;
- «»;
- «»;
- «».
Fonte: habr.com
