Isolamento de inquilinos - Amazon EKS

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 é um projeto de código aberto que pode auxiliar na implementação da multilocação flexível. Ele é implementado como uma série de controladores CRDs e que fornecem os seguintes recursos:

  • 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 é uma oferta comercial dos mantenedores do Kiosk e DevSpaceque adiciona os seguintes recursos:

  • 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 que possam isolar cargas de trabalho confidenciais e protegê-las do acesso não autorizado ao executar o Kubernetes na AWS. Isso significa que você pode usar todos os recursos da API de política de rede em seu cluster Amazon EKS. Esse nível de controle granular permite que você implemente o princípio do privilégio mínimo, o que garante que somente pods autorizados possam se comunicar entre si.

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.

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 e o Firekube da Weave.

Para obter informações adicionais sobre o esforço de tornar o Firecracker um tempo de execução compatível com o EKS, consulte 1238496944684597248.html. https://threadreaderapp.com/thread/

Agente de política aberta (OPA) e porteiro

O Gatekeeper é um controlador de admissão do Kubernetes que aplica políticas criadas com o OPA. Com o OPA, você pode criar uma política que executa pods de inquilinos em instâncias separadas ou com maior prioridade do que outros locatários. Uma coleção de políticas comuns de OPA pode ser encontrada no GitHub repositório deste projeto.

Há também um plug-in OPA experimental para CoreDNS que permite usar o OPA nos registros retornados filter/control pelo CoreDNS.

Kyverno

O Kyverno é um mecanismo de políticas nativo do Kubernetes que pode validar, alterar e gerar configurações com políticas como recursos do Kubernetes. O Kyverno usa sobreposições no estilo Kustomize para validação, suporta JSON Patch e patch de mesclagem estratégica para mutação e pode clonar recursos em namespaces com base em acionadores flexíveis.

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 deste projeto. Muitos outros estão incluídos na biblioteca de políticas no site da Kyverno.

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 do Kubernetes é usada para direcionar nós para agendamento, com base nos rótulos dos nós. Com as regras de afinidade de nós, os pods são atraídos por nós específicos que correspondem aos termos do seletor. Na especificação do pod abaixo, a afinidade do requiredDuringSchedulingIgnoredDuringExecution 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. NodeRestrictionque está habilitado para clusters EKS kubelet 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. No entanto, a afinidade do nó é mais expressiva e permite que mais condições sejam consideradas durante o agendamento do pod. Para obter informações adicionais sobre as diferenças e as opções de agendamento mais avançadas, consulte esta postagem no blog da CNCF sobre o agendamento avançado de pod para node do Kubernetes.

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. As manchas são usadas para impor condições nos nós que impedem que os pods sejam programados. A mancha abaixo usa um par de valores-chave de. 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) e pelos daemonsets kube-proxy. Para esse fim, as especificações desses frutos contêm tolerâncias muito permissivas, para tolerar diferentes contaminações. Deve-se tomar cuidado para não alterar essas tolerações. A alteração dessas tolerâncias pode resultar em uma operação incorreta do cluster. Além disso, ferramentas de gerenciamento de políticas, como OPA/Gatekeeper e Kyverno, podem ser usadas para criar políticas de validação que impeçam que pods não autorizados usem essas tolerâncias permissivas.

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 do Kubernetes, as políticas podem ser usadas para alterar as especificações do pod de entrada. As mutações adicionam os elementos necessários para permitir o agendamento desejado. Um exemplo OPA/Gatekeeper de política que adiciona uma afinidade de nó é visto abaixo.

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 complementar deste guia.

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 no Fechamento.

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 pode ser usada para lidar com a mutação de afinidade do nó.

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

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) está tentando resolver essas deficiências por meio de vários projetos de incubação, incluindo o Hierarchical Namespace Controller (HNC) e o Virtual Cluster.

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 fornece diretrizes para compartilhar clusters usando namespaces para isolamento e segmentação, e uma ferramenta de linha de comando kubectl-mtb para validar a conformidade com as diretrizes.

Ferramentas e recursos de gerenciamento de vários clusters