Instalacja HashiCorp Vault na NSIS Magnum
W Kubernetes, Secret jest obiektem zawierającym hasła, tokeny, klucze lub inne małe fragmenty danych. Korzystanie z Secrets zapewnia, że prawdopodobieństwo ujawnienia poufnych danych podczas tworzenia, uruchamiania i edytowania podów jest znacznie mniejsze. Głównym problemem jest to, że Secrets są przechowywane w postaci niezaszyfrowanej w etcd, więc każdy, kto ma dostęp do Secrets, może je odczytać.
API, a także każdy, kto
może utworzyć Pod lub Wdrożenie w przestrzeni nazw
może również pobierać lub modyfikować Secret.
Można zastosować szereg strategii w celu poprawy bezpieczeństwa klastra lub zainstalować specjalistyczne rozwiązanie, takie jak HashiCorp Vault. Oferuje ono
bezpieczne przechowywanie wszelkiego rodzaju sekretów - haseł, certyfikatów TLS, poświadczeń bazy danych, kluczy szyfrowania API i innych,
szyfrowanie wszystkich danych,
dynamiczna obsługa poświadczeń,
szczegółowe zasady dostępu dla użytkowników, aplikacji i usług,
rejestrowanie i audyt wykorzystania danych,
odwołanie lub usunięcie dowolnego klucza lub klucza tajnego,
ustawienie automatycznej rotacji sekretów - zarówno dla administratorów, jak i użytkowników.
W tym artykule zainstalujemy HashiCorp Vault w klastrze Magnum Kubernetes w chmurze NSIS.
Co będziemy omawiać
Zainstaluj samodzielnie podpisane certyfikaty TLS za pomocą CFSSL
Generowanie certyfikatów umożliwiających szyfrowanie ruchu za pomocą Vault
Instalacja zaplecza pamięci masowej Consul dla wysokiej dostępności
Instalacja skarbca
Uszczelnianie i rozszczelnianie skarbca
Rozszczelnienie skarbca
Uruchom interfejs użytkownika Vault
Zwraca livenessProbe do wartości produkcyjnej
Rozwiązywanie problemów
Wymagania wstępne
Nr 1 Konto
Potrzebne jest konto hostingowe NSIS z dostępem do interfejsu Horizon: https://horizon.cloudferro.com.
Nr 2 Znajomość kubectl
Powinieneś mieć uruchomiony odpowiedni klaster Kubernetes, z kubectl wskazującym na niego Jak uzyskać dostęp do klastra Kubernetes po wdrożeniu przy użyciu Kubectl na NSIS OpenStack Magnum?.
Nr 3 Znajomość obsługi wykresów Helm
W tym artykule przedstawiono wykresy Helm na platformie Kubernetes:
Wdrażanie Helm Charts na klastrach Magnum Kubernetes w chmurze NSIS Cloud
Krok 1 Zainstaluj CFSSL
Aby zapewnić, że komunikacja Vault z klastrem jest szyfrowana, musimy dostarczyć certyfikaty TLS.
Użyjemy samopodpisanych certyfikatów TLS wydanych przez prywatny urząd certyfikacji. Do ich wygenerowania użyjemy narzędzi CFSSL: cfssl i cfssljson.
cfssl jest narzędziem CLI. cfssljson pobiera dane wyjściowe JSON z cfssl i zapisuje certyfikaty, klucze i CSR (żądania podpisania certyfikatu).
Musimy pobrać pliki binarne obu narzędzi: cfssl i cfssljson ze strony https://github.com/cloudflare/cfssl i uczynić je wykonywalnymi:
curl -L https://github.com/cloudflare/cfssl/releases/download/v1.6.3/cfssl_1.6.3_linux_amd64 -o cfssl
curl -L https://github.com/cloudflare/cfssl/releases/download/v1.6.1/cfssljson_1.6.1_linux_amd64 -o cfssljson
chmod +x cfssl
chmod +x cfssljson
Następnie musimy dodać je do naszej ścieżki:
sudo mv cfssl cfssljson /usr/local/bin
Krok 2 Generowanie certyfikatów TLS
Zanim zaczniemy, stwórzmy dedykowaną przestrzeń nazw, w której będą znajdować się wszystkie zasoby Kubernetes związane z Vault:
kubectl create namespace vault
Będziemy musieli wydać dwa zestawy certyfikatów. Pierwszy zestaw będzie certyfikatem głównym dla urzędu certyfikacji. Drugi będzie odwoływał się do certyfikatu CA i utworzy rzeczywisty certyfikat Vault.
Aby utworzyć żądanie klucza dla CA, oprzemy je na pliku JSON ca-csr.json ca-csr.json ca-csr.json ca-csr.json. Utwórz ten plik w swoim ulubionym edytorze i jeśli chcesz, zastąp szczegóły certyfikatu do własnego przypadku użycia:
ca-csr.json ca-csr.json ca-csr.json ca-csr.json
{
"hosts": [
"cluster.local"
],
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "Poland",
"L": "Warsaw",
"O": "MyOrganization"
}
]
}
Następnie należy wydać polecenie wygenerowania samopodpisanego certyfikatu głównego urzędu certyfikacji.
cfssl gencert -initca ca-csr.json | cfssljson -bare ca
Powinieneś zobaczyć dane wyjściowe podobne do poniższych:
2023/01/02 15:27:36 [INFO] generating a new CA key and certificate from CSR
2023/01/02 15:27:36 [INFO] generate received request
2023/01/02 15:27:36 [INFO] received CSR
2023/01/02 15:27:36 [INFO] generating key: rsa-2048
2023/01/02 15:27:36 [INFO] encoded CSR
2023/01/02 15:27:36 [INFO] signed certificate with serial number 472447709029717049436439292623827313295747809061
W rezultacie generowane są trzy podmioty:
klucz prywatny,
CSR i
certyfikat z podpisem własnym (ca.pem, ca.csr, ca-key.pem).
Następnym krokiem jest utworzenie certyfikatów Vault, które odwołują się do prywatnego urzędu certyfikacji. W tym celu należy najpierw utworzyć plik konfiguracyjny ca-config.json, aby zastąpić domyślną konfigurację. Jest to szczególnie przydatne w przypadku zmiany ważności certyfikatu:
ca-config.json
{
"signing": {
"default": {
"expiry": "17520h"
},
"profiles": {
"default": {
"usages": ["signing", "key encipherment", "server auth", "client auth"],
"expiry": "17520h"
}
}
}
}
Następnie wygeneruj klucze Vault, odwołując się do tego pliku i kluczy CA:
cfssl gencert \
-ca ./ca.pem \
-ca-key ./ca-key.pem \
-config ca-config.json \
-profile default \
-hostname="vault,vault.vault.svc.cluster.local,localhost,127.0.0.1" \
ca-csr.json | cfssljson -bare vault
Wynik będzie następujący:
2023/01/02 16:19:52 [INFO] generate received request
2023/01/02 16:19:52 [INFO] received CSR
2023/01/02 16:19:52 [INFO] generating key: rsa-2048
2023/01/02 16:19:52 [INFO] encoded CSR
2023/01/02 16:19:52 [INFO] signed certificate with serial number 709743788174272015258726707100830785425213226283
Ponadto w folderze roboczym zostaną utworzone kolejne trzy pliki: vault.pem, vault.csr, vault-key.pem.
Ostatnim krokiem jest zapisanie wygenerowanych kluczy jako sekretów Kubernetes TLS w naszym klastrze:
kubectl -n vault create secret tls tls-ca --cert ./ca.pem --key ./ca-key.pem -n vault
kubectl -n vault create secret tls tls-server --cert ./vault.pem --key ./vault-key.pem -n vault
Nazwy tych sekretów odzwierciedlają domyślne nazwy mapy Vault Helm.
Krok 3 Zainstaluj wykres Consul Helm
Backend Consul zapewni wysoką dostępność naszej instalacji Vault. Consul będzie działał w przestrzeni nazw, którą już utworzyliśmy, vault.
Oto plik konfiguracyjny zastępujący wykres Consul Helm: consul-values.yaml.
consul-values.yaml
global:
datacenter: vault-kubernetes-guide
client:
enabled: true
server:
replicas: 1
bootstrapExpect: 1
disruptionBudget:
maxUnavailable: 0
Teraz zainstaluj repozytorium hashicorp wykresów Helm i sprawdź, czy znajduje się w nim vault:
helm repo add hashicorp https://helm.releases.hashicorp.com
helm search repo hashicorp/vault
W ostatnim kroku zainstaluj Consul chart:
helm install consul hashicorp/consul -f consul-values.yaml -n vault
To jest raport o powodzeniu instalacji:
NAME: consul
LAST DEPLOYED: Thu Feb 9 18:52:58 2023
NAMESPACE: vault
STATUS: deployed
REVISION: 1
NOTES:
Thank you for installing HashiCorp Consul!
Your release is named consul.
Wkrótce kilka kapsuł Consul zostanie wdrożonych w przestrzeni nazw vault. Uruchom następujące polecenie, aby to zweryfikować:
kubectl get pods -n vault
Poczekaj, aż wszystkie kapsuły będą Running, a następnie przejdź do następnego kroku.
Krok 4 Zainstaluj wykres Vault Helm
Jesteśmy teraz gotowi do zainstalowania Vault.
Najpierw udostępnijmy plik vault-values.yaml, który zastąpi plik konfiguracyjny dla wykresu Vault Helm. Te nadpisania zapewniają włączenie szyfrowania, wysokiej dostępności, ustawienie większego czasu dla readinessProbe i wystawienie interfejsu użytkownika jako typu usługi LoadBalancer:
vault-values.yaml
# Vault Helm Chart Value Overrides
global:
enabled: true
tlsDisable: false
injector:
enabled: true
image:
repository: "hashicorp/vault-k8s"
tag: "0.14.1"
resources:
requests:
memory: 500Mi
cpu: 500m
limits:
memory: 1000Mi
cpu: 1000m
server:
# These Resource Limits are in line with node requirements in the
# Vault Reference Architecture for a Small Cluster
image:
repository: "hashicorp/vault"
tag: "1.9.2"
# For HA configuration and because we need to manually init the vault,
# we need to define custom readiness/liveness Probe settings
readinessProbe:
enabled: true
path: "/v1/sys/health?standbyok=true&sealedcode=204&uninitcode=204"
livenessProbe:
enabled: true
path: "/v1/sys/health?standbyok=true"
initialDelaySeconds: 360
extraEnvironmentVars:
VAULT_CACERT: /vault/userconfig/tls-ca/tls.crt
# extraVolumes is a list of extra volumes to mount. These will be exposed
# to Vault in the path `/vault/userconfig/<name>/`.
# These reflect the Kubernetes vault and ca secrets created
extraVolumes:
- type: secret
name: tls-server
- type: secret
name: tls-ca
standalone:
enabled: false
# Run Vault in "HA" mode.
ha:
enabled: true
replicas: 3
config: |
ui = true
listener "tcp" {
tls_disable = 0
address = "0.0.0.0:8200"
tls_cert_file = "/vault/userconfig/tls-server/tls.crt"
tls_key_file = "/vault/userconfig/tls-server/tls.key"
tls_min_version = "tls12"
}
storage "consul" {
path = "vault"
address = "consul-consul-server:8500"
}
# Vault UI
ui:
enabled: true
serviceType: "LoadBalancer"
serviceNodePort: null
externalPort: 8200
Następnie uruchom instalację:
helm install vault hashicorp/vault -n vault -f vault-values.yaml
W rezultacie tworzonych jest kilka podów:
kubectl get pods -n vault
NAME READY STATUS RESTARTS AGE
consul-consul-client-655fq 1/1 Running 0 104s
consul-consul-client-dkngt 1/1 Running 0 104s
consul-consul-client-nnbnl 1/1 Running 0 104s
consul-consul-connect-injector-8447d8d97b-8hkj8 1/1 Running 0 104s
consul-consul-server-0 1/1 Running 0 104s
consul-consul-webhook-cert-manager-7c4ccbdd4c-d89bw 1/1 Running 0 104s
vault-0 1/1 Running 0 23s
vault-1 1/1 Running 0 23s
vault-2 1/1 Running 0 23s
vault-agent-injector-6c7cfc768-kv968 1/1 Running 0 23s
Uszczelnianie i rozszczelnianie skarbca
Zaraz po instalacji serwer Vault uruchamia się w stanie zamkniętym. Wie, gdzie i jak uzyskać dostęp do fizycznej pamięci masowej, ale z założenia nie ma klucza do jej odszyfrowania. Jedyne operacje, które można wykonać, gdy Vault jest zapieczętowany, to
rozszczelnienie skarbca i
sprawdzić stan uszczelnienia.
Proces odwrotny, zwany rozszczelnianiem, polega na utworzeniu klucza głównego tekstu jawnego niezbędnego do odczytania klucza deszyfrującego.
W prawdziwym życiu istniałby administrator, który mógłby najpierw wygenerować tak zwane key shares lub unseal keys, czyli zestaw dokładnie pięciu ciągów tekstowych. Następnie rozdzieliłby te klucze na dwie lub więcej osób, tak aby sekrety były trudne do zdobycia dla potencjalnego atakującego. Aby wykonać odpieczętowanie, co najmniej trzy z tych pięciu ciągów musiałyby zostać przedstawione skarbcowi, w dowolnej kolejności.
W tym artykule jesteś jednak zarówno administratorem, jak i użytkownikiem i możesz skonfigurować wszystko po swojemu. Najpierw będziesz
wygenerować klucze i mieć je dostępne w zasięgu wzroku, a następnie
wprowadzić trzy z tych pięciu ciągów z powrotem do systemu.
Będziesz miał ograniczoną, ale wystarczającą ilość czasu na wprowadzenie kluczy; wartość livenessProbe w pliku vault-values.yaml wynosi 360 sekund, co da ci wystarczająco dużo czasu na wprowadzenie kluczy.
Na końcu artykułu pokażemy, jak interaktywnie ustawić go na 60 sekund, aby klaster mógł częściej sprawdzać kondycję podów.
Krok 5 Rozszczelnienie skarbca
Trzy węzły w klastrze Kubernetes reprezentują Vault i noszą nazwy vault-0, vault-1, vault-2. Aby Vault był funkcjonalny, należy odblokować wszystkie trzy węzły.
Aby rozpocząć, wprowadź kontener w vault-0:
kubectl -n vault exec -it vault-0 -- sh
Następnie z wnętrza kapsuły zdobądź klucze:
vault operator init
Wynik będzie następujący, otrzymasz 5 kluczy odpieczętowujących i token root. Zapisz te klucze w Notatniku, aby mieć do nich wygodny dostęp później:
Unseal Key 1: jcJj2ukVBNG5K01PX3UkskPotc+tGAvalG5CqBveS6LN
Unseal Key 2: OBzqfTYL9lmmvuewk85kPxpgc0D/CDVXrY9cdBElA3hJ
Unseal Key 3: M6QysiGixui4SlqB7Jdgv0jaHn8m45V91iabrxRvNo6v
Unseal Key 4: H7T5BHR2isbBSHfu2q4aKG0hvvA13uXlT9799whxmuL+
Unseal Key 5: rtbXv3TqdUeN3luelJa8OOI/CKlILANXxFVkyE/SKv4c
Initial Root Token: s.Pt7xVk5rShSuIJqRPqBFWY5H
Następnie, z poziomu kapsuły vault-0, odpieczętuj ją wpisując:
vault operator unseal
Zostaniesz poproszony o podanie klucza, a następnie wklej klucz 1 z notatnika. Powtórz ten proces 3 razy w kapsule vault-0, za każdym razem podając inny klucz z tych pięciu, które właśnie wygenerowałeś.
Tak wygląda cały proces:
W trzeciej próbie wartości Initialized zmieniają się na true, a sealed na false:
Key Value
--- -----
Seal Type shamir
Initialized true
Sealed false
... ...
Kapsuła jest rozszczelniona.
Teraz powtórz ten sam proces dla vault-1 i vault-2 pods.
Aby przestać korzystać z konsoli w vault-0, naciśnij Ctrl-D na klawiaturze. Następnie wprowadź vault-1 za pomocą polecenia
kubectl -n vault exec -it vault-1 -- sh
i odblokować go, wprowadzając co najmniej trzy klucze. Następnie wykonaj podobną procedurę dla vault-2. Dopiero po odblokowaniu wszystkich trzech kapsuł skarbiec stanie się aktywny.
Krok 6 Uruchomienie interfejsu użytkownika Vault
W naszej konfiguracji Vault UI jest wystawiony na porcie 8200 dedykowanego LoadBalancera, który został utworzony.
Aby sprawdzić LoadBalancer, uruchom:
kubectl -n vault get svc
Sprawdź zewnętrzny adres IP LoadBalancera (może to potrwać kilka minut, jeśli zewnętrzny adres IP jest dostępny):
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
...
vault-ui LoadBalancer 10.254.49.9 64.225.129.145 8200:32091/TCP 143m
Wpisz zewnętrzny adres IP do przeglądarki, określając HTTPS i port 8200. Witryna może poprosić o certyfikat i może narzekać, że istnieje ryzyko kontynuowania. Powinieneś zaakceptować wszystkie zagrożenia i zobaczyć, że interfejs użytkownika Vault jest dostępny, podobnie jak na poniższym obrazku. Aby się zalogować, należy podać uzyskany wcześniej token:
Możesz teraz rozpocząć korzystanie z Vault.
Zwraca livenessProbe do wartości produkcyjnej
livenessProbe w Kubernetes to czas, w którym system sprawdza kondycję węzłów. W normalnych okolicznościach nie byłoby to twoim zmartwieniem, ale jeśli nie odpieczętujesz skarbca w tym czasie, odpieczętowanie nie zadziała. W normalnych okolicznościach wartość ta wynosiłaby 60 sekund, więc w przypadku jakichkolwiek zakłóceń system zareagowałby w ciągu jednej minuty zamiast sześciu. Ale bardzo trudno jest skopiować i wprowadzić trzy ciągi poniżej jednej minuty, tak jak miałoby to miejsce, gdyby wartość 60 była obecna w pliku vault-values.yaml. Prawie nieuchronnie zobaczyłbyś błąd Kubernetes 137, co oznacza, że nie wykonałeś wymaganych operacji na czas.
W pliku vault-values.yaml następująca sekcja definiuje 360 sekund jako czas aktywacji livenessProbe:
livenessProbe:
enabled: true
path: "/v1/sys/health?standbyok=true"
initialDelaySeconds: 360
Aby przywrócić wartość livenessProbe do 60, wykonaj polecenie:
kubectl edit statefulset vault -n vault
Możesz teraz uzyskać dostęp do odpowiednika pliku vault-values.yaml wewnątrz klastra Kubernetes. Polecenie automatycznie przejdzie do edytora podobnego do Vima, więc naciśnij klawisz O na klawiaturze, aby móc zmienić wartość za jego pomocą:
Po zakończeniu zapisz i opuść Vima ze standardową składnią :w i :q.
Rozwiązywanie problemów
Sprawdź wydarzenia, które mogą wskazać, co należy poprawić:
kubectl get events -n vault
Jeśli wystąpią błędy i chcesz usunąć instalację Vault, aby powtórzyć proces od nowa, pamiętaj, że MutatingWebhookConfiguration może pozostać w domyślnej przestrzeni nazw. Usuń go przed ponowną próbą:
kubectl get MutatingWebhookConfiguration
kubectl delete MutatingWebhookConfiguration consul-consul-connect-injector
kubectl delete MutatingWebhookConfiguration vault-agent-injector-cfg
Co robić dalej
Teraz serwer Vault jest częścią klastra i można z niego korzystać z adresu IP, na którym został zainstalowany.
Innym sposobem na poprawę bezpieczeństwa Kubernetes jest zabezpieczenie aplikacji za pomocą protokołu HTTPS przy użyciu ingress:
Wdrażanie usług HTTPS na platformie Magnum Kubernetes w NSIS Cloud.