Esta página mostra como reduzir o risco de ataques de escalada de privilégios no seu cluster, indicando ao Google Kubernetes Engine (GKE) que agende as suas cargas de trabalho num conjunto de nós dedicado separado das cargas de trabalho privilegiadas geridas pelo GKE. Só deve usar esta abordagem se não conseguir usar o GKE Sandbox. O GKE Sandbox é a abordagem recomendada para o isolamento de nós. O GKE Sandbox também oferece outras vantagens de reforço para as suas cargas de trabalho.
Esta página destina-se a especialistas de segurança que requerem uma camada de isolamento em cargas de trabalho, mas não podem usar o GKE Sandbox. Para saber mais sobre as funções comuns e as tarefas de exemplo que referimos no conteúdo, consulte o artigo Funções e tarefas comuns do utilizador do GKE. Trusted Cloud by S3NS
Esta página aplica-se a clusters padrão sem aprovisionamento automático de nós. Para separar cargas de trabalho em clusters do Autopilot e em clusters padrão com o aprovisionamento automático de nós ativado, consulte o artigo Configure a separação de cargas de trabalho no GKE.
Vista geral
Os clusters do GKE usam cargas de trabalho privilegiadas geridas pelo GKE para ativar funcionalidades específicas do cluster, como a recolha de métricas. Estas cargas de trabalho recebem autorizações especiais para serem executadas corretamente no cluster.
As cargas de trabalho que implementa nos seus nós podem ser potencialmente comprometidas por uma entidade maliciosa. A execução destas cargas de trabalho juntamente com cargas de trabalho privilegiadas geridas pelo GKE significa que um atacante que saia de um contentor comprometido pode usar as credenciais da carga de trabalho privilegiada no nó para aumentar os privilégios no seu cluster.
Impeça fugas de contentores
A sua defesa principal deve ser as suas aplicações. O GKE tem várias funcionalidades que pode usar para proteger os seus clusters e pods. Na maioria dos casos, recomendamos vivamente a utilização do GKE Sandbox para isolar as suas cargas de trabalho. O GKE Sandbox baseia-se no projeto de código aberto gVisor e implementa a API do kernel do Linux no espaço do utilizador. Cada Pod é executado num kernel dedicado que isola as aplicações para impedir o acesso a chamadas de sistema privilegiadas no kernel do anfitrião. As cargas de trabalho executadas no GKE Sandbox são agendadas automaticamente em nós separados, isolados de outras cargas de trabalho.
Também deve seguir as recomendações em Reforce a segurança do cluster.
Evite ataques de escalamento de privilégios
Se não puder usar o GKE Sandbox e quiser uma camada adicional de isolamento, além de outras medidas de reforço, pode usar node taints e node affinity para agendar as suas cargas de trabalho num conjunto de nós dedicado. Uma restrição de nó indica ao GKE que deve evitar agendar cargas de trabalho sem uma tolerância correspondente (como cargas de trabalho geridas pelo GKE) nesses nós. A afinidade de nós nas suas próprias cargas de trabalho indica ao GKE para agendar os seus pods nos nós dedicados.
Limitações do isolamento de nós
- Os atacantes continuam a poder iniciar ataques de negação de serviço (DoS) a partir do nó comprometido.
- Os nós comprometidos ainda podem ler muitos recursos, incluindo todos os pods e namespaces no cluster.
- Os nós comprometidos podem aceder a segredos e credenciais usados por todos os pods em execução nesse nó.
- A utilização de um node pool separado para isolar as cargas de trabalho pode afetar a eficiência de custos, o dimensionamento automático e a utilização de recursos.
- Os nós comprometidos podem continuar a ignorar as políticas de rede de saída.
- Algumas cargas de trabalho geridas pelo GKE têm de ser executadas em todos os nós do cluster e estão configuradas para tolerar todas as restrições.
- Se implementar DaemonSets com autorizações elevadas e que possam tolerar qualquer contaminação, esses pods podem ser um caminho para a escalada de privilégios a partir de um nó comprometido.
Como funciona o isolamento de nós
Para implementar o isolamento de nós para as suas cargas de trabalho, tem de fazer o seguinte:
- Contamine e etiquete um conjunto de nós para as suas cargas de trabalho.
- Atualize as suas cargas de trabalho com a regra de tolerância e afinidade de nós correspondente.
Este guia pressupõe que começa com um node pool no seu cluster. A utilização da afinidade de nós, além das restrições de nós, não é obrigatória, mas recomendamos que o faça porque beneficia de um maior controlo sobre o agendamento.
Antes de começar
Antes de começar, certifique-se de que realizou as seguintes tarefas:
- Ative a API Google Kubernetes Engine. Ative a API Google Kubernetes Engine
- Se quiser usar a CLI gcloud para esta tarefa,
instale-a e, em seguida,
inicialize-a. Se instalou anteriormente a CLI gcloud, execute
gcloud components update
para obter a versão mais recente.
- Escolha um nome específico para a restrição de contaminação do nó e a etiqueta do nó que quer usar para os conjuntos de nós dedicados.
Contamine e etiquete um conjunto de nós para as suas cargas de trabalho
Crie um novo node pool para as suas cargas de trabalho e aplique uma restrição de nó e uma etiqueta de nó. Quando aplica uma restrição ou uma etiqueta ao nível do conjunto de nós, todos os novos nós, como os criados pelo dimensionamento automático, recebem automaticamente as restrições e as etiquetas especificadas.
Também pode adicionar taints de nós e etiquetas de nós a pools de nós existentes. Se usar o efeito NoExecute
, o GKE despeja todos os pods em execução nesses nós que não tenham uma tolerância para a nova mancha.
Para o isolamento da carga de trabalho, use sempre o prefixo node-restriction.kubernetes.io/
para as etiquetas dos nós e para os seletores correspondentes nos manifestos dos pods.
Este prefixo impede que um atacante use a credencial do nó para definir ou modificar as etiquetas que usam este prefixo. Para mais informações, consulte o artigo
Isolamento/restrição de nós
na documentação do Kubernetes.
Para adicionar uma restrição e uma etiqueta a um novo conjunto de nós, execute o seguinte comando:
gcloud container node-pools create POOL_NAME \
--cluster=CLUSTER_NAME \
--node-taints=TAINT_KEY=TAINT_VALUE:TAINT_EFFECT \
--node-labels=node-restriction.kubernetes.io/LABEL_KEY=LABEL_VALUE
Substitua o seguinte:
POOL_NAME
: o nome do novo conjunto de nós para as suas cargas de trabalho.CLUSTER_NAME
: o nome do seu cluster do GKE.TAINT_KEY=TAINT_VALUE
: um par de chave-valor associado a uma programaçãoTAINT_EFFECT
. Por exemplo,workloadType=untrusted
.TAINT_EFFECT
: um dos seguintes valores de efeito:NoSchedule
,PreferNoSchedule
ouNoExecute
.NoExecute
oferece uma garantia de despejo melhor do queNoSchedule
.node-restriction.kubernetes.io/LABEL_KEY
=LABEL_VALUE
: pares de chaves-valores para as etiquetas dos nós, que correspondem aos seletores que especifica nos manifestos da carga de trabalho. O prefixonode-restriction.kubernetes.io/
impede que as credenciais do nó sejam usadas para definir estes pares de valor-chave nos nós.
Adicione uma tolerância e uma regra de afinidade de nós às suas cargas de trabalho
Depois de contaminar o pool de nós dedicado, nenhuma carga de trabalho pode ser agendada no mesmo, a menos que tenha uma tolerância correspondente à contaminação que adicionou. Adicione a tolerância à especificação das suas cargas de trabalho para permitir que esses pods sejam agendados no seu conjunto de nós contaminado.
Se etiquetou o conjunto de nós dedicado, também pode adicionar uma regra de afinidade de nós para indicar ao GKE que agende as suas cargas de trabalho apenas nesse conjunto de nós.
O exemplo seguinte adiciona uma tolerância para a restrição workloadType=untrusted:NoExecute
e uma regra de afinidade de nós para a etiqueta de nó workloadType=untrusted
.
kind: Deployment
apiVersion: apps/v1
metadata:
name: my-app
namespace: default
labels:
app: my-app
spec:
replicas: 1
selector:
matchLabels:
app: my-app
template:
metadata:
labels:
app: my-app
spec:
tolerations:
- key: TAINT_KEY
operator: Equal
value: TAINT_VALUE
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: node-restriction.kubernetes.io/LABEL_KEY
operator: In
values:
- "LABEL_VALUE"
containers:
- name: sleep
image: ubuntu
command: ["/bin/sleep", "inf"]
Substitua o seguinte:
TAINT_KEY
: a chave de contaminação que aplicou ao seu conjunto de nós dedicado.TAINT_VALUE
: o valor de contaminação que aplicou ao seu grupo de nós dedicado.LABEL_KEY
: a chave da etiqueta do nó que aplicou ao seu node pool dedicado.LABEL_VALUE
: o valor da etiqueta do nó que aplicou ao seu node pool dedicado.
Quando atualiza a sua implementação com kubectl apply
, o GKE recria os pods afetados. A regra de afinidade de nós força os pods para o node pool dedicado que criou. A tolerância permite que apenas esses pods sejam colocados nos nós.
Verifique se a separação funciona
Para verificar se o agendamento funciona corretamente, execute o seguinte comando e verifique se as suas cargas de trabalho estão no conjunto de nós dedicado:
kubectl get pods -o=wide
Recomendações e práticas recomendadas
Depois de configurar o isolamento de nós, recomendamos que faça o seguinte:
- Restrinja pools de nós específicos apenas a cargas de trabalho geridas pelo GKE adicionando a
contaminação
components.gke.io/gke-managed-components
. A adição desta mancha impede que os seus próprios pods sejam agendados nesses nós, o que melhora o isolamento. - Ao criar novos node pools, impeça que a maioria das cargas de trabalho geridas pelo GKE sejam executadas nesses nós adicionando a sua própria restrição a esses node pools.
- Sempre que implementar novas cargas de trabalho no cluster, como quando instala ferramentas de terceiros, audite as autorizações que os pods requerem. Sempre que possível, evite implementar cargas de trabalho que usem autorizações elevadas em nós partilhados.