Konfiguracja Vault Hashicorp: Polityki, scieżki, silniki i inne – zarządzamy dostępem

Silniki

Silniki (secret engines) są komponentami, które odpowiadają za dużą część możliwośći Vault. Umożliwają one przechowywanie sekretów (Key/Value, Cubbyhole), generowanie jednorazowych kluczy (Nomad, AWS, PKI), szyfrowanie (SSH, Transit) i inne. Tymczasowo skupię się na jednym silniku – Kv, który umożliwia przechowywanie par Klucz/Wartość. W celu odblokowania silnika musimy wydać komendę:

$ vault secrets enable -path=newEngine kv

W rezultacie powinniśmy otrzymać:

$ vault secrets enable -path=newEngine kv
Success! Enabled the kv secrets engine at: newEngine/

Za flagą path podajemy ścieżkę do silnika, z którą wiąże się kilka rzeczy:

  • Każdy silnik mocowany jest w niezależnym miejscu.
  • Żaden silnik nie może być zamontowany w ścieżce innego silnika. Poprawne ścieżki dla dwóch silników to na przykład <punkt1;punkt2>, <punkt/p1;punkt/p2>, a złe to <punkt0;punkt0/p1>
  • Jest to abstrakcja bardzo podobno do linuksowego punktu mocowania i może udostępniać prawdziwe dyski, bazy danych, REST API i inne

Polityki

W ogólnym przypadku dostęp do zasobów możemy przypisywać bezpośrednio konkretnym użytkownikom i grupom. Niestety takie podejście szybko powoduje problemy. Z tego powodu powstały polityki, które opisują jak modyfikują domyślne uprawnienia. Modelowy przykład zarządzania politykami posiada następujące cechy:

  • Domyślnie polityki, grupy i użytkownicy nie mają żadnych uprawnień
  • Każda polityka nadpisuje pewną część uprawnień
  • Polityka dla dziecka nadpisuje politykę rodzica
  • Polityka nie powinna odbierać uprawnień
  • Nie przypisujemy uprawnień bezpośrednio do użytkowników i grup
  • Nie przypisujemy polityk bezpośrednio do użytkowników
  • Uprawnienia grupy to suma uprawnień nadanych przez przypisane jej polityki
  • Uprawnienia użytkownika to suma uprawnień grup do których jest przypisany

Te cechy ułatwiają zarządzanie i monitorowanie dostępu do zasobów.

Do podstawowych uprawnień jakie można nadać należą:

  • create – tworzenie nowego sekretu
  • read – odczyt istniejącego sekretu
  • update- aktualizacja istniejącego sekretu
  • delete – kasowanie sekretu
  • list – wypisanie istniejących sekretów

Polityki definiujemy w formacie HCl, który jest kompatybilny z jsonem:

path "secret/*" {
  capabilities = ["create"]
}

path "secret/foo" {
  capabilities = ["read"]
}

Taki plik z polityką możemy zapisać komendą:

vault policy write <nazwaPolityki> "<ścieżkaDoPlikuPolityki>"

Przykładowa konfiguracja

Teraz zobaczymy zrobić prototyp realnej implementacji. Najpierw dodamy silniki, które zorganizują nam strukturę:

  • develop – sekrety związane z rozwojem aplikacji. Każdy może robić co chce
  • prod – sekrety związane ze środowiskami klienckimi. Odczyt i aktualizacja dla devopsów, edycja dla “administracji”
  • licenses – Klucze aplikacji, itp. Odczyt dla wszystkich, edycja dla “administracji”

Wykonamy to następującymi komendami:

vault secrets enable -path="develop" kv
vault secrets enable -path="prod" kv
vault secrets enable -path="licenses" kv
vault secrets enable -path="users" kv

Teraz tworzymy pliki polityk:

path "develop/*" {
  capabilities = ["read", "list", "update", "create"]
}
path "prod/*" {
  capabilities = ["read", "list", "update"]
}
path "prod/*" {
  capabilities = ["read", "list", "update", "create", "delete"]
}
path "licenses /*" {
  capabilities = ["read", "list", "update", "create", "delete"]
}
path "licenses/*" {
  capabilities = ["read", "list"]
}

I same polityki:

vault policy write develop develop
vault policy write prodLite prodLite
vault policy write prodAdmin prodAdmin
vault policy write licensesFull  licensesFull 
vault policy write licensesAccess licensesAccess

Następnie powinniśmy stworzyć grupy, które będą implementowały te polityki. Ze względu na to, że do autoryzacji używamy LDAP użyjemy następujących komend:

vault write auth/ldap/groups/developers policies="develop,licensesAccess "
vault write auth/ldap/groups/devops policies="develop,prodLite"
vault write auth/ldap/groups/managers policies="develop,prodAdmin,licensesAdmin"

Teraz czas na crème de la crème – dodajemy użytkownika:

vault write auth/ldap/users/<username> groups=developers

Na koniec tworzymy zasoby:

vault write prod/db/login  value=prodDbLogin
vault write prod/db/password  value=prodDbPass
vault write develop/login  value=developDbLogin
vault write develop/password  value=developDbPass
vault write licenses/WinRar/key value="0033e049-8fea-461b-88fa-3a2d180b9c99"
vault write licenses/VisualStudio/key value="4f169e69-a6d1-46be-9f39-4c7960ce3d2c"

Uwierzytelniamy się w LDAP za pomocą komendy:

$ curl -s POST  http://127.0.0.1:8200/v1/auth/ldap/login/<naszLogin>  -d '{
"password":"<naszeHaslo>"
}' | json_pp

{
   "data" : {},
   "warnings" : [
      "no LDAP groups found in groupDN ''; only policies from locally-defined groups available"
   ],
   "lease_id" : "",
   "renewable" : false,
   "auth" : {
      "client_token" : "de8051b8-fdc1-4b5b-665b-8bb003ec07df",
      "metadata" : {
         "username" : "<naszLogin>"
      },
      "lease_duration" : 2764800,
      "entity_id" : "f7ccf9a5-a66f-4922-2137-ba95ba774125",
      "accessor" : "8278050c-1a62-f7ad-93e0-10c9e43707e5",
      "renewable" : true,
      "policies" : [
         "default",
         "developers"
      ]
   },
   "wrap_info" : null,
   "request_id" : "cb48256d-fd30-4416-0b16-7f8f6a8d5e3c",
   "lease_duration" : 0
}

Teraz używając client-token możemy odpytać się o pojedynczy zasób:

curl GET http://127.0.0.1:8200/v1/licenses/WinRar/key -sH 'X-Vault-Token: de8051b8-fdc1-4b5b-665b-8bb003ec07df' | json_pp
{
   "auth" : null,
   "wrap_info" : null,
   "data" : {
      "value" : "0033e049-8fea-461b-88fa-3a2d180b9c99"
   },
   "lease_duration" : 2764800,
   "lease_id" : "",
   "warnings" : null,
   "renewable" : false,
   "request_id" : "3dcec093-d6af-4386-861b-eece33e42d24"
}

Wylistować dostępne zasoby:

$ curl --request LIST http://127.0.0.1:8200/v1/licenses/ -sH 'X-Vault-Token: de8051b8-fdc1-4b5b-665b-8bb003ec07df'| json_pp
{
   "data" : {
      "keys" : [
         "VisualStudio/",
         "WinRar/"
      ]
   },
   "auth" : null,
   "lease_duration" : 0,
   "renewable" : false,
   "wrap_info" : null,
   "lease_id" : "",
   "request_id" : "5165f7cf-ff59-cd51-3712-44d42b16ba99",
   "warnings" : null
}

Ale tylko jeśli mamy uprawnienia:

$ curl --request LIST http://127.0.0.1:8200/v1/prod/ -sH 'X-Vault-Token: de8051b8-fdc1-4b5b-665b-8bb003ec07df' | json_pp
{
   "errors" : [
      "permission denied"
   ]
}

Możemy też tworzyć nowe zasoby:

$ curl --request POST --data '{"key": "super", "foo": "bar"}' -s -H 'X-Vault-Token: de8051b8-fdc1-4b5b-665b-8bb003ec07df' http://127.0.0.1:8200/v1/develop/brandNewSecret
$ curl --request LIST http://127.0.0.1:8200/v1/develop/ -sH 'X-Vault-Token: de8051b8-fdc1-4b5b-665b-8bb003ec07df'  | json_pp
{
   "lease_id" : "",
   "request_id" : "d820e2dd-9173-4211-74c0-61177198cc4c",
   "data" : {
      "keys" : [
         "brandNewSecret",
         "login",
         "password"
      ]
   },
   "lease_duration" : 0,
   "warnings" : null,
   "renewable" : false,
   "wrap_info" : null,
   "auth" : null
}

Oraz je usuwać:

$ curl --request DELETE http://127.0.0.1:8200/v1/develop/brandNewSecret -sH 'X-Vault-Token: de8051b8-fdc1-4b5b-665b-8bb003ec07df' 
$ curl --request LIST http://127.0.0.1:8200/v1/develop/ -sH 'X-Vault-Token: de8051b8-fdc1-4b5b-665b-8bb003ec07df'| json_pp
{
   "wrap_info" : null,
   "auth" : null,
   "data" : {
      "keys" : [
         "login",
         "password"
      ]
   },
   "request_id" : "99c0ce13-1b47-c182-6976-19aa69dea065",
   "warnings" : null,
   "lease_id" : "",
   "lease_duration" : 0,
   "renewable" : false
}

Podsumowanie

Nasz Vault jest praktycznie gotowy. Jesteśmy w stanie uwierzytelniać użytkowników i nadawać im dostępy. Jedyne co nam zostało to przygotowanie skryptu produkcyjnego i hardening.

Leave a Reply

Your email address will not be published. Required fields are marked *