Wątek przeniesiony 2022-08-30 21:12 z Inżynieria oprogramowania przez Riddle.

Jak zarządzać sekretami pomiędzy środowiskami?

0

Miałem ostatnio w pracy następującą "sytuację".
Dostaliśmy prostego i małego ficzera do zrobienia:
Umożliwić zalogowanemu użytkownikowi pobranie statycznych plików (jakieś tam pdf'y). Pomysł na wykonanie był prosty - wrzucamy dokumenty do blob storage, użytkownik klika link, uderza do usługi w tej samej chmurze, usługa po otrzymaniu żądania generuje jednorazowy token autoryzujący żądanie, dokleja go do URL'a zwracanego jako location 302.
Nic niezwykłego, ale pech chciał, że było to pierwsze użycie blob storage w takim układzie i usługa przekierowująca żądanie musiała mieć odpowiednie credentials, żeby móc pobierać tokeny. Usługa napisana w Springu, pobiera sobie konfigurację, w tym ten sekretny kod na starcie.

Napisane i zaczyna się wdrażanie, infrastruktura opisana kodem (tutaj arm template), kod zapakowany w kontenery - jedzie pull request, kompliacja automatyczny deploy na dev, jakoś poszło. Lecimy ze środowiskami testowymi - trzeba dodać ten sekret, ale to 5 minut roboty, poszło. Na środowiskach testowych poleżało sobie chwilę, o problemie wszyscy zapomnieli, nadszedł moment wrzucenia na produkcję, jak łatwo można się domyślić - zaczynają dzwonić telefony (tak, usługa, która wykonywała przekierowanie była jednocześnie API gatewayem...). Dojście co się stało zajęło chwilę, dojście jaki konkretnie wpis trzeba dodać chwilę dłużej, w końcu dodanie wpisu i usługa się podniosła.

Jasne, miejsce zaimplementowania usługi było niefortunne, ktoś napisał kod, który wywalał się na niezabezpieczonym null pointerze, ktoś inny go puścił przy review itd.
Zastanawiam się jednak, czy macie jakiś pomysł na upewnienei sie, że takie dane znajdą się na srodowisku docelowym, bo:

  • nie moga być w kodzie aplikacji
  • nie mogą być w kodzie infrastruktury
  • nie mogą być w kontenerach
    Czyli trzeba użyć kartki "pamiętaj o dodaniu klucza x do key vaulta y"? Czy da się to jakoś zautomatyzować?
0

Nie rozumiem. Nie pisze w springu, ale pisząc w Go, Pythonie czy Rust jak nie pobrało danych z configu to leciał panic i serwis nie wstawał. Więc nie było szans by czegoś nie doczytało i by o tym nie wiedzieć. Ponadto są lintery by sprawdzać takie błędy jak np. null pointer, polecam. Ewentualnie napisać jakieś testy, które by to wykryły.

0

A kto stworzył ten blob storage i zarządza jego cyklem życia?

Napisałeś, że takie dane nie mogą być w kodzie infrastruktury. Co masz tu na myśli? Nie możesz w szablonach IaC które tworzą ten blob storage wrzucać klucza do KeyVaulta?

0

A jakby appka sama przy starcie odpytywała jakiś secret provider microservice? tylko jak to uwierzytelnić

0

Nie do końca rozumiem, co to znaczy "nie mogą być w kontenerach". Jeśli oznacza to "nie mogą być w repozytorium" to OK, natomiast prędzej czy później musisz zawsze gdzieś się jednak uwierzytelnić.

Ogólnie rozumiem sytuację w ten sposób:

  1. Istnieje sobie repozytorium z sekretami.
  2. Chciałbyś, żeby przy deployu sobie samo tworzyło credentiale, które następnie będą pobierane przez aplikację.

Po pierwsze - czy repozytorium z pkt. 1 pozwala na takie cuda? Jaki jest interfejs? Jeśli jakiś ogarnialny to przecież zawsze można wyklepać prosty skrypt w Pythonie i dorzucić jego wykonanie na start, żeby takie credentiale tworzyło. Oczywiście tutaj się zaczyna problem secretów do secretów - ale gdzieś to trzymać przecież musisz.

0

Ok, troche mniej beletrystyki:

  • Jest sobie KeyVault, czyli bazy klucz-wartość https://azure.microsoft.com/pl-pl/services/key-vault/#product-overview
  • Podczas kompilacji kod jest pakowany do kontenera, kontener jest umieszczany w repozytorium kontenerów.
  • W repozytoriach trzymana jest definicja kodu, infrastruktury, gotowe kontenery.
  • To oznacza, że niczego co jest tajne, ani specyficzne dla środowiska nie można trzymać w tych miejscach.
  • Po buildzie tworzony jest artefakt (docker container), który trafia kolejno na różne środowiska i ma dostęp do osobnego repozytorium kontenerów
  • deployment pobiera sobie kontenery i umieszcza je w klastrze kubernetesa na konkretnym środowisku
  • kontener startuje, loguje się do KV z pierwszego punktu i próbuje zawartość dla konkretnego klucza
  • Nie znajduje tej wartości, zmienna przyjmuje wartość null
  • w jakiejś tam linijce leci NPE, usługi nie dało się wystartować.

Równie dobrze mógłby to być jakiś parametr konfiguracyjny, który musi być ustawiony, a jak nie jest ustawiony, to aplikacja nie działa.

Wartość, ponieważ jest sekretem nie może być przechowywana w repozytorium kodu, infrastruktury, kontenerów.
Problem wciskam "deploy" na środowisko dev wszystko działa, bo ktoś pisząc kod dodał sobie odpowiednią wartość.
Wciskam ten sam guzik ale na środowisku prod i nie działa, bo nikt tej wartości nie dodał, a deploy jedynie odpala kontener.

0

w jakiejś tam linijce leci NPE, usługi nie dało się wystartować.

  • błąd logowany jest np. do Grafany, którą ktoś obserwuje (bo jak to tak robić deploy i nawet nie spojrzeć w logi czy aplikacja wstała?), ktoś dorzuca brakujące sekrety i restartuje aplikację 🙃
0

@Patryk27: No jest, tylko jednak deploy na produkcję, trzymając się zasady "jak się wykopyrtnie to naprawimy development" jest taki średni :) Tak, mamy monitoring. Zastanawiam się nad tym jak uniknąć tego typu sytuacji.

2

A dlaczego aplikacja czy mikroserwis nie uwierzytelnia się przez Azure AD (Azure Managed Identity) tak jak rekomenduje Microsoft? Odpada wtedy cały proces zarządzania i utrzymywania kluczy. Obecnie dobrą praktyką w cloudzie jest stosowanie managed identities do uwierzytelniania i autoryzacji, zamiast kluczy. Tyczy się do zarówno Azure jak i AWS.

We recommend using Azure Storage integration with Azure Active Directory (Azure AD), Microsoft's cloud-based identity and access management service. Azure AD integration is available for Azure blobs and queues, and provides OAuth2 token-based access to Azure Storage (just like Azure Key Vault). Azure AD allows you to authenticate your client application by using an application or user identity, instead of storage account credentials. You can use an Azure AD managed identity when you run on Azure. Managed identities remove the need for client authentication and storing credentials in or with your application.

Do niedawna była opcja pozwalająca Azure KeyVault na generowanie i rotację kluczy dla Storage Account automatycznie, ale jest już przez Microsoft oznaczona jako legacy i nie wspierana na rzecz opcji z AAD (https://docs.microsoft.com/en-us/azure/key-vault/secrets/overview-storage-keys).

Wracając do twojego przypadku. Wasz problem polega na tym, że ktoś zapomina dodać secret do produkcyjnego key vaulta, więc musicie sobie to zautomatyzować, co wiąże się z tym, ze te secrety muszą jednak być gdzieś przechowywane. Dlatego zalecaną praktyką jest to co napisałem w pierwszym akapicie.

1

@markone_dev: Masz rację, aktualnie przepinamy się z kolejnymi usługami na Managed Identity, pewnie trochę zajmie zanim to wszystko ruszy. Zastanawiałem się nad środkami zaradczymi zanim osiągniemy nirvanę.

1

No jak zawsze przy takich ręcznych operacjach, najsłabszym ogniwem jest i będzie człowiek dlatego kiedyś się pisało SOP (Standard Operating Procedure) i jak ktoś robił wdrożenie to jechał punkt po punkcie, lol :D. Teraz automatyzacja popsuła wszystko.

EDIT: w sumie to wciąż się pisze SOP w branżach podlegających silnym regulacjom

1 użytkowników online, w tym zalogowanych: 0, gości: 1