Tutorial: gruppi di sicurezza per pods - Amazon EKS

Tutorial: gruppi di sicurezza per pods

I gruppi di sicurezza per i pods integrano i gruppi di sicurezza Amazon EC2 con i pods Kubernetes. È possibile utilizzare i gruppi di sicurezza Amazon EC2 per definire regole che consentono il traffico di rete in entrata e in uscita da e verso i pods implementati nei nodi in esecuzione su molti tipi di istanza Amazon EC2 e Fargate. Per una descrizione dettagliata di questa funzionalità, consulta il post Introduzione ai gruppi di sicurezza per i podpods del blog.

Considerazioni

Prima di implementare i gruppi di sicurezza per i pods, considerare i limiti e le condizioni seguenti:

  • I gruppi di sicurezza per i pods non possono essere utilizzati con i nodi Windows.

  • I gruppi di sicurezza per i pods non possono essere utilizzati con cluster configurati per la famiglia IPv6 che contengono nodi Amazon EC2. Tuttavia, è possibile utilizzare gruppi di sicurezza per i pods con cluster configurati per la famiglia IPv6 che contengono solo nodi Fargate. Per ulteriori informazioni, consultare Tutorial: Assegnazione di indirizzi IPv6 a pods e services.

  • I gruppi di sicurezza per pods sono supportati dalla maggior parte delle famiglie di istanze Amazon EC2 basate su Nitro, ma non da tutte le generazioni di una famiglia. Ad esempio, sono supportate la famiglia e le generazioni dell'istanza m5, c5, r5, p3, m6g, c6g e r6g. Non è supportato alcun tipo di istanza nella famiglia t. Per un elenco completo dei tipi di istanza supportati, consulta il file limits.go su GitHub. I nodi devono essere uno dei tipi di istanza elencati che contengono IsTrunkingCompatible: true nel file. Per ulteriori informazioni sui tipi di istanze supportati, consulta i tipi di istanze EC2 supportati da amazon-vpc-resource-controller-k8s su GitHub.

  • Se utilizzi anche le policy di sicurezza dei pod per limitare l'accesso alla mutazione del pod, allora l'utente eks:vpc-resource-controller Kubernetes deve essere specificato in ClusterRoleBinding Kubernetes per il role a cui è assegnato il psp. Se si utilizza Amazon EKS psp, role, e ClusterRoleBinding, questa è la eks:podsecuritypolicy:authenticated ClusterRoleBinding. Ad esempio, aggiungi l'utente alla sezione subjects:, come mostrato nell'esempio seguente:

    ... subjects: - kind: Group apiGroup: rbac.authorization.k8s.io name: system:authenticated - apiGroup: rbac.authorization.k8s.io kind: User name: eks:vpc-resource-controller - kind: ServiceAccount name: eks-vpc-resource-controller
  • Se si utilizzano allo stesso tempo una rete personalizzata e i gruppi di sicurezza per i pods, il gruppo di sicurezza specificato dai gruppi di sicurezza per i pods viene utilizzato in alternativa al gruppo di protezione specificato in ENIconfig.

  • Se utilizzi la versione 1.10.2 o precedente del plug-in CNI di Amazon VPC e includi l'impostazione terminationGracePeriodSeconds nelle specifiche del pod, il valore per l'impostazione non può essere zero.

  • Se utilizzi la versione 1.10 o precedente del plug-in CNI di Amazon VPC o la versione 1.11 con l'impostazione predefinita POD_SECURITY_GROUP_ENFORCING_MODE=strict, i servizi Kubernetes di tipo NodePort e LoadBalancer che utilizzano le destinazioni di istanza con externalTrafficPolicy impostato su Local non sono supportati con i pods a cui si assegnano i gruppi di sicurezza. Per ulteriori informazioni sull'utilizzo di un load balancer con target di istanza, consultare Bilanciamento del carico di rete su Amazon EKS. Le destinazioni dell'istanza con externalTrafficPolicy impostato su Local sono supportate se si utilizza la versione 1.11 o successiva del plug-in con POD_SECURITY_GROUP_ENFORCING_MODE=standard.

  • La fonte NAT è disabilitata per il traffico in uscita dai pods con gruppi di sicurezza assegnati, in modo che vengano applicate le regole dei gruppi di sicurezza in uscita, se si utilizza la versione 1.10 o precedente del plug-in CNI di Amazon VPC o la versione 1.11 con l'impostazione predefinita POD_SECURITY_GROUP_ENFORCING_MODE=strict. Per accedere a Internet, è necessario avviare pods con gruppi di sicurezza assegnati su nodi implementati in una sottorete privata configurata con un gateway NAT o un'istanza. I Podscon gruppi di sicurezza assegnati implementati nelle sottoreti pubbliche non sono in grado di accedere a Internet.

    Se si utilizza la versione 1.11 o successiva del plug-in con POD_SECURITY_GROUP_ENFORCING_MODE=standard, il traffico pod destinato all'esterno del VPC viene convertito nell'indirizzo IP dell'interfaccia di rete primaria dell'istanza. Per questo traffico vengono utilizzate le regole nei gruppi di sicurezza per l'interfaccia di rete primaria, anziché le regole nei gruppi di sicurezza dei pod's.

  • Per utilizzare le policy di rete Calico con pods che hanno gruppi di sicurezza associati, dovrai utilizzare la versione 1.11.0 o successiva del plug-in CNI di Amazon VPC e impostare POD_SECURITY_GROUP_ENFORCING_MODE=standard. In caso contrario, i flussi di traffico da e verso i pods con gruppi di sicurezza associati non sono soggetti all'applicazione della policy di rete Calico ma saranno limiti esclusivamente all'applicazione del gruppo di sicurezza di Amazon EC2. Per aggiornare la versione di CNI di Amazon VPC, consulta la sezione Gestione del componente aggiuntivo Amazon VPC CNI plugin for Kubernetes.

  • I Pods in esecuzione su nodi Amazon EC2 che utilizzano gruppi di sicurezza in cluster che impiegano Nodelocal DNSCache sono supportati solo con la versione 1.11.0 o successiva del plug-in CNI di Amazon VPC e con POD_SECURITY_GROUP_ENFORCING_MODE=standard. Per aggiornare la versione del plug-in CNI di Amazon VPC, consulta la sezione Gestione del componente aggiuntivo Amazon VPC CNI plugin for Kubernetes.

  • I gruppi di sicurezza per pod potrebbero portare a un aumento della latenza di avvio dei pod per i pods con un alto tasso di abbandono. Ciò è dovuto alla limitazione della velocità nel controller delle risorse.

Configurazione del Amazon VPC CNI plugin for Kubernetes per i gruppi di sicurezza per pods

Per implementare i gruppi di sicurezza per i pods

Se si utilizzano gruppi di sicurezza solo per i pods di Fargate e non si dispone di nodi Amazon EC2 nel cluster, andare alla fase Implementare un'applicazione di esempio.

  1. Controlla la versione del Amazon VPC CNI plugin for Kubernetes corrente con il comando seguente:

    kubectl describe daemonset aws-node --namespace kube-system | grep amazon-k8s-cni: | cut -d : -f 3

    Di seguito è riportato l'output di esempio.

    v1.7.6

    Se la versione del Amazon VPC CNI plugin for Kubernetes è precedente alla 1.7.7, aggiorna il plug-in alla versione 1.7.7 o successiva. Per ulteriori informazioni, consultare Aggiornamento del componente aggiuntivo Amazon VPC CNI plugin for Kubernetes.

  2. Aggiungi la policy IAM gestita AmazonEKSVPCResourceController al ruolo del cluster associato al cluster Amazon EKS. La policy consente al ruolo di gestire le interfacce di rete, i relativi indirizzi IP privati e i relativi allegati e distacchi da e verso le istanze di rete.

    1. Recupera il nome del ruolo IAM del cluster e archivialo in una variabile. Sostituisci my-cluster con il nome del cluster.

      cluster_role=$(aws eks describe-cluster --name my-cluster --query cluster.roleArn --output text | cut -d / -f 2)
    2. Collegare la policy al ruolo.

      aws iam attach-role-policy --policy-arn arn:aws:iam::aws:policy/AmazonEKSVPCResourceController --role-name $cluster_role
  3. Abilitare il componente aggiuntivo CNI di Amazon VPC per gestire le interfacce di rete per i pods impostando la variabile ENABLE_POD_ENI su true nel aws-node DaemonSet. Una volta che questa impostazione è settata su true, per ogni nodo nel cluster il componente aggiuntivo aggiunge un'etichetta con il valore vpc.amazonaws.com/has-trunk-attached=true. Il controller di risorse VPC crea e allega un'interfaccia di rete speciale chiamata interfaccia di rete trunk con la descrizione aws-k8s-trunk-eni.

    kubectl set env daemonset aws-node -n kube-system ENABLE_POD_ENI=true
    Nota

    L'interfaccia di rete trunk è inclusa nel numero massimo di interfacce di rete supportate dal tipo di istanza. Per un elenco del numero massimo di interfacce di rete supportate da ciascun tipo di istanza, consultare la sezione Indirizzi IP per interfaccia di rete per tipo di istanza nella Guida per l'utente di Amazon EC2 per istanze Linux. Se il nodo ha già allegato il numero massimo di interfacce di rete standard, il controller di risorse VPC riserverà uno spazio. Sarà necessario ridurre i pods in esecuzione in modo sufficiente da consentire al controller di scollegare ed eliminare un'interfaccia di rete standard, creare l'interfaccia di rete trunk e allegarla all'istanza.

    É possibile vedere quale dei nodi ha aws-k8s-trunk-eni impostato su true con il seguente comando. Se viene restituito l'output No resources found, attendere alcuni secondi e riprovare. La fase precedente richiede il riavvio dei pods Amazon VPC CNI plugin for Kubernetes, operazione che richiede alcuni secondi.

    kubectl get nodes -o wide -l vpc.amazonaws.com/has-trunk-attached=true

    Una volta creata l'interfaccia di rete del trunk, ai pods possono essere assegnati indirizzi IP secondari dalla rete trunk o dalle interfacce di rete standard. L'interfaccia trunk viene eliminata automaticamente se il nodo viene eliminato.

    Quando si implementa un gruppo di sicurezza per un pod in una fase successiva, il controller di risorse VPC crea un'interfaccia di rete speciale denominata interfaccia di rete di filiali con una descrizione di aws-k8s-branch-eni e associa i gruppi di sicurezza. Le interfacce di rete di filiali vengono create in aggiunta alle interfacce di rete standard e trunk allegate al nodo. Se si utilizzano probe liveness o readiness, è inoltre necessario disabilitare il demux precoce TCP, in modo che il kubelet possa connettersi a pods su interfacce di rete di filiali tramite TCP. Per disabilitare TCP early demux, eseguire il comando seguente:

    kubectl patch daemonset aws-node -n kube-system \ -p '{"spec": {"template": {"spec": {"initContainers": [{"env":[{"name":"DISABLE_TCP_EARLY_DEMUX","value":"true"}],"name":"aws-vpc-cni-init"}]}}}}'
    Nota

    Non è necessario eseguire il comando precedente se si utilizza la versione 1.11.0 o successive del componente aggiuntivo Amazon VPC CNI plugin for Kubernetes e si imposta POD_SECURITY_GROUP_ENFORCING_MODE=standard, come descritto nella fase successiva.

  4. Se il cluster utilizza NodeLocal DNSCache, se desideri utilizzare la policy di rete Calico con i tuoi pods che dispongono dei propri gruppi di sicurezza, oppure se disponi di servizi Kubernetes di tipo NodePort e LoadBalancer che utilizzano le destinazioni di istanza con una externalTrafficPolicy impostata su Local per pods a cui desideri assegnare i gruppi di sicurezza, dovrai utilizzare la versione 1.11.0 o successiva del componente aggiuntivo Amazon VPC CNI plugin for Kubernetes e dovrai abilitare la seguente impostazione:

    kubectl set env daemonset aws-node -n kube-system POD_SECURITY_GROUP_ENFORCING_MODE=standard
    Importante
    • Le regole del gruppo di sicurezza per i Pod non si applicano al traffico tra pods o tra pods e services, ad esempio kubelet o nodeLocalDNS che si trovano sullo stesso nodo.

    • Traffico in uscita dai pods verso gli indirizzi esterni al VPC è l'indirizzo di rete convertito nell'indirizzo IP dell'interfaccia di rete primaria dell'istanza (a meno che non sia stato impostato AWS_VPC_K8S_CNI_EXTERNALSNAT=true). Per questo traffico vengono utilizzate le regole nei gruppi di sicurezza per l'interfaccia di rete primaria, anziché le regole nei gruppi di sicurezza dei pod's.

    • Affinché questa impostazione venga applicata ai pods esistenti, è necessario riavviare i pods o i nodi su cui sono in esecuzione i pods.

Implementare un'applicazione di esempio

Per utilizzare i gruppi di sicurezza per i pods, è necessario disporre di un gruppo di sicurezza esistente ed è necessario implementare un SecurityGroupPolicy di Amazon EKS nel cluster, come descritto nella procedura seguente. I passaggi seguenti mostrano l'utilizzo delle policy di gruppo di sicurezza per un pod. Se non diversamente indicato, completare tutti i passaggi nello stesso terminale, poiché nei passaggi successivi vengono utilizzate variabili che non persistono tra i terminali.

Per implementare un pod di esempio con un gruppo di sicurezza

  1. Crea uno spazio dei nomi Kubernetes in cui implementare le risorse. Puoi sostituire my-namespace con il nome di uno spazio dei nomi che desideri utilizzare.

    kubectl create namespace my-namespace
  2. Implementa una SecurityGroupPolicy Amazon EKS nel cluster.

    1. Copia i seguenti contenuti sul dispositivo. Puoi sostituire podSelector con serviceAccountSelector se preferisci selezionare i pods in base alle etichette degli account di servizio. É necessario specificare uno selettore. Un podSelector vuoto (ad esempio, podSelector: {}) seleziona tutti i pods nello spazio dei nomi. Puoi cambiare il my-role con il nome del tuo ruolo. Un serviceAccountSelector vuoto seleziona tutti gli account di servizio nello spazio dei nomi. Puoi sostituire my-security-group-policy con un nome per il tuo SecurityGroupPolicy e my-namespace con lo spazio dei nomi in cui desideri creare SecurityGroupPolicy.

      È necessario sostituire my_pod_security_group_id con l'ID di un gruppo di sicurezza esistente. Se non disponi ancora di un gruppo di sicurezza dovrai crearne uno. Per ulteriori informazioni, consulta Gruppi di sicurezza Amazon EC2 per le istanze Linux nella Guida per l'utente di Amazon EC2 per le istanze Linux. Puoi specificare da 1 a 5 ID gruppo di sicurezza. Se si specificano più ID, la combinazione di tutte le regole in tutti i gruppi di sicurezza sarà valida per i pods selezionati.

      cat >my-security-group-policy.yaml <<EOF apiVersion: vpcresources.k8s.aws/v1beta1 kind: SecurityGroupPolicy metadata: name: my-security-group-policy namespace: my-namespace spec: podSelector: matchLabels: role: my-role securityGroups: groupIds: - my_pod_security_group_id EOF
      Importante

      Il gruppo di sicurezza o i gruppi specificati per il pod devono soddisfare i criteri seguenti:

      • Devono essere esistenti. Se non lo sono, quando si implementa un pod che corrisponde al selettore, il pod rimane bloccato nel processo di creazione. Se si descrive il pod, si otterrà un messaggio di errore simile al seguente: An error occurred (InvalidSecurityGroupID.NotFound) when calling the CreateNetworkInterface operation: The securityGroup ID 'sg-05b1d815d1EXAMPLE' does not exist.

      • Devono consentire la comunicazione in ingresso dal gruppo di sicurezza applicato ai nodi (per kubelet) su tutte le porte per cui sono state configurate le sonde.

      • Devono consentire la comunicazione in uscita tramite le porte 53 TCP e UDP a un gruppo di sicurezza assegnato ai pods (o ai nodi su cui sono eseguiti i pods) che eseguono CoreDNS. Il gruppo di sicurezza per i pods CoreDNS deve consentire il traffico in ingresso tramite le porte 53 TCP e UDP dal gruppo di sicurezza specificato.

      • Devono disporre delle regole in entrata e in uscita necessarie per comunicare con altri pods.

      • Devono disporre di regole che consentano ai pods di comunicare con il piano di controllo di Kubernetes se utilizzi il gruppo di sicurezza con Fargate. Il modo più semplice per eseguire questa operazione consiste nello specificare il gruppo di sicurezza del cluster come uno dei gruppi di sicurezza.

      Le policy dei gruppi di sicurezza si applicano solo ai nuovi pods pianificati. Non incidono sui pods in esecuzione.

    2. Implementare la policy.

      kubectl apply -f my-security-group-policy.yaml
  3. Implementa un'applicazione di esempio con un'etichetta che corrisponda al valore my-role per podSelector specificato nel passaggio precedente.

    1. Copia i seguenti contenuti sul dispositivo. Sostituisci i valori di esempio con i tuoi, quindi esegui il comando modificato. Se sostituisci il my-role, assicurati che sia uguale al valore che hai specificato per il selettore in un passaggio precedente.

      cat >sample-application.yaml <<EOF apiVersion: apps/v1 kind: Deployment metadata: name: my-deployment namespace: my-namespace labels: app: my-app spec: replicas: 4 selector: matchLabels: app: my-app template: metadata: labels: app: my-app role: my-role spec: terminationGracePeriodSeconds: 120 containers: - name: nginx image: public.ecr.aws/nginx/nginx:1.23 ports: - containerPort: 80 --- apiVersion: v1 kind: Service metadata: name: my-app namespace: my-namespace labels: app: my-app spec: selector: app: my-app ports: - protocol: TCP port: 80 targetPort: 80 EOF
    2. Implementare l'applicazione con il seguente comando. Quando si implementa l'applicazione, il Amazon VPC CNI plugin for Kubernetes corrisponde all'etichetta role e i gruppi di sicurezza specificati nel passaggio precedente vengono applicati al pod.

      kubectl apply -f sample-application.yaml
  4. Visualizza i pods implementati con l'applicazione di esempio. Nella parte restante di questo argomento, questo terminale è indicato come TerminalA.

    kubectl get pods -n my-namespace -o wide

    Di seguito è riportato l'output di esempio.

    NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES my-deployment-5df6f7687b-4fbjm 1/1 Running 0 7m51s 192.168.53.48 ip-192-168-33-28.region-code.compute.internal <none> <none> my-deployment-5df6f7687b-j9fl4 1/1 Running 0 7m51s 192.168.70.145 ip-192-168-92-33.region-code.compute.internal <none> <none> my-deployment-5df6f7687b-rjxcz 1/1 Running 0 7m51s 192.168.73.207 ip-192-168-92-33.region-code.compute.internal <none> <none> my-deployment-5df6f7687b-zmb42 1/1 Running 0 7m51s 192.168.63.27 ip-192-168-33-28.region-code.compute.internal <none> <none>
    Nota
    • Se dei pods sono bloccati nello stato Waiting, esegui kubectl describe pod my-deployment-xxxxxxxxxx-xxxxx -n my-namespace. Se visualizzi Insufficient permissions: Unable to create Elastic Network Interface., verifica di avere aggiunto la policy IAM al ruolo cluster IAM in un passaggio precedente.

    • Se dei pod sono bloccati nello stato Pending, verifica che il tipo di istanza del nodo sia elencato in limits.go e che non sia già stato raggiunto il prodotto del numero massimo di interfacce di rete di filiali supportate dal tipo di istanza moltiplicato per il numero di nodi nel gruppo di nodi. Ad esempio, una istanza m5.large supporta nove interfacce di rete di filiali. Se il gruppo di nodi dispone di cinque nodi, è possibile creare un massimo di 45 interfacce di rete di filiali per il gruppo di nodi. Il 46° pod che si tenta di implementare si troverà in uno stato di Pending finché non viene eliminato un altro pod a cui sono associati gruppi di sicurezza.

    Se si esegue kubectl describe pod my-deployment-xxxxxxxxxx-xxxxx -n my-namespace e si visualizza un messaggio simile al seguente, può essere ignorato in modo sicuro. Questo messaggio potrebbe essere visualizzato quando il Amazon VPC CNI plugin for Kubernetes tenta di impostare la rete host e fallisce durante la creazione dell'interfaccia di rete. Il plug-in registra questo evento fino a quando non viene creata l'interfaccia di rete.

    Failed to create pod sandbox: rpc error: code = Unknown desc = failed to set up sandbox container "e24268322e55c8185721f52df6493684f6c2c3bf4fd59c9c121fd4cdc894579f" network for pod "my-deployment-5df6f7687b-4fbjm": networkPlugin cni failed to set up pod "my-deployment-5df6f7687b-4fbjm-c89wx_my-namespace" network: add cmd: failed to assign an IP address to container

    Non è possibile superare il numero massimo di pods eseguibili sul tipo di istanza. Per un elenco del numero massimo di pods che è possibile eseguire su ogni tipo di istanza, consulta eni-max-pods.txt su GitHub. Quando si elimina un pod a cui sono associati gruppi di sicurezza o si elimina il nodo su cui è in esecuzione il pod, il controller di risorse VPC elimina l'interfaccia di rete di filiali. Se si elimina un cluster con pods che utilizzano pods per i gruppi di sicurezza, il controller non elimina le interfacce di rete di filiali. Sarà quindi necessario eliminarle personalmente.

  5. In un terminale separato, inserisci nella shell uno dei pods. Nella parte restante di questo argomento, questo terminale è indicato come TerminalB. Sostituisci 5df6f7687b-4fbjm con l'ID di uno dei pods restituiti nell'output della fase precedente.

    kubectl exec -it -n my-namespace my-deployment-5df6f7687b-4fbjm -- /bin/bash
  6. Confermare il funzionamento dell'applicazione di esempio dalla shell in TerminalB.

    curl my-app

    Di seguito è riportato l'output di esempio.

    <!DOCTYPE html> <html> <head> <title>Welcome to nginx!</title> ...

    L'output è stato ricevuto in quanto tutti i pods che eseguono l'applicazione sono associati al gruppo di sicurezza creato. Tale gruppo contiene una regola che abilita il traffico tra tutti i pods a cui è associato il gruppo di sicurezza. Il traffico DNS è consentito in uscita da tale gruppo di sicurezza al gruppo di sicurezza del cluster associato ai nodi. I nodi eseguono i pods CoreDNS, su cui i pods hanno eseguito la ricerca del nome.

  7. Da TerminalA, rimuovere le regole del gruppo di sicurezza che consentono la comunicazione DNS dal gruppo di sicurezza al gruppo di sicurezza del cluster. Se in una fase precedente non hai aggiunto le regole DNS al gruppo di sicurezza del cluster, sostituisci $my_cluster_security_group_id con l'ID del gruppo di sicurezza in cui sono state create le regole.

    aws ec2 revoke-security-group-ingress --group-id $my_cluster_security_group_id --security-group-rule-ids $my_tcp_rule_id aws ec2 revoke-security-group-ingress --group-id $my_cluster_security_group_id --security-group-rule-ids $my_udp_rule_id
  8. Tentare di accedere nuovamente all'applicazione da TerminalB.

    curl my-app

    Di seguito è riportato l'output di esempio.

    curl: (6) Could not resolve host: my-app

    Il tentativo ha esito negativo perché il pod non è più in grado di accedere ai pods CoreDNS a cui è associato il gruppo di sicurezza del cluster. Il gruppo di sicurezza del cluster non dispone più delle relative regole che consentono la comunicazione DNS dal gruppo di sicurezza associato al pod.

    Se si tenta di accedere all'applicazione utilizzando gli indirizzi IP restituiti in una fase precedente per uno dei pods, si riceve comunque una risposta perché tutte le porte sono consentite tra i pods a cui è associato il gruppo di sicurezza e non è necessaria una ricerca del nome.

  9. Dopo avere eseguito diverse prove, è possibile rimuovere la policy del gruppo di sicurezza, l'applicazione e il gruppo di sicurezza di esempio creati. Esegui i comandi seguenti da TerminalA.

    kubectl delete namespace my-namespace aws ec2 revoke-security-group-ingress --group-id $my_pod_security_group_id --security-group-rule-ids $my_inbound_self_rule_id wait sleep 45s aws ec2 delete-security-group --group-id $my_pod_security_group_id