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.
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:
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):
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:
separat artikel om att arbeta med certifikat i den officiella Kubernetes-dokumentationen;
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:
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:
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:
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:
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:
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:
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:
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:
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:
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:
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
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.