Dominik Miklaszewski
by Dominik Miklaszewski

Categories

Tags

..noszę, bezpieczne kredki, bardzo lubią mnie.. Mógłby sobie zanucić programista, gdyby chciał.. ;).

Tak jak obiecałem, będziemy kontynuować temat wpisu z 28 czerwca “Kto schował kredki?”. Tu skupimy się na bezpiecznym serwowaniu aplikacji niezbędnych “kredek” przy pomocy Vaulta i Nomada, zaczynając od konfiguracji samego silnika w Vaulcie. Całość opisu tej integracji (ten i poprzedni wpis) powstał po zabawie w wirtualnym labie Hashicorpa.

Co mamy?

Na razie mamy zapewnione bezpieczeństwo samej bazy MongoDB, która przy deploymencie, przy pomocy integracji Nomada z Vaultem, dostaje swoje inicjalne dane uwierzytelniające (dalej w tekście będę pisał - sekrety, może nie do końca poprawnie po polsku, ale moim zdaniem - krócej i zgrabniej).

Vault: Uruchamiamy silnik bazodanowy

Silnik bazodanowy w Hashicorp Vault to takie “proxy” pomiędzy klientem a bazą danych. Vault integruje się z kilkoma powszechnie używanymi bazami danych poprzez pluginy (patrz: obrazki poniżej). Klient uwierzytelnia się w Vaulcie, dostaje odpowiednią rolę, która jest autoryzowana do kilku czynności związanych z operacjami na użytkowniku w wybranej bazie danych. Czynności te wykonuje za klienta Vault, a wyniki (sekrety) serwuje klientowi. Wszystko odbywa się oczywiście w ramach bezpiecznie zestawionej komunikacji (TLS) oraz uwierzytelnianiu z wykorzystaniem krótko-żyjących tokenów Vaulta.

Vault DB EngineVault Mongo

Swoją drogą, zwróćmy uwagę na szeroką paletę integracji Vaulta (warto na to poświęcić więcej czasu). :)

konfiguracja

Kiedy mamy już uruchomiony silnik bazodanowy, musimy go odpowiednio skonfigurować:

A sam panel po skonfigurowaniu integracji wygląda tak: Panel MongoDB po zalogowaniu z autoryzacją do uzycia tej integracji

Ta konfiguracja posłuży nam do tego, aby prawidłowo obsługiwać generowanie kont aplikacyjnych dla danej bazy w MongoDB poprzez zdefiniowaną rolę. Tzn: zdefiniowana_rola_w_Vaulcie_1 -> zdefiniowany użytkownik w bazie (z uprawnieniami do zarz. użytkownikami) -> zdefiniowany_prefix_nazwy_konta -> hasło.

Wszystko na swoim miejscu

Czego potrzebuje nasza aplikacja do prawidłowego funkcjonowania z bazą MongoDB?

  • CONNECTION_STRING
  • JWTSECRET
  • PORT
  • SESSION_ID

I to wszystko mamy zapisane key-value store o nazwie “my-fs-app”:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
 
$ vault kv get kv/my-fs-app
== Secret Path ==
kv/data/my-fs-app

======= Metadata =======
Key                Value
---                -----
created_time       2022-06-24T06:29:25.540471649Z
custom_metadata    <nil>
deletion_time      n/a
destroyed          false
version            2

========== Data ==========
Key                  Value
---                  -----
CONNECTION_STRING    mongodb://appuser:*******@srv1u100.nukelab.home:27017/ComplexApp?retryWrites=true&w=majority
JWTSECRET            ************
PORT                 ************
SESSION_ID           ************
 

Jak zdążyliście pewnie zauważyć, w CONNECTION_STRING nazwa konta i hasło to właśnie te kredki, które wygenerował nam Vault przy pomocy skonfigurowanego plugina. Trochę ręcznie. Wiem. Nie udało mi się jeszcze dojść jak poprawnie wyciągnąć te kredki template-m Nomada ze ścieżki database/... A po drugie musiałbym potem robić w pliku nomadowym jakieś złożenie tych wartości w jeden connection string, trzymając nazwę serwera osobno, parametry URLa osobno i mongo:// osobno.

Sprawdźmy czy wszystko jest na swoim miejscu:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
 
$ vault list database/mongodb/static-roles

Keys
----
my-app-user

$ vault read database/mongodb/static-roles/my-app-user
Key                    Value
---                    -----
credential_type        password
db_name                my-fs-app
last_vault_rotation    2022-06-10T13:57:51.082470413+02:00
rotation_period        8760h
rotation_statements    []
username               appuser

$ vault read database/mongodb/static-creds/my-app-user
Key                    Value
---                    -----
last_vault_rotation    2022-06-10T13:57:51.082470413+02:00
password               ******************
rotation_period        8760h
ttl                    7554h9m26s
username               *******
 

Ale.. zaraz, zaraz. My to nie Nomad, skąd Vault ma wiedzieć, że klient Nomada jest upoważniony do sięgnięcia po te kredki? Póki co, Vault “rżnie głupa”, że nic nie wie o żadnych kredkach dla aplikacji - Missing: vault.read(kv/my-fs-app). Zgodnie z podejściem ustanowionym w poprzednim odcinku, klient Nomada odczyta wszystkie polityki poza przeznaczoną tylko dla serwera Nomada. Wracamy więc, do tematu ustawienia odpowiedniej polityki, bo rolę i krótkoterminowy token mamy już ustawione w poprzednim ćwiczeniu. Więc załadowanie takiej o to polityki jak poniżej, w zupełności wystarczy (dla kv v1 i v2):

1
2
3
4
5
6
7
8
9
10
11
12
 
# Access apps secrets

path "kv/data/my-fs-app" {
  capabilities = ["read"]
}

path "secret/kv/data/my-fs-app" {
  capabilities = ["read"]
}

 

(Dodajemy do Vaulta przez UI-a, albo vault policy write..)

Nomad: konfiguracja deploymentu aplikacji

Konfiguracja specs file aplikacji, konstrukcyjnie niczym się praktycznie nie różni od tego, którego wyprodukowałem dla mongo. Podmienione zostały tylko parametry i zlikwidowana stanza dotycząca miejsca na dysku dla danych. Sam plik jest dostępny tutaj

Start aplikacji

nomad plan app.nomad i nomad job run -check-index 0 app.nomad

Deployment w Nomadzie

..i sprawdźmy czy aplikacja odpowiada..

Aplikacja odpowiada

..i ciągnie dane z Mongo (porównajmy oba obrazki)

Wpis w Mongo

Co dalej?

Dobrze byłoby ten proces teraz skonsolidować - jeden job dla Mongo i aplikacji. A następnie zautomatyzować, wykorzystując rozwijany intensywnie w tym roku Nomad Packs. Ten Nomad Pack to coś jak Helm dla Kubernetesa. Własne repozytorium paczek, zarządzanie wersjami itd.