Skip to main content
  • »
  • KUBERNETES »
  • Instalacja HashiCorp Vault na NSIS Magnum

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:

../_images/unsealing_the_pod1.png

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:

../_images/vault_created1.png

Możesz teraz rozpocząć korzystanie z Vault.

../_images/start_using_vault1.png

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ą:

../_images/vim_editor_change1.png

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.