ABC for sikkerhet i Kubernetes: Autentisering, autorisasjon, revisjon

ABC for sikkerhet i Kubernetes: Autentisering, autorisasjon, revisjon

Før eller senere, i driften av ethvert system, oppstår spørsmålet om sikkerhet: sikring av autentisering, separasjon av rettigheter, revisjon og andre oppgaver. Allerede opprettet for Kubernetes mange løsninger, som lar deg oppnå samsvar med standarder selv i svært krevende miljøer... Det samme materialet er viet til de grunnleggende aspektene ved sikkerhet implementert innenfor de innebygde mekanismene til K8s. Først av alt vil det være nyttig for de som begynner å bli kjent med Kubernetes – som et utgangspunkt for å studere sikkerhetsrelaterte problemstillinger.

Autentisering

Det er to typer brukere i Kubernetes:

  • Tjenestekontoer — kontoer administrert av Kubernetes API;
  • brukere — «normale» brukere administrert av eksterne, uavhengige tjenester.

Hovedforskjellen mellom disse typene er at for tjenestekontoer er det spesielle objekter i Kubernetes API (de kalles det - ServiceAccounts), som er knyttet til et navneområde og et sett med autorisasjonsdata lagret i klyngen i objekter av typen Secrets. Slike brukere (tjenestekontoer) er primært ment å administrere tilgangsrettigheter til Kubernetes API for prosesser som kjører i Kubernetes-klyngen.

Vanlige brukere har ikke oppføringer i Kubernetes API: de må administreres av eksterne mekanismer. De er beregnet på personer eller prosesser som lever utenfor klyngen.

Hver API-forespørsel er knyttet til enten en tjenestekonto, en bruker eller anses som anonym.

Brukerautentiseringsdata inkluderer:

  • Brukernavn — brukernavn (skiller mellom store og små bokstaver!);
  • UID - en maskinlesbar brukeridentifikasjonsstreng som er "mer konsistent og unik enn brukernavnet";
  • Grupper — liste over grupper som brukeren tilhører;
  • ekstra – tilleggsfelt som kan brukes av autorisasjonsmekanismen.

Kubernetes kan bruke et stort antall autentiseringsmekanismer: X509-sertifikater, Bearer-tokens, autentiseringsproxy, HTTP Basic Auth. Ved å bruke disse mekanismene kan du implementere et stort antall autorisasjonsskjemaer: fra en statisk fil med passord til OpenID OAuth2.

Dessuten er det mulig å bruke flere autorisasjonsordninger samtidig. Som standard bruker klyngen:

  • tjenestekontotokens - for tjenestekontoer;
  • X509 - for brukere.

Spørsmålet om å administrere ServiceAccounts ligger utenfor rammen av denne artikkelen, men for de som ønsker å sette seg mer inn i denne problemstillingen, anbefaler jeg å starte med offisielle dokumentasjonssider. Vi skal se nærmere på spørsmålet om hvordan X509-sertifikater fungerer.

Sertifikater for brukere (X.509)

Den klassiske måten å jobbe med sertifikater på innebærer:

  • nøkkelgenerering:
    mkdir -p ~/mynewuser/.certs/
    openssl genrsa -out ~/.certs/mynewuser.key 2048
  • generere en sertifikatforespørsel:
    openssl req -new -key ~/.certs/mynewuser.key -out ~/.certs/mynewuser.csr -subj "/CN=mynewuser/O=company"
  • behandle en sertifikatforespørsel ved å bruke Kubernetes-klynge-CA-nøklene, skaffe et brukersertifikat (for å få et sertifikat må du bruke en konto som har tilgang til Kubernetes-klynge-CA-nøkkelen, som som standard er plassert 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
  • lage en konfigurasjonsfil:
    • klyngebeskrivelse (spesifiser adressen og plasseringen til CA-sertifikatfilen for en spesifikk klyngeinstallasjon):
      kubectl config set-cluster kubernetes --certificate-authority=/etc/kubernetes/pki/ca.crt --server=https://192.168.100.200:6443
    • eller hvordan noanbefalt alternativ - du trenger ikke spesifisere rotsertifikatet (da vil ikke kubectl sjekke riktigheten til klyngens api-server):
      kubectl config set-cluster kubernetes  --insecure-skip-tls-verify=true --server=https://192.168.100.200:6443
    • legge til en bruker i konfigurasjonsfilen:
      kubectl config set-credentials mynewuser --client-certificate=.certs/mynewuser.crt  --client-key=.certs/mynewuser.key
    • legge til kontekst:
      kubectl config set-context mynewuser-context --cluster=kubernetes --namespace=target-namespace --user=mynewuser
    • standard konteksttilordning:
      kubectl config use-context mynewuser-context

Etter manipulasjonene ovenfor, i filen .kube/config en konfigurasjon som dette vil bli opprettet:

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

For å gjøre det enklere å overføre konfigurasjonen mellom kontoer og servere, er det nyttig å redigere verdiene til følgende nøkler:

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

For å gjøre dette kan du kode filene som er spesifisert i dem ved hjelp av base64 og registrere dem i konfigurasjonen, og legge til suffikset til navnet på nøklene -data, dvs. har mottatt certificate-authority-data etc.

Sertifikater med kubeadm

Med utgivelsen Kubernetes 1.15 arbeid med sertifikater har blitt mye enklere takket være alfaversjonen av støtten i kubeadm-verktøyet. For eksempel kan det se slik ut å generere en konfigurasjonsfil med brukernøkler:

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

NB: Påkrevd annonsere adresse kan finnes i api-server-konfigurasjonen, som som standard er plassert i /etc/kubernetes/manifests/kube-apiserver.yaml.

Den resulterende konfigurasjonen vil bli sendt ut til stdout. Den må lagres i ~/.kube/config brukerkonto eller til en fil spesifisert i en miljøvariabel KUBECONFIG.

Grave dypere

For de som ønsker å forstå problemstillingene som er beskrevet mer grundig:

Autorisasjon

Den autoriserte standardkontoen har ikke rettigheter til å operere på klyngen. For å gi tillatelser implementerer Kubernetes en autorisasjonsmekanisme.

Før versjon 1.6 brukte Kubernetes en autorisasjonstype kalt ABAC (Attributtbasert tilgangskontroll). Detaljer om det finner du i offisiell dokumentasjon. Denne tilnærmingen anses for øyeblikket som gammel, men du kan fortsatt bruke den sammen med andre autentiseringstyper.

Den nåværende (og mer fleksible) måten å dele tilgangsrettigheter til en klynge på kalles RBAC (Rollebasert tilgangskontroll). Den har blitt erklært stabil siden versjonen Kubernetes 1.8. RBAC implementerer en rettighetsmodell der alt som ikke er eksplisitt tillatt er forbudt.
For å aktivere RBAC, må du starte Kubernetes api-server med parameteren --authorization-mode=RBAC. Parametrene er satt i manifestet med api-serverkonfigurasjonen, som som standard er plassert langs banen /etc/kubernetes/manifests/kube-apiserver.yaml, i seksjon command. Imidlertid er RBAC allerede aktivert som standard, så mest sannsynlig bør du ikke bekymre deg for det: du kan bekrefte dette med verdien authorization-mode (i det allerede nevnte kube-apiserver.yaml). Forresten, blant betydningene kan det være andre typer autorisasjoner (node, webhook, always allow), men vi vil la deres vurdering ligge utenfor rammen av materialet.

Vi har forresten allerede publisert artikkel med en ganske detaljert beskrivelse av prinsippene og funksjonene ved å jobbe med RBAC, så videre vil jeg begrense meg til en kort liste over det grunnleggende og eksempler.

Følgende API-enheter brukes til å kontrollere tilgang i Kubernetes via RBAC:

  • Role и ClusterRole – roller som tjener til å beskrive tilgangsrettigheter:
  • Role lar deg beskrive rettigheter innenfor et navneområde;
  • ClusterRole - innenfor klyngen, inkludert til klyngespesifikke objekter som noder, ikke-ressursnettadresser (dvs. ikke relatert til Kubernetes-ressurser - for eksempel, /version, /logs, /api*);
  • RoleBinding и ClusterRoleBinding - brukes til innbinding Role и ClusterRole til en bruker, brukergruppe eller tjenestekonto.

Rolle- og RoleBinding-enhetene er begrenset av navneområde, dvs. må være innenfor samme navneområde. En RoleBinding kan imidlertid referere til en ClusterRole, som lar deg opprette et sett med generiske tillatelser og kontrollere tilgang ved å bruke dem.

Roller beskriver rettigheter ved å bruke sett med regler som inneholder:

  • API-grupper - se offisiell dokumentasjon av apiGroups og utdata kubectl api-resources;
  • ressurser (ressurser: pod, namespace, deployment og så videre.);
  • Verb (verb: set, update etc.).
  • ressursnavn (resourceNames) - for tilfellet når du trenger å gi tilgang til en spesifikk ressurs, og ikke til alle ressurser av denne typen.

En mer detaljert analyse av autorisasjon i Kubernetes finner du på siden offisiell dokumentasjon. I stedet (eller rettere sagt, i tillegg til dette) vil jeg gi eksempler som illustrerer arbeidet hennes.

Eksempler på RBAC-enheter

enkel Role, som lar deg få en liste og status for pods og overvåke dem i navneområ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"]

Eksempel ClusterRole, som lar deg få en liste og status over pods og overvåke dem i hele klyngen:

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

Eksempel RoleBinding, som tillater brukeren mynewuser "les" pods i navneområdet 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

Eventrevisjon

Skjematisk kan Kubernetes-arkitekturen representeres som følger:

ABC for sikkerhet i Kubernetes: Autentisering, autorisasjon, revisjon

Den viktigste Kubernetes-komponenten som er ansvarlig for å behandle forespørsler er api-server. Alle operasjoner på klyngen går gjennom den. Du kan lese mer om disse interne mekanismene i artikkelen "Hva skjer i Kubernetes når du kjører kubectl run?'.

Systemrevisjon er en interessant funksjon i Kubernetes, som er deaktivert som standard. Den lar deg logge alle anrop til Kubernetes API. Som du kanskje gjetter, utføres alle handlinger relatert til overvåking og endring av klyngens tilstand gjennom denne API. En god beskrivelse av dens evner kan (som vanlig) finnes i offisiell dokumentasjon K8s. Deretter vil jeg prøve å presentere temaet på et enklere språk.

således for å muliggjøre revisjon, må vi sende tre nødvendige parametere til beholderen i api-server, som er beskrevet mer detaljert nedenfor:

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

I tillegg til disse tre nødvendige parameterne er det mange tilleggsinnstillinger knyttet til revisjon: fra loggrotasjon til webhook-beskrivelser. Eksempel på loggrotasjonsparametere:

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

Men vi vil ikke dvele mer på dem - du kan finne alle detaljene i kube-apiserver dokumentasjon.

Som allerede nevnt, er alle parametere satt i manifestet med api-serverkonfigurasjonen (som standard /etc/kubernetes/manifests/kube-apiserver.yaml), i seksjon command. La oss gå tilbake til de tre nødvendige parameterne og analysere dem:

  1. audit-policy-file — bane til YAML-filen som beskriver revisjonspolicyen. Vi kommer tilbake til innholdet senere, men foreløpig vil jeg merke at filen må være lesbar av api-server-prosessen. Derfor er det nødvendig å montere den inne i beholderen, som du kan legge til følgende kode til de aktuelle delene av konfigurasjonen:
      volumeMounts:
        - mountPath: /etc/kubernetes/policies
          name: policies
          readOnly: true
      volumes:
      - hostPath:
          path: /etc/kubernetes/policies
          type: DirectoryOrCreate
        name: policies
  2. audit-log-path — bane til loggfilen. Banen må også være tilgjengelig for api-serverprosessen, så vi beskriver monteringen på samme måte:
      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 — revisjonsloggformat. Standard er json, men det eldre tekstformatet er også tilgjengelig (legacy).

Revisjonspolicy

Nå om den nevnte filen som beskriver loggingspolicyen. Det første konseptet med revisjonspolitikk er level, loggingsnivå. De er som følger:

  • None - ikke logg;
  • Metadata — loggforespørselsmetadata: bruker, forespørselstidspunkt, målressurs (pod, navneområde, etc.), handlingstype (verb), etc.;
  • Request — logg metadata og forespørselstekst;
  • RequestResponse — logg metadata, forespørselstekst og svartekst.

De to siste nivåene (Request и RequestResponse) ikke logg forespørsler som ikke fikk tilgang til ressurser (tilganger til såkalte ikke-ressurser urls).

Også alle forespørsler går gjennom flere stadier:

  • RequestReceived – stadiet når forespørselen mottas av prosessoren og ennå ikke er overført videre langs prosessorkjeden;
  • ResponseStarted — svarhoder sendes, men før svarteksten sendes. Generert for langvarige søk (f.eks. watch);
  • ResponseComplete — svarinstansen er sendt, ingen mer informasjon vil bli sendt;
  • Panic — hendelser genereres når en unormal situasjon oppdages.

For å hoppe over trinn du kan bruke omitStages.

I en policyfil kan vi beskrive flere seksjoner med ulike loggingsnivåer. Den første samsvarsregelen i retningslinjebeskrivelsen vil bli brukt.

Kubelet-demonen overvåker endringer i manifestet med api-server-konfigurasjonen og, hvis noen oppdages, starter beholderen på nytt med api-server. Men det er en viktig detalj: endringer i policyfilen vil bli ignorert av den. Etter å ha gjort endringer i policyfilen, må du starte api-serveren på nytt manuelt. Siden api-server er startet som statisk pod, team kubectl delete vil ikke føre til at den starter på nytt. Du må gjøre det manuelt docker stop på kube-masters, der revisjonspolicyen er endret:

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

Når du aktiverer revisjon, er det viktig å huske det belastningen på kube-apiserver øker. Spesielt øker minneforbruket for lagring av forespørselskontekst. Loggingen begynner først etter at svarhodet er sendt. Belastningen avhenger også av konfigurasjonen av revisjonspolicyen.

Eksempler på retningslinjer

La oss se på strukturen til policyfiler ved å bruke eksempler.

Her er en enkel fil policyå logge alt på nivået Metadata:

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

I policy kan du spesifisere en liste over brukere (Users и ServiceAccounts) og brukergrupper. For eksempel er det slik vi vil ignorere systembrukere, men logge alt annet på nivået 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 er også mulig å beskrive målene:

  • navneområder (namespaces);
  • Verb (verb: get, update, delete og andre);
  • ressurser (ressurser, Som følger: pod, configmaps etc.) og ressursgrupper (apiGroups).

Vær oppmerksom! Ressurser og ressursgrupper (API-grupper, dvs. apiGroups), samt deres versjoner installert i klyngen, kan fås ved å bruke kommandoene:

kubectl api-resources
kubectl api-versions

Følgende revisjonspolicy er gitt som en demonstrasjon av beste praksis i Alibaba Cloud-dokumentasjon:

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

Et annet godt eksempel på revisjonspolitikk er profil brukt i GCE.

For raskt å svare på revisjonshendelser er det mulig beskriv webhook. Dette problemet er dekket i offisiell dokumentasjon, jeg lar det ligge utenfor rammen av denne artikkelen.

Resultater av

Artikkelen gir en oversikt over grunnleggende sikkerhetsmekanismer i Kubernetes-klynger, som lar deg opprette personlige brukerkontoer, skille rettighetene deres og registrere handlingene deres. Jeg håper det vil være nyttig for de som står overfor slike problemstillinger i teorien eller i praksis. Jeg anbefaler også at du leser listen over annet materiale om emnet sikkerhet i Kubernetes, som er gitt i "PS" - kanskje vil du blant dem finne de nødvendige detaljene om problemene som er relevante for deg.

PS

Les også på bloggen vår:

Kilde: www.habr.com

Legg til en kommentar