ABC för säkerhet i Kubernetes: Autentisering, auktorisering, revision

ABC för säkerhet i Kubernetes: Autentisering, auktorisering, revision

Förr eller senare, i driften av alla system, uppstår frågan om säkerhet: säkerställande av autentisering, åtskillnad av rättigheter, revision och andra uppgifter. Redan skapad för Kubernetes många lösningar, som gör att du kan uppnå överensstämmelse med standarder även i mycket krävande miljöer... Samma material ägnas åt de grundläggande säkerhetsaspekterna som implementeras inom de inbyggda mekanismerna i K8s. Först och främst kommer det att vara användbart för dem som börjar bekanta sig med Kubernetes – som en utgångspunkt för att studera säkerhetsrelaterade frågor.

autentisering

Det finns två typer av användare i Kubernetes:

  • Servicekonton — konton som hanteras av Kubernetes API;
  • användare — "normala" användare som hanteras av externa, oberoende tjänster.

Huvudskillnaden mellan dessa typer är att det för tjänstekonton finns speciella objekt i Kubernetes API (de kallas det - ServiceAccounts), som är knutna till ett namnområde och en uppsättning auktoriseringsdata lagrade i klustret i objekt av typen Secrets. Sådana användare (tjänstkonton) är i första hand avsedda att hantera åtkomsträttigheter till Kubernetes API för processer som körs i Kubernetes-klustret.

Vanliga användare har inga poster i Kubernetes API: de måste hanteras av externa mekanismer. De är avsedda för människor eller processer som lever utanför klustret.

Varje API-begäran är kopplad till antingen ett tjänstkonto, en användare eller anses vara anonym.

Användarautentiseringsdata inkluderar:

  • Användarnamn — användarnamn (skiftlägeskänsligt!);
  • UID - en maskinläsbar användaridentifikationssträng som är "mer konsekvent och unik än användarnamnet";
  • Grupper — lista över grupper som användaren tillhör.
  • extra — Ytterligare fält som kan användas av tillståndsmekanismen.

Kubernetes kan använda ett stort antal autentiseringsmekanismer: X509-certifikat, bärartokens, autentiseringsproxy, HTTP Basic Auth. Genom att använda dessa mekanismer kan du implementera ett stort antal auktoriseringsscheman: från en statisk fil med lösenord till OpenID OAuth2.

Dessutom är det möjligt att använda flera auktoriseringssystem samtidigt. Som standard använder klustret:

  • tjänstkontotokens - för tjänstekonton;
  • X509 - för användare.

Frågan om att hantera ServiceAccounts ligger utanför ramen för den här artikeln, men för den som vill bekanta sig mer med denna fråga rekommenderar jag att börja med officiella dokumentationssidor. Vi kommer att titta närmare på frågan om hur X509-certifikat fungerar.

Certifikat för användare (X.509)

Det klassiska sättet att arbeta med certifikat innebär:

  • nyckelgenerering:
    mkdir -p ~/mynewuser/.certs/
    openssl genrsa -out ~/.certs/mynewuser.key 2048
  • generera en certifikatbegäran:
    openssl req -new -key ~/.certs/mynewuser.key -out ~/.certs/mynewuser.csr -subj "/CN=mynewuser/O=company"
  • behandla en certifikatbegäran med Kubernetes kluster CA-nycklar, skaffa ett användarcertifikat (för att få ett certifikat måste du använda ett konto som har åtkomst till Kubernetes kluster CA-nyckel, som som standard finns i /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
  • skapa en konfigurationsfil:
    • klusterbeskrivning (ange adressen och platsen för CA-certifikatfilen för en specifik klusterinstallation):
      kubectl config set-cluster kubernetes --certificate-authority=/etc/kubernetes/pki/ca.crt --server=https://192.168.100.200:6443
    • eller hur ingenrekommenderat alternativ - du behöver inte ange rotcertifikatet (då kontrollerar kubectl inte riktigheten av klustrets api-server):
      kubectl config set-cluster kubernetes  --insecure-skip-tls-verify=true --server=https://192.168.100.200:6443
    • lägga till en användare i konfigurationsfilen:
      kubectl config set-credentials mynewuser --client-certificate=.certs/mynewuser.crt  --client-key=.certs/mynewuser.key
    • lägga till sammanhang:
      kubectl config set-context mynewuser-context --cluster=kubernetes --namespace=target-namespace --user=mynewuser
    • standardkontexttilldelning:
      kubectl config use-context mynewuser-context

Efter ovanstående manipulationer, i filen .kube/config en konfiguration som denna kommer att skapas:

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

För att göra det enklare att överföra konfigurationen mellan konton och servrar är det användbart att redigera värdena för följande nycklar:

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

För att göra detta kan du koda filerna som anges i dem med base64 och registrera dem i konfigurationen, lägga till suffixet till namnet på nycklarna -data, dvs. ha fått certificate-authority-data etc.

Certifikat med kubeadm

Med releasen Kubernetes 1.15 att arbeta med certifikat har blivit mycket lättare tack vare alfaversionen av dess stöd i kubeadm verktyg. Till exempel kan det se ut så här att generera en konfigurationsfil med användarnycklar:

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

NB: Krävs annonsera adress kan hittas i api-serverkonfigurationen, som som standard finns i /etc/kubernetes/manifests/kube-apiserver.yaml.

Den resulterande konfigurationen kommer att matas ut till stdout. Det måste sparas in ~/.kube/config användarkonto eller till en fil specificerad i en miljövariabel KUBECONFIG.

Gräv djupare

För den som vill förstå de problem som beskrivs mer ingående:

Bemyndigande

Det auktoriserade standardkontot har inte rättigheter att arbeta på klustret. För att ge behörigheter implementerar Kubernetes en auktoriseringsmekanism.

Före version 1.6 använde Kubernetes en auktoriseringstyp som heter ABAC (Attributbaserad åtkomstkontroll). Detaljer om det finns i officiell dokumentation. Denna metod anses för närvarande vara äldre, men du kan fortfarande använda den tillsammans med andra autentiseringstyper.

Det nuvarande (och mer flexibla) sättet att dela åtkomsträttigheter till ett kluster kallas RBAC (Rollbaserad åtkomstkontroll). Den har förklarats stabil sedan versionen Kubernetes 1.8. RBAC implementerar en rättighetsmodell där allt som inte är uttryckligen tillåtet är förbjudet.
För att aktivera RBAC, måste du starta Kubernetes api-server med parametern --authorization-mode=RBAC. Parametrarna ställs in i manifestet med api-serverkonfigurationen, som som standard är placerad längs vägen /etc/kubernetes/manifests/kube-apiserver.yaml, i avsnitt command. Men RBAC är redan aktiverat som standard, så troligtvis bör du inte oroa dig för det: du kan verifiera detta med värdet authorization-mode (i det redan nämnda kube-apiserver.yaml). Förresten, bland dess betydelser kan det finnas andra typer av auktorisation (node, webhook, always allow), men vi kommer att lämna deras övervägande utanför materialets omfattning.

Förresten, vi har redan publicerat Artikel med en ganska detaljerad beskrivning av principerna och funktionerna i att arbeta med RBAC, så vidare kommer jag att begränsa mig till en kort lista över grunderna och exemplen.

Följande API-entiteter används för att kontrollera åtkomst i Kubernetes via RBAC:

  • Role и ClusterRole — roller som tjänar till att beskriva åtkomsträttigheter:
  • Role låter dig beskriva rättigheter inom ett namnområde;
  • ClusterRole - inom klustret, inklusive till klusterspecifika objekt som noder, icke-resurs-urls (dvs inte relaterade till Kubernetes-resurser - till exempel, /version, /logs, /api*);
  • RoleBinding и ClusterRoleBinding - används för bindning Role и ClusterRole till en användare, användargrupp eller ServiceAccount.

Entiteterna Roll och RoleBinding begränsas av namnutrymme, dvs. måste finnas inom samma namnområde. En RoleBinding kan dock referera till en ClusterRole, vilket gör att du kan skapa en uppsättning generiska behörigheter och kontrollera åtkomst med hjälp av dem.

Roller beskriver rättigheter med hjälp av uppsättningar regler som innehåller:

  • API-grupper - se officiell dokumentation av apiGroups och utdata kubectl api-resources;
  • Resurser (medel: pod, namespace, deployment och så vidare.);
  • Verb (verb: set, update etc).
  • resursnamn (resourceNames) - för det fall du behöver ge åtkomst till en specifik resurs och inte till alla resurser av denna typ.

En mer detaljerad analys av auktorisation i Kubernetes finns på sidan officiell dokumentation. Istället (eller snarare, utöver detta) kommer jag att ge exempel som illustrerar hennes arbete.

Exempel på RBAC-enheter

Enkel Role, som låter dig få en lista och status för poddar och övervaka dem i namnområdet 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"]

Exempel ClusterRole, som låter dig få en lista och status för poddar och övervaka dem i hela klustret:

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

Exempel RoleBinding, vilket tillåter användaren mynewuser "läs" poddar i namnutrymmet 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

Event revision

Schematiskt kan Kubernetes-arkitekturen representeras enligt följande:

ABC för säkerhet i Kubernetes: Autentisering, auktorisering, revision

Den viktigaste Kubernetes-komponenten som är ansvarig för att behandla förfrågningar är api-server. Alla operationer på klustret går igenom det. Du kan läsa mer om dessa interna mekanismer i artikeln "Vad händer i Kubernetes när du kör kubectl run?".

Systemrevision är en intressant funktion i Kubernetes, som är inaktiverad som standard. Det låter dig logga alla samtal till Kubernetes API. Som du kanske gissar utförs alla åtgärder relaterade till övervakning och ändring av klustrets tillstånd via detta API. En bra beskrivning av dess kapacitet finns (som vanligt) i officiell dokumentation K8s. Därefter ska jag försöka presentera ämnet på ett enklare språk.

Så, för att möjliggöra revision, måste vi skicka tre nödvändiga parametrar till behållaren i api-server, som beskrivs mer detaljerat nedan:

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

Utöver dessa tre nödvändiga parametrar finns det många ytterligare inställningar relaterade till revision: från loggrotation till webhook-beskrivningar. Exempel på loggrotationsparametrar:

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

Men vi kommer inte att uppehålla oss mer i detalj - du kan hitta alla detaljer i kube-apiserver dokumentation.

Som redan nämnts ställs alla parametrar in i manifestet med api-serverkonfigurationen (som standard /etc/kubernetes/manifests/kube-apiserver.yaml), i avsnitt command. Låt oss återgå till de tre nödvändiga parametrarna och analysera dem:

  1. audit-policy-file — Sökväg till YAML-filen som beskriver revisionspolicyn. Vi kommer att återkomma till dess innehåll senare, men för nu kommer jag att notera att filen måste vara läsbar av api-serverprocessen. Därför är det nödvändigt att montera den inuti behållaren, för vilken du kan lägga till följande kod till lämpliga avsnitt av konfigurationen:
      volumeMounts:
        - mountPath: /etc/kubernetes/policies
          name: policies
          readOnly: true
      volumes:
      - hostPath:
          path: /etc/kubernetes/policies
          type: DirectoryOrCreate
        name: policies
  2. audit-log-path — sökväg till loggfilen. Sökvägen måste också vara tillgänglig för api-serverprocessen, så vi beskriver dess montering på samma sätt:
      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 — Revisionsloggformat. Standard är json, men det äldre textformatet är också tillgängligt (legacy).

Revisionspolicy

Nu om den nämnda filen som beskriver loggningspolicyn. Det första begreppet revisionspolicy är level, loggningsnivå. De är följande:

  • None - logga inte;
  • Metadata — metadata för loggförfrågan: användare, förfråganstid, målresurs (pod, namnområde, etc.), åtgärdstyp (verb), etc.;
  • Request — Logga metadata och förfrågningsorgan.
  • RequestResponse — logga metadata, förfrågningsorgan och svarsorgan.

De två sista nivåerna (Request и RequestResponse) logga inte förfrågningar som inte fick åtkomst till resurser (åtkomst till så kallade icke-resurser urls).

Alla förfrågningar går också igenom flera etapper:

  • RequestReceived — Det skede då begäran tas emot av processorn och ännu inte har sänts vidare längs kedjan av processorer.
  • ResponseStarted — svarsrubriker skickas, men innan svarstexten skickas. Genereras för långvariga frågor (t.ex. watch);
  • ResponseComplete — Svarsinstansen har skickats, ingen mer information kommer att skickas.
  • Panic — händelser genereras när en onormal situation upptäcks.

För att hoppa över alla steg du kan använda omitStages.

I en policyfil kan vi beskriva flera avsnitt med olika loggningsnivåer. Den första matchningsregeln som finns i policybeskrivningen kommer att tillämpas.

Kubelet-demonen övervakar ändringar i manifestet med api-serverkonfigurationen och, om några upptäcks, startar om behållaren med api-server. Men det finns en viktig detalj: ändringar i policyfilen kommer att ignoreras av den. Efter att ha gjort ändringar i policyfilen måste du starta om api-servern manuellt. Eftersom api-server startas som statisk pod, team kubectl delete kommer inte att få den att starta om. Du måste göra det manuellt docker stop på kube-masters, där revisionspolicyn har ändrats:

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

När du aktiverar revision är det viktigt att komma ihåg det belastningen på kube-apiserver ökar. I synnerhet ökar minnesförbrukningen för lagring av begärankontext. Loggningen börjar först efter att svarshuvudet har skickats. Belastningen beror också på revisionspolicykonfigurationen.

Exempel på policyer

Låt oss titta på strukturen för policyfiler med hjälp av exempel.

Här är en enkel fil policyatt logga allt på nivån Metadata:

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

I policy kan du ange en lista över användare (Users и ServiceAccounts) och användargrupper. Det är till exempel så här vi kommer att ignorera systemanvändare, men logga allt annat på nivån 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

Det är också möjligt att beskriva målen:

  • namnrymder (namespaces);
  • Verb (verb: get, update, delete och andra);
  • Resurser (medel, nämligen: pod, configmaps etc.) och resursgrupper (apiGroups).

Var uppmärksam! Resurser och resursgrupper (API-grupper, d.v.s. apiGroups), såväl som deras versioner installerade i klustret, kan erhållas med hjälp av kommandona:

kubectl api-resources
kubectl api-versions

Följande revisionspolicy tillhandahålls som en demonstration av bästa praxis inom Alibaba Cloud dokumentation:

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

Ett annat bra exempel på revisionspolicy är profil som används i GCE.

För att snabbt svara på revisionshändelser är det möjligt beskriv webhook. Denna fråga tas upp i officiell dokumentation, jag lämnar det utanför ramen för denna artikel.

Resultat av

Artikeln ger en översikt över grundläggande säkerhetsmekanismer i Kubernetes-kluster, som låter dig skapa personliga användarkonton, separera deras rättigheter och registrera deras handlingar. Jag hoppas att det kommer att vara användbart för dem som ställs inför sådana frågor i teorin eller i praktiken. Jag rekommenderar också att du läser listan över annat material om ämnet säkerhet i Kubernetes, som ges i "PS" - kanske bland dem hittar du nödvändig information om de problem som är relevanta för dig.

PS

Läs även på vår blogg:

Källa: will.com

Lägg en kommentar