Het ABC van beveiliging in Kubernetes: authenticatie, autorisatie, auditing

Het ABC van beveiliging in Kubernetes: authenticatie, autorisatie, auditing

Vroeg of laat komt bij de werking van elk systeem de kwestie van veiligheid aan de orde: het waarborgen van authenticatie, scheiding van rechten, auditing en andere taken. Al gemaakt voor Kubernetes veel oplossingen, waarmee u zelfs in zeer veeleisende omgevingen aan de normen kunt voldoen... Hetzelfde materiaal is gewijd aan de basisaspecten van beveiliging die zijn geïmplementeerd in de ingebouwde mechanismen van de K8s. Allereerst zal het nuttig zijn voor degenen die kennis maken met Kubernetes - als startpunt voor het bestuderen van beveiligingsgerelateerde kwesties.

authenticatie

Er zijn twee soorten gebruikers in Kubernetes:

  • Serviceaccounts — accounts beheerd door de Kubernetes API;
  • Gebruikers — “normale” gebruikers beheerd door externe, onafhankelijke diensten.

Het belangrijkste verschil tussen deze typen is dat er voor serviceaccounts speciale objecten zijn in de Kubernetes API (ze worden zo genoemd: ServiceAccounts), die zijn gekoppeld aan een naamruimte en een set autorisatiegegevens die in het cluster zijn opgeslagen in objecten van het type Geheimen. Dergelijke gebruikers (Service Accounts) zijn primair bedoeld voor het beheren van toegangsrechten tot de Kubernetes API van processen die in het Kubernetes cluster draaien.

Gewone gebruikers hebben geen vermeldingen in de Kubernetes API: ze moeten worden beheerd door externe mechanismen. Ze zijn bedoeld voor mensen of processen die buiten het cluster wonen.

Elk API-verzoek is gekoppeld aan een serviceaccount of een gebruiker of wordt als anoniem beschouwd.

Gebruikersauthenticatiegegevens omvatten:

  • Gebruikersnaam — gebruikersnaam (hoofdlettergevoelig!);
  • UID - een machinaal leesbare gebruikersidentificatiereeks die “consistentiever en unieker is dan de gebruikersnaam”;
  • Groepen — lijst met groepen waartoe de gebruiker behoort;
  • Extra — aanvullende velden die door het autorisatiemechanisme kunnen worden gebruikt.

Kubernetes kan een groot aantal authenticatiemechanismen gebruiken: X509-certificaten, Bearer-tokens, authenticatieproxy, HTTP Basic Auth. Met deze mechanismen kunt u een groot aantal autorisatieschema’s implementeren: van een statisch bestand met wachtwoorden tot OpenID OAuth2.

Bovendien is het mogelijk om meerdere autorisatieschema's tegelijkertijd te gebruiken. Standaard gebruikt het cluster:

  • serviceaccounttokens - voor serviceaccounts;
  • X509 - voor gebruikers.

De vraag over het beheren van ServiceAccounts valt buiten het bestek van dit artikel, maar voor degenen die zich meer in detail met dit probleem willen verdiepen, raad ik aan te beginnen met officiële documentatiepagina's. We zullen de kwestie van hoe X509-certificaten werken nader bekijken.

Certificaten voor gebruikers (X.509)

De klassieke manier van werken met certificaten omvat:

  • sleutel generatie:
    mkdir -p ~/mynewuser/.certs/
    openssl genrsa -out ~/.certs/mynewuser.key 2048
  • een certificaataanvraag genereren:
    openssl req -new -key ~/.certs/mynewuser.key -out ~/.certs/mynewuser.csr -subj "/CN=mynewuser/O=company"
  • het verwerken van een certificaataanvraag met behulp van de Kubernetes cluster CA-sleutels, het verkrijgen van een gebruikerscertificaat (om een ​​certificaat te verkrijgen moet u een account gebruiken dat toegang heeft tot de Kubernetes cluster CA-sleutel, die zich standaard bevindt in /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
  • een configuratiebestand maken:
    • clusterbeschrijving (geef het adres en de locatie op van het CA-certificaatbestand voor een specifieke clusterinstallatie):
      kubectl config set-cluster kubernetes --certificate-authority=/etc/kubernetes/pki/ca.crt --server=https://192.168.100.200:6443
    • of hoe geenaanbevolen optie - u hoeft het rootcertificaat niet op te geven (dan zal kubectl de juistheid van de api-server van het cluster niet controleren):
      kubectl config set-cluster kubernetes  --insecure-skip-tls-verify=true --server=https://192.168.100.200:6443
    • een gebruiker toevoegen aan het configuratiebestand:
      kubectl config set-credentials mynewuser --client-certificate=.certs/mynewuser.crt  --client-key=.certs/mynewuser.key
    • context toevoegen:
      kubectl config set-context mynewuser-context --cluster=kubernetes --namespace=target-namespace --user=mynewuser
    • standaard contexttoewijzing:
      kubectl config use-context mynewuser-context

Na de bovenstaande manipulaties, in het bestand .kube/config een configuratie als deze wordt gemaakt:

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.key

Om het gemakkelijker te maken om de configuratie tussen accounts en servers over te dragen, is het handig om de waarden van de volgende sleutels te bewerken:

  • certificate-authority
  • client-certificate
  • client-key

Om dit te doen, kunt u de daarin gespecificeerde bestanden coderen met base64 en ze in de configuratie registreren, waarbij u het achtervoegsel aan de naam van de sleutels toevoegt -data, d.w.z. te hebben ontvangen certificate-authority-data etc.

Certificaten met kubeadm

Met de uitgave Kubernetes 1.15 het werken met certificaten is veel eenvoudiger geworden dankzij de alfaversie van de ondersteuning in kubeadm-hulpprogramma. Dit is bijvoorbeeld hoe het genereren van een configuratiebestand met gebruikerssleutels er nu uit zou kunnen zien:

kubeadm alpha kubeconfig user --client-name=mynewuser --apiserver-advertise-address 192.168.100.200

NB: Vereist adres adverteren is te vinden in de api-serverconfiguratie, die zich standaard bevindt in /etc/kubernetes/manifests/kube-apiserver.yaml.

De resulterende configuratie wordt uitgevoerd naar stdout. Er moet in worden opgeslagen ~/.kube/config gebruikersaccount of naar een bestand dat is opgegeven in een omgevingsvariabele KUBECONFIG.

Graaf dieper

Voor degenen die de beschreven problemen grondiger willen begrijpen:

Machtiging

Het standaard geautoriseerde account heeft geen rechten om op het cluster te werken. Om machtigingen te verlenen implementeert Kubernetes een autorisatiemechanisme.

Vóór versie 1.6 gebruikte Kubernetes een autorisatietype genaamd ABAC (Attribuutgebaseerde toegangscontrole). Details hierover zijn te vinden in officiële documentatie. Deze aanpak wordt momenteel als verouderd beschouwd, maar u kunt deze nog steeds naast andere authenticatietypen gebruiken.

De huidige (en flexibelere) manier om toegangsrechten tot een cluster te verdelen heet RBAC (Op rollen gebaseerde toegangscontrole). Het is sinds de versie stabiel verklaard Kubernetes 1.8. RBAC implementeert een rechtenmodel waarin alles wat niet expliciet is toegestaan, verboden is.
Om RBAC in te schakelen, moet u Kubernetes api-server starten met de parameter --authorization-mode=RBAC. De parameters worden in het manifest ingesteld met de api-serverconfiguratie, die zich standaard langs het pad bevindt /etc/kubernetes/manifests/kube-apiserver.yaml, in sectie command. RBAC is echter standaard al ingeschakeld, dus u hoeft zich daar waarschijnlijk geen zorgen over te maken: u kunt dit verifiëren aan de hand van de waarde authorization-mode (in het reeds genoemde kube-apiserver.yaml). Tussen haakjes, onder de betekenissen kunnen er andere soorten autorisatie zijn (node, webhook, always allow), maar we laten hun beschouwing buiten de reikwijdte van het materiaal.

We hebben het trouwens al gepubliceerd статью met een vrij gedetailleerde beschrijving van de principes en kenmerken van het werken met RBAC, dus verder zal ik mezelf beperken tot een korte opsomming van de basisprincipes en voorbeelden.

De volgende API-entiteiten worden gebruikt om de toegang in Kubernetes via RBAC te beheren:

  • Role и ClusterRole — rollen die dienen om toegangsrechten te beschrijven:
  • Role stelt u in staat rechten binnen een naamruimte te beschrijven;
  • ClusterRole - binnen het cluster, inclusief clusterspecifieke objecten zoals knooppunten, niet-resources-URL's (d.w.z. niet gerelateerd aan Kubernetes-resources - bijvoorbeeld /version, /logs, /api*);
  • RoleBinding и ClusterRoleBinding - gebruikt voor binding Role и ClusterRole aan een gebruiker, gebruikersgroep of ServiceAccount.

De Role- en RoleBinding-entiteiten worden beperkt door de naamruimte, d.w.z. moet zich binnen dezelfde naamruimte bevinden. Een RoleBinding kan echter verwijzen naar een ClusterRole, waarmee u een set algemene machtigingen kunt maken en de toegang hiermee kunt beheren.

Rollen beschrijven rechten met behulp van sets regels die het volgende bevatten:

  • API-groepen - zie officiële documentatie door apiGroups en uitvoer kubectl api-resources;
  • bronnen (resources: pod, namespace, deployment enzovoort.);
  • Werkwoorden (werkwoorden: set, update etc.).
  • resourcenamen (resourceNames) - voor het geval dat u toegang moet verlenen tot een specifieke bron, en niet tot alle bronnen van dit type.

Een meer gedetailleerde analyse van autorisatie in Kubernetes vindt u op de pagina officiële documentatie. In plaats daarvan (of beter gezegd, in aanvulling hierop) zal ik voorbeelden geven die haar werk illustreren.

Voorbeelden van RBAC-entiteiten

eenvoudig Role, waarmee u een lijst en status van pods kunt krijgen en deze in de naamruimte kunt controleren 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"]

Voorbeeld ClusterRole, waarmee u een lijst en status van pods kunt krijgen en deze in het hele cluster kunt controleren:

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  # секции "namespace" нет, так как ClusterRole задействует весь кластер
  name: secret-reader
rules:
- apiGroups: [""]
  resources: ["secrets"]
  verbs: ["get", "watch", "list"]

Voorbeeld RoleBinding, waarmee de gebruiker kan mynewuser "lees"-pods in de naamruimte my-namespace:

apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: read-pods
  namespace: target-namespace
subjects:
- kind: User
  name: mynewuser # имя пользователя зависимо от регистра!
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: Role # здесь должно быть “Role” или “ClusterRole”
  name: pod-reader # имя Role, что находится в том же namespace,
                   # или имя ClusterRole, использование которой
                   # хотим разрешить пользователю
  apiGroup: rbac.authorization.k8s.io

Evenementaudit

Schematisch kan de Kubernetes-architectuur als volgt worden weergegeven:

Het ABC van beveiliging in Kubernetes: authenticatie, autorisatie, auditing

De belangrijkste Kubernetes-component die verantwoordelijk is voor het verwerken van verzoeken is api-server. Alle bewerkingen op het cluster gaan er doorheen. Meer over deze interne mechanismen kun je lezen in het artikel “Wat gebeurt er in Kubernetes wanneer u kubectl run uitvoert?.

Systeemauditing is een interessante functie in Kubernetes, die standaard is uitgeschakeld. Hiermee kunt u alle oproepen naar de Kubernetes API loggen. Zoals u wellicht kunt raden, worden alle acties met betrekking tot het monitoren en wijzigen van de status van het cluster via deze API uitgevoerd. Een goede beschrijving van de mogelijkheden is (zoals gebruikelijk) te vinden in officiële documentatie K8's. Vervolgens zal ik proberen het onderwerp in eenvoudiger taal te presenteren.

aldus om auditing mogelijk te maken, moeten we drie vereiste parameters doorgeven aan de container in api-server, die hieronder in meer detail worden beschreven:

  • --audit-policy-file=/etc/kubernetes/policies/audit-policy.yaml
  • --audit-log-path=/var/log/kube-audit/audit.log
  • --audit-log-format=json

Naast deze drie noodzakelijke parameters zijn er veel aanvullende instellingen met betrekking tot auditing: van logrotatie tot webhookbeschrijvingen. Voorbeeld van logrotatieparameters:

  • --audit-log-maxbackup=10
  • --audit-log-maxsize=100
  • --audit-log-maxage=7

Maar we zullen er niet dieper op ingaan - u kunt alle details vinden in kube-apiserver-documentatie.

Zoals reeds vermeld, worden alle parameters in het manifest ingesteld met de api-serverconfiguratie (standaard /etc/kubernetes/manifests/kube-apiserver.yaml), in sectie command. Laten we terugkeren naar de 3 vereiste parameters en deze analyseren:

  1. audit-policy-file — pad naar het YAML-bestand dat het auditbeleid beschrijft. We komen later op de inhoud terug, maar voor nu merk ik op dat het bestand leesbaar moet zijn door het api-serverproces. Daarom is het noodzakelijk om het in de container te monteren, waarvoor u de volgende code aan de juiste secties van de configuratie kunt toevoegen:
      volumeMounts:
        - mountPath: /etc/kubernetes/policies
          name: policies
          readOnly: true
      volumes:
      - hostPath:
          path: /etc/kubernetes/policies
          type: DirectoryOrCreate
        name: policies
  2. audit-log-path — pad naar het logbestand. Het pad moet ook toegankelijk zijn voor het api-serverproces, dus beschrijven we de montage ervan op dezelfde manier:
      volumeMounts:
        - mountPath: /var/log/kube-audit
          name: logs
          readOnly: false
      volumes:
      - hostPath:
          path: /var/log/kube-audit
          type: DirectoryOrCreate
        name: logs
  3. audit-log-format — auditlogboekformaat. De standaardwaarde is json, maar het oudere tekstformaat is ook beschikbaar (legacy).

Auditbeleid

Nu over het genoemde bestand dat het logbeleid beschrijft. Het eerste concept van auditbeleid is level, logniveau. Ze zijn als volgt:

  • None - niet inloggen;
  • Metadata — metadata van logverzoeken: gebruiker, verzoektijdstip, doelbron (pod, naamruimte, enz.), actietype (werkwoord), enz.;
  • Request — log metadata en verzoektekst;
  • RequestResponse — log-metagegevens, verzoektekst en antwoordtekst.

De laatste twee niveaus (Request и RequestResponse) log geen verzoeken in die geen toegang hebben tot bronnen (toegang tot zogenaamde niet-resources-URL's).

Ook alle aanvragen komen door verschillende stages:

  • RequestReceived — het stadium waarin het verzoek door de verwerker wordt ontvangen en nog niet verder in de keten van verwerkers is verzonden;
  • ResponseStarted — antwoordheaders worden verzonden, maar voordat de antwoordtekst wordt verzonden. Gegenereerd voor langlopende zoekopdrachten (bijvoorbeeld watch);
  • ResponseComplete — de antwoordtekst is verzonden; er wordt geen informatie meer verzonden;
  • Panic — gebeurtenissen worden gegenereerd wanneer een abnormale situatie wordt gedetecteerd.

Om stappen over te slaan die u kunt gebruiken omitStages.

In een beleidsbestand kunnen we verschillende secties beschrijven met verschillende logniveaus. De eerste matchingregel die in de polisbeschrijving wordt gevonden, wordt toegepast.

De kubelet-daemon bewaakt wijzigingen in het manifest met de api-server-configuratie en start, als deze worden gedetecteerd, de container opnieuw op met api-server. Maar er is een belangrijk detail: wijzigingen in het beleidsbestand worden erdoor genegeerd. Nadat u wijzigingen in het beleidsbestand hebt aangebracht, moet u de api-server handmatig opnieuw opstarten. Omdat api-server is gestart als statische pod, team kubectl delete zal er niet voor zorgen dat het opnieuw opstart. Je zult het handmatig moeten doen docker stop op kube-masters, waar het auditbeleid is gewijzigd:

docker stop $(docker ps | grep k8s_kube-apiserver | awk '{print $1}')

Wanneer u auditing inschakelt, is het belangrijk om dat te onthouden de belasting op kube-apiserver neemt toe. In het bijzonder neemt het geheugengebruik voor het opslaan van verzoekcontext toe. Het loggen begint pas nadat de antwoordheader is verzonden. De belasting is ook afhankelijk van de configuratie van het auditbeleid.

Voorbeelden van beleid

Laten we de structuur van beleidsbestanden bekijken aan de hand van voorbeelden.

Hier is een eenvoudig bestand policyom alles op niveau te loggen Metadata:

apiVersion: audit.k8s.io/v1
kind: Policy
rules:
- level: Metadata

In beleid kunt u een lijst met gebruikers opgeven (Users и ServiceAccounts) en gebruikersgroepen. Zo negeren we bijvoorbeeld systeemgebruikers, maar loggen we al het andere op niveau 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: Request

Het is ook mogelijk om de doelstellingen te beschrijven:

  • naamruimten (namespaces);
  • Werkwoorden (werkwoorden: get, update, delete en anderen);
  • bronnen (resources, namelijk: pod, configmaps enz.) en resourcegroepen (apiGroups).

Let op! Resources en resourcegroepen (API-groepen, d.w.z. apiGroups), evenals hun versies die in het cluster zijn geïnstalleerd, kunnen worden verkregen met behulp van de opdrachten:

kubectl api-resources
kubectl api-versions

Het volgende auditbeleid wordt gegeven als demonstratie van best practices op het gebied van: Alibaba Cloud-documentatie:

apiVersion: audit.k8s.io/v1beta1
kind: Policy
# Не логировать стадию RequestReceived
omitStages:
  - "RequestReceived"
rules:
  # Не логировать события, считающиеся малозначительными и не опасными:
  - level: None
    users: ["system:kube-proxy"]
    verbs: ["watch"]
    resources:
      - group: "" # это api group с пустым именем, к которому относятся
                  # базовые ресурсы Kubernetes, называемые “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"]
  # Не логировать обращения к read-only URLs:
  - level: None
    nonResourceURLs:
      - /healthz*
      - /version
      - /swagger*
  # Не логировать сообщения, относящиеся к типу ресурсов “события”:
  - level: None
    resources:
      - group: "" # core
        resources: ["events"]
  # Ресурсы типа Secret, ConfigMap и TokenReview могут содержать  секретные данные,
  # поэтому логируем только метаданные связанных с ними запросов
  - level: Metadata
    resources:
      - group: "" # core
        resources: ["secrets", "configmaps"]
      - group: authentication.k8s.io
        resources: ["tokenreviews"]
  # Действия типа get, list и watch могут быть ресурсоёмкими; не логируем их
  - 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"
  # Уровень логирования по умолчанию для стандартных ресурсов API
  - 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"
  # Уровень логирования по умолчанию для всех остальных запросов
  - level: Metadata

Een ander goed voorbeeld van auditbeleid is profiel gebruikt in GCE.

Snel reageren op auditgebeurtenissen is mogelijk webhook beschrijven. Deze kwestie wordt behandeld in officiële documentatie, ik laat het buiten het bestek van dit artikel.

Resultaten van

Het artikel geeft een overzicht van basisbeveiligingsmechanismen in Kubernetes-clusters, waarmee u gepersonaliseerde gebruikersaccounts kunt maken, hun rechten kunt scheiden en hun acties kunt vastleggen. Ik hoop dat het nuttig zal zijn voor degenen die in theorie of in de praktijk met dergelijke kwesties worden geconfronteerd. Ik raad u ook aan om de lijst met ander materiaal over het onderwerp beveiliging in Kubernetes te lezen, die wordt gegeven in "PS" - misschien vindt u daaronder de nodige details over de problemen die voor u relevant zijn.

PS

Lees ook op onze blog:

Bron: www.habr.com

Voeg een reactie