As traduções são geradas por tradução automática. Em caso de conflito entre o conteúdo da tradução e da versão original em inglês, a versão em inglês prevalecerá.
Isolamento de inquilinos
Quando pensamos em multilocação, geralmente queremos isolar um usuário ou aplicativo de outros usuários ou aplicativos executados em uma infraestrutura compartilhada.
O Kubernetes é um único orquestrador de inquilinos, ou seja, uma única instância do plano de controle é compartilhada entre todos os inquilinos em um cluster. No entanto, existem vários objetos do Kubernetes que você pode usar para criar a aparência de multilocação. Por exemplo, namespaces e controles de acesso baseados em funções (RBAC) podem ser implementados para isolar logicamente os inquilinos uns dos outros. Da mesma forma, as cotas e os intervalos de limite podem ser usados para controlar a quantidade de recursos do cluster que cada inquilino pode consumir. No entanto, o cluster é a única construção que fornece um forte limite de segurança. Isso ocorre porque um invasor que consegue obter acesso a um host dentro do cluster pode recuperar todos os segredos e volumes montados nesse host. ConfigMaps Eles também poderiam se passar pelo Kubelet, o que lhes permitiria manipular os atributos do nó and/or se movendo lateralmente dentro do cluster.
As seções a seguir explicarão como implementar o isolamento de inquilinos e, ao mesmo tempo, reduzir os riscos de usar um único orquestrador de inquilinos, como o Kubernetes.
Multilocação suave
Com a multilocação flexível, você usa construções nativas do Kubernetes, por exemplo, namespaces, funções e associações de funções e políticas de rede, para criar uma separação lógica entre os locatários. O RBAC, por exemplo, pode impedir que os inquilinos acessem ou manipulem os recursos uns dos outros. As cotas e os intervalos de limite controlam a quantidade de recursos do cluster que cada locatário pode consumir, enquanto as políticas de rede podem ajudar a impedir que aplicativos implantados em namespaces diferentes se comuniquem entre si.
Nenhum desses controles, no entanto, impede que pods de diferentes locatários compartilhem um nó. Se for necessário um isolamento mais forte, você pode usar um seletor de nós, regras de antiafinidade, and/or manchas e tolerâncias para forçar pods de diferentes inquilinos a serem programados em nós separados; geralmente chamados de nós de locatários únicos. Isso pode ser bastante complicado e ter um custo proibitivo em um ambiente com muitos inquilinos.
Importante
A multilocação flexível implementada com namespaces não permite que você forneça aos locatários uma lista filtrada de namespaces porque os namespaces são um tipo com escopo global. Se um locatário tiver a capacidade de visualizar um determinado namespace, ele poderá visualizar todos os namespaces dentro do cluster.
Atenção
Com soft-multi-tenancy, os locatários mantêm a capacidade de consultar o CoreDNS para todos os serviços executados no cluster por padrão. Um invasor pode explorar isso executando o dig SRV a
..svc.cluster.local
partir de qualquer pod no cluster. Se você precisar restringir o acesso aos registros DNS dos serviços executados em seus clusters, considere usar os plug-ins Firewall ou Policy para CoreDNS. Para obter informações adicionais, consulte https://github.com/coredns/policy# -policy kubernetes-metadata-multi-tenancy
O Kiosk
-
Contas e usuários de contas para separar inquilinos em um cluster Kubernetes compartilhado
-
Provisionamento de namespace de autoatendimento para usuários da conta
-
Limites de conta para garantir a qualidade do serviço e a imparcialidade ao compartilhar um cluster
-
Modelos de namespace para isolamento seguro de inquilinos e inicialização de namespace de autoatendimento
O Loft
-
Acesso a vários clusters para conceder acesso a espaços em diferentes clusters
-
O modo de suspensão reduz as implantações em um espaço durante períodos de inatividade
-
Login único com provedores de autenticação OIDC, como GitHub
Há três casos de uso principais que podem ser resolvidos por meio de multilocação flexível.
Configuração empresarial
A primeira é em um ambiente corporativo em que os “inquilinos” são semiconfiáveis, pois são funcionários, contratados ou estão autorizados pela organização. Cada inquilino normalmente se alinha a uma divisão administrativa, como um departamento ou equipe.
Nesse tipo de configuração, um administrador de cluster geralmente será responsável pela criação de namespaces e pelo gerenciamento de políticas. Eles também podem implementar um modelo de administração delegada em que determinados indivíduos supervisionam um namespace, permitindo que eles executem operações CRUD para objetos não relacionados a políticas, como implantações, serviços, pods, trabalhos etc.
O isolamento fornecido pelo tempo de execução de um contêiner pode ser aceitável dentro dessa configuração ou pode precisar ser aumentado com controles adicionais para a segurança do pod. Também pode ser necessário restringir a comunicação entre serviços em namespaces diferentes se for necessário um isolamento mais rigoroso.
Kubernetes como serviço
Por outro lado, a multilocação flexível pode ser usada em configurações nas quais você deseja oferecer o Kubernetes como um serviço (KaaS). Com o KaaS, seu aplicativo é hospedado em um cluster compartilhado junto com uma coleção de controladores e CRDs que fornecem um conjunto de serviços PaaS. Os locatários interagem diretamente com o servidor da API Kubernetes e têm permissão para realizar operações CRUD em objetos que não sejam de política. Há também um elemento de autoatendimento em que os inquilinos podem criar e gerenciar seus próprios namespaces. Nesse tipo de ambiente, presume-se que os inquilinos estejam executando código não confiável.
Para isolar os inquilinos nesse tipo de ambiente, você provavelmente precisará implementar políticas de rede rígidas, bem como o sandboxing de pods. O sandboxing é onde você executa os contêineres de um pod dentro de uma micro VM como o Firecracker ou em um kernel de espaço de usuário. Hoje, você pode criar pods em sandbox com o EKS Fargate.
Software como serviço (SaaS)
O caso de uso final da multilocação flexível está em uma configuração ( Software-as-a-ServiceSaaS). Nesse ambiente, cada locatário está associado a uma instância específica de um aplicativo em execução no cluster. Cada instância geralmente tem seus próprios dados e usa controles de acesso separados que geralmente são independentes do Kubernetes RBAC.
Diferentemente dos outros casos de uso, o locatário em uma configuração SaaS não interage diretamente com a API Kubernetes. Em vez disso, o aplicativo SaaS é responsável pela interface com a API Kubernetes para criar os objetos necessários para dar suporte a cada locatário.
Construções do Kubernetes
Em cada um desses casos, as seguintes construções são usadas para isolar os inquilinos uns dos outros:
Namespaces
Os namespaces são fundamentais para implementar a multilocação flexível. Eles permitem que você divida o cluster em partições lógicas. Cotas, políticas de rede, contas de serviço e outros objetos necessários para implementar a multilocação têm como escopo um namespace.
Políticas de rede
Por padrão, todos os pods em um cluster Kubernetes podem se comunicar entre si. Esse comportamento pode ser alterado usando políticas de rede.
As políticas de rede restringem a comunicação entre pods usando rótulos ou intervalos de endereços IP. Em um ambiente multilocatário em que o isolamento estrito da rede entre os locatários é necessário, recomendamos começar com uma regra padrão que negue a comunicação entre os pods e outra regra que permita que todos os pods consultem o servidor DNS para resolução de nomes. Com isso estabelecido, você pode começar a adicionar mais regras permissivas que permitem a comunicação dentro de um namespace. Isso pode ser refinado ainda mais conforme necessário.
nota
O Amazon VPC CNI agora oferece suporte às políticas de rede do Kubernetes para criar políticas
Importante
As políticas de rede são necessárias, mas não suficientes. A aplicação de políticas de rede requer um mecanismo de políticas como Calico ou Cilium.
Regras de controle de acesso com base em função (RBAC)
Funções e associações de funções são os objetos do Kubernetes usados para aplicar o controle de acesso baseado em funções (RBAC) no Kubernetes. As funções contêm listas de ações que podem ser executadas em objetos em seu cluster. As vinculações de funções especificam os indivíduos ou grupos aos quais as funções se aplicam. Nas configurações corporativas e de KaaS, o RBAC pode ser usado para permitir a administração de objetos por grupos ou indivíduos selecionados.
Cotas
As cotas são usadas para definir limites nas cargas de trabalho hospedadas em seu cluster. Com as cotas, você pode especificar a quantidade máxima de CPU e memória que um pod pode consumir ou limitar o número de recursos que podem ser alocados em um cluster ou namespace. Os intervalos de limite permitem que você declare valores mínimos, máximos e padrão para cada limite.
O comprometimento excessivo de recursos em um cluster compartilhado geralmente é benéfico porque permite que você maximize seus recursos. No entanto, o acesso ilimitado a um cluster pode causar falta de recursos, o que pode levar à degradação do desempenho e à perda da disponibilidade do aplicativo. Se as solicitações de um pod forem definidas como muito baixas e a utilização real dos recursos exceder a capacidade do nó, o nó começará a sentir pressão na CPU ou na memória. Quando isso acontece, os pods podem ser reiniciados e and/or removidos do nó.
Para evitar que isso aconteça, você deve planejar impor cotas em namespaces em um ambiente multilocatário para forçar os inquilinos a especificar solicitações e limites ao programar seus pods no cluster. Isso também mitigará uma possível negação de serviço ao restringir a quantidade de recursos que um pod pode consumir.
Você também pode usar cotas para distribuir os recursos do cluster de acordo com os gastos do inquilino. Isso é particularmente útil no cenário de KaaS.
Prioridade e preempção do pod
A prioridade e a preempção de pods podem ser úteis quando você quer dar mais importância a um pod em relação a outros pods. Por exemplo, com o pod priority, você pode configurar os pods do cliente A para serem executados com uma prioridade maior que a do cliente B. Quando não houver capacidade disponível suficiente, o programador despejará os pods de menor prioridade do cliente B para acomodar os pods de maior prioridade do cliente A. Isso pode ser especialmente útil em um ambiente SaaS em que os clientes dispostos a pagar um prêmio recebem uma prioridade maior.
Importante
A prioridade dos pods pode ter um efeito indesejado em outros pods com prioridade mais baixa. Por exemplo, embora os grupos de vítimas sejam encerrados normalmente, mas isso não PodDisruptionBudget seja garantido, o que pode interromper um aplicativo com prioridade mais baixa que depende de um quórum de pods, consulte Limitações de preempção.
Controles de mitigação
Sua principal preocupação como administrador de um ambiente multilocatário é impedir que um invasor tenha acesso ao host subjacente. Os seguintes controles devem ser considerados para mitigar esse risco:
Ambientes de execução em sandbox para contêineres
O sandboxing é uma técnica pela qual cada contêiner é executado em sua própria máquina virtual isolada. As tecnologias que realizam o sandboxing de pods incluem o Firecracker
Agente de política aberta (OPA) e porteiro
O Gatekeeper
Há também um plug-in OPA experimental para CoreDNS que
Kyverno
O Kyverno
Você pode usar o Kyverno para isolar namespaces, reforçar a segurança do pod e outras práticas recomendadas e gerar configurações padrão, como políticas de rede. Vários exemplos estão incluídos no GitHub repositório
Isolando cargas de trabalho de inquilinos em nós específicos
Restringir as cargas de trabalho do inquilino para execução em nós específicos pode ser usado para aumentar o isolamento no modelo flexível de multilocação. Com essa abordagem, as cargas de trabalho específicas do inquilino são executadas somente em nós provisionados para os respectivos inquilinos. Para obter esse isolamento, as propriedades nativas do Kubernetes (afinidade de nós, manchas e tolerações) são usadas para direcionar nós específicos para o agendamento de pods e evitar que pods de outros locatários sejam programados nos nós específicos do inquilino.
Parte 1 - Afinidade de nós
A afinidade de nós dorequiredDuringSchedulingIgnoredDuringExecution
nó é aplicada ao respectivo pod. O resultado é que o pod terá como alvo nós rotulados com a seguinte chave/valor:. node-restriction.kubernetes.io/tenant: tenants-x
... spec: affinity: nodeAffinity: requiredDuringSchedulingIgnoredDuringExecution: nodeSelectorTerms: - matchExpressions: - key: node-restriction.kubernetes.io/tenant operator: In values: - tenants-x ...
Com essa afinidade de nó, o rótulo é necessário durante o agendamento, mas não durante a execução. Se os rótulos dos nós subjacentes mudarem, os pods não serão removidos apenas devido à alteração do rótulo. No entanto, o agendamento futuro pode ser afetado.
Atenção
O prefixo do rótulo de node-restriction.kubernetes.io/
tem um significado especial no Kubernetes. NodeRestrictionkubelet
evita adding/removing/updating rótulos com esse prefixo. Os atacantes não podem usar o kubelet’s credentials to update the node object or modify the system setup to pass these labels into `kubelet
anúncio não kubelet
é permitido para modificar esses rótulos. Se esse prefixo for usado para todo o agendamento de pod para nó, ele evitará cenários em que um invasor queira atrair um conjunto diferente de cargas de trabalho para um nó modificando os rótulos dos nós.
Em vez da afinidade de nós, poderíamos ter usado o seletor de nós
Parte 2 - Contaminações e tolerâncias
Atrair grupos para nós é apenas a primeira parte dessa abordagem em três partes. Para que essa abordagem funcione, devemos impedir que os pods sejam programados para nós para os quais os pods não estão autorizados. Para repelir pods indesejados ou não autorizados, o Kubernetes usa manchas de nós.tenant: tenants-x
... taints: - key: tenant value: tenants-x effect: NoSchedule ...
Dado o nó acimataint
, somente cápsulas que toleram a contaminação poderão ser programadas no nó. Para permitir que os pods autorizados sejam programados no nó, as respectivas especificações do pod devem incluir a toleration
até a contaminação, conforme mostrado abaixo.
... tolerations: - effect: NoSchedule key: tenant operator: Equal value: tenants-x ...
Os pods com os itens acima não toleration
serão impedidos de serem programados no nó, pelo menos não por causa dessa contaminação específica. As impurezas também são usadas pelo Kubernetes para interromper temporariamente o agendamento de pods durante determinadas condições, como a pressão dos recursos do nó. Com afinidade de nós, manchas e tolerâncias, podemos atrair efetivamente os frutos desejados para nós específicos e repelir os frutos indesejados.
Importante
É necessário que determinados pods do Kubernetes sejam executados em todos os nós. Exemplos desses pods são aqueles iniciados pela Container Network Interface (CNI)
Parte 3 - Gerenciamento baseado em políticas para seleção de nós
Há várias ferramentas que podem ser usadas para ajudar a gerenciar a afinidade dos nós e as tolerâncias das especificações do pod, incluindo a aplicação de regras nos pipelines do CICD. No entanto, a aplicação do isolamento também deve ser feita no nível do cluster Kubernetes. Para esse fim, as ferramentas de gerenciamento de políticas podem ser usadas para alterar as solicitações de entrada do servidor da API Kubernetes, com base nas cargas de solicitação, para aplicar as respectivas regras e tolerâncias de afinidade de nós mencionadas acima.
Por exemplo, pods destinados ao namespace tenants-x podem ser marcados com a afinidade e a tolerância corretas do nó para permitir o agendamento nos nós tenants-x. Utilizando ferramentas de gerenciamento de políticas configuradas usando o Webhook de admissão mutante
apiVersion: mutations.gatekeeper.sh/v1alpha1 kind: Assign metadata: name: mutator-add-nodeaffinity-pod annotations: aws-eks-best-practices/description: >- Adds Node affinity - https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#node-affinity spec: applyTo: - groups: [""] kinds: ["Pod"] versions: ["v1"] match: namespaces: ["tenants-x"] location: "spec.affinity.nodeAffinity.requiredDuringSchedulingIgnoredDuringExecution.nodeSelectorTerms" parameters: assign: value: - matchExpressions: - key: "tenant" operator: In values: - "tenants-x"
A política acima é aplicada a uma solicitação do servidor da API Kubernetes para aplicar um pod ao namespace tenants-x. A política adiciona a regra de afinidade do requiredDuringSchedulingIgnoredDuringExecution
nó, para que os pods sejam atraídos pelos nós com o rótulo. tenant: tenants-x
Uma segunda política, vista abaixo, adiciona a tolerância à mesma especificação de pod, usando os mesmos critérios de correspondência de namespace e grupos, tipos e versões de destino.
apiVersion: mutations.gatekeeper.sh/v1alpha1 kind: Assign metadata: name: mutator-add-toleration-pod annotations: aws-eks-best-practices/description: >- Adds toleration - https://kubernetes.io/docs/concepts/scheduling-eviction/taint-and-toleration/ spec: applyTo: - groups: [""] kinds: ["Pod"] versions: ["v1"] match: namespaces: ["tenants-x"] location: "spec.tolerations" parameters: assign: value: - key: "tenant" operator: "Equal" value: "tenants-x" effect: "NoSchedule"
As políticas acima são específicas para pods; isso se deve aos caminhos para os elementos mutantes nos elementos das políticaslocation
. Políticas adicionais podem ser criadas para lidar com recursos que criam pods, como recursos de Deployment e Job. As políticas listadas e outros exemplos podem ser vistos no GitHubprojeto
O resultado dessas duas mutações é que os frutos são atraídos para o nódulo desejado e, ao mesmo tempo, não são repelidos pela mancha específica do nódulo. Para verificar isso, podemos ver os trechos da saída de duas kubectl
chamadas para obter os nós rotulados e colocar os tenant=tenants-x
pods no namespace. tenants-x
kubectl get nodes -l tenant=tenants-x NAME ip-10-0-11-255... ip-10-0-28-81... ip-10-0-43-107... kubectl -n tenants-x get pods -owide NAME READY STATUS RESTARTS AGE IP NODE tenant-test-deploy-58b895ff87-2q7xw 1/1 Running 0 13s 10.0.42.143 ip-10-0-43-107... tenant-test-deploy-58b895ff87-9b6hg 1/1 Running 0 13s 10.0.18.145 ip-10-0-28-81... tenant-test-deploy-58b895ff87-nxvw5 1/1 Running 0 13s 10.0.30.117 ip-10-0-28-81... tenant-test-deploy-58b895ff87-vw796 1/1 Running 0 13s 10.0.3.113 ip-10-0-11-255... tenant-test-pod 1/1 Running 0 13s 10.0.35.83 ip-10-0-43-107...
Como podemos ver nas saídas acima, todos os pods estão programados nos nós rotulados com. tenant=tenants-x
Simplificando, os pods funcionarão apenas nos nós desejados, e os outros pods (sem a afinidade e as tolerâncias exigidas) não. As cargas de trabalho dos inquilinos são efetivamente isoladas.
Um exemplo de especificação de pod com mutação é visto abaixo.
apiVersion: v1 kind: Pod metadata: name: tenant-test-pod namespace: tenants-x spec: affinity: nodeAffinity: requiredDuringSchedulingIgnoredDuringExecution: nodeSelectorTerms: - matchExpressions: - key: tenant operator: In values: - tenants-x ... tolerations: - effect: NoSchedule key: tenant operator: Equal value: tenants-x ...
Importante
As ferramentas de gerenciamento de políticas integradas ao fluxo de solicitações do servidor da API Kubernetes, usando webhooks de admissão de mutação e validação, são projetadas para responder à solicitação do servidor da API dentro de um prazo especificado. Isso geralmente é de 3 segundos ou menos. Se a chamada do webhook não retornar uma resposta dentro do tempo configurado, a and/or validação de mutação da solicitação de entrada do servidor da API poderá ou não ocorrer. Esse comportamento se baseia no fato de as configurações do webhook de admissão estarem definidas como Falha na Abertura ou Falha
Nos exemplos acima, usamos políticas escritas para OPA/Gatekeeper. No entanto, existem outras ferramentas de gerenciamento de políticas que também lidam com nosso caso de uso de seleção de nós. Por exemplo, essa política do Kyverno
nota
Se estiverem operando corretamente, as políticas mutantes afetarão as alterações desejadas nas cargas de solicitação do servidor de API de entrada. No entanto, políticas de validação também devem ser incluídas para verificar se as alterações desejadas ocorrem, antes que as alterações possam persistir. Isso é especialmente importante ao usar essas políticas para tenant-to-node isolamento. Também é uma boa ideia incluir políticas de auditoria para verificar rotineiramente seu cluster em busca de configurações indesejadas.
Referências
-
k-rail
Projetado para ajudar você a proteger um ambiente multilocatário por meio da aplicação de determinadas políticas. -
Práticas de segurança para aplicativos MultiTenant SaaS usando o Amazon EKS
Multilocação rígida
A multilocação rígida pode ser implementada provisionando clusters separados para cada inquilino. Embora isso forneça um isolamento muito forte entre os inquilinos, tem várias desvantagens.
Primeiro, quando você tem muitos inquilinos, essa abordagem pode rapidamente se tornar cara. Além de pagar pelos custos do plano de controle de cada cluster, você não poderá compartilhar recursos computacionais entre clusters. Isso acabará por causar fragmentação, na qual um subconjunto de seus clusters é subutilizado, enquanto outros são superutilizados.
Em segundo lugar, você provavelmente precisará comprar ou criar ferramentas especiais para gerenciar todos esses clusters. Com o tempo, gerenciar centenas ou milhares de clusters pode simplesmente se tornar muito complicado.
Por fim, a criação de um cluster por inquilino será lenta em relação à criação de um namespace. No entanto, uma abordagem de locação rígida pode ser necessária em setores altamente regulamentados ou em ambientes SaaS onde é necessário um forte isolamento.
Direções futuras
A comunidade Kubernetes reconheceu as deficiências atuais da multilocação flexível e os desafios da multilocação rígida. O Multi-Tenancy Special Interest Group (SIG)
A proposta do HNC (KEP) descreve uma maneira de criar relacionamentos pai-filho entre namespaces com herança de objetos [policy], além da capacidade de administradores de inquilinos criarem subnamespaces.
A proposta do Virtual Cluster descreve um mecanismo para criar instâncias separadas dos serviços do plano de controle, incluindo o servidor de API, o gerenciador do controlador e o agendador, para cada inquilino dentro do cluster (também conhecido como “Kubernetes on Kubernetes”).
A proposta de benchmarks de multilocação