Definiowanie połączeń do różnych źródeł danych jest nieodłącznym elementem pracy każdego kto zajmuje się systemami analitycznymi. Samo uwierzytelnienie do źródła może przebiegać na wiele różnych sposobów zależnych między innymi od typu źródła, zdefiniowanej polityki bezpieczeństwa itd. Bardzo ważnym aspektem jest to aby wszelkie dane wrażliwe przechowywać w bezpieczny sposób tak aby nie trafiły one w ręce niepowołanych osób. W ramach dzisiejszego artykułu powiemy sobie jak przechowywać tego typu dane w Azure Key Vault, a następnie jak je wykorzystywać w przepływać Azure Data Factory.
Bez zbędnego wstępu przechodzimy do demonstracji. Nasz scenariusz testowy zakłada bardzo prosty przypadek, a mianowicie ładowanie danych w Copy Activity z Data Lake’a do Azure SQL Db. Mamy zatem zdefiniowane dwa połączenia do odpowiednich serwisów:
O tym jak stworzyć każde z tych połączeń nie będę pisał ponieważ pisałem o tym w ramach poprzednich artykułów dlatego pokaże tylko ich końcową definicję. Połączenie do Azure Data Lake wygląda następująco:
Jak widać powyżej do serwisu podłączyłem się używając klucza jako metody uwierzytelniającej (w większości przypadków lepszym pomysłem byłoby użycie Managed Identity ale do celów demonstracyjnych klucz będzie dobrze pasował). Jeśli chodzi o połączenie do Azure SQL Db użyjemy tradycyjnego połączenia użytkownik + hasło czyli SQL Authentication (gdzie po raz kolejny lepszym rozwiązaniem byłoby Managed Identity):
Wszelkie hasła czy klucze zapisane w ten sposób są oczywiście przechowywane bezpiecznie po stronie Data Factory,może to nam to przysporzyć kilku problemów. Przede wszystkim zarządzanie hasłami najlepiej żeby było scentralizowane dzięki czemu wszelkie zmiany haseł itd. mogą być wykonane w jednym, a nie w wielu miejscach. Rozwiązaniem może tutaj być dedykowana usługa w chmurze jaką jest Azure Key Vault (AKV). Usługa ta pozwala na przechowywanie wszelkiego rodzaju kluczy, sekretów czy też certyfikowanych w bezpiecznym, zaszyfrowanym i zabezpieczonym miejscu. O tej usłudze nie będę się rozpisywał i zainteresowanych zachęcam do zapoznania się z dokumentacją. W przedstawianym scenariuszu testowym po stworzeniu AKV dodałem tam następujące sekrety:
Do tych właśnie sekretów możemy odwoływać się na wiele różnych sposobów. Niektóre usługi są bezpośrednio zintegrowane z AKV i Data Factory do nich należy. W wielu przypadkach jedyne co musimy zrobić to nadać dostęp naszemu ADF do Key Vaulta. Dokonamy tego przechodząc w ADF na zakładkę Manage aby dodać połączenie do Key Vaulta:
Mamy dedykowany konektor, który z łatwością wyszukamy po nazwie:
Jego konfiguracja również jest bezproblemowa bo sprowadza się do podania adresu Key Vaulta wybierając go z subskrypcji lub wpisując ręcznie. Adres usługi wygląda następująco: https://nazwaKeyVaulta.vault.azure.net czyli w moim przypadku:
Na powyższym obrazku możecie zobaczyć również dane na temat Managed Identity (nazwa + object ID) naszego Data Factory i to właśnie temu MI będziemy musieli nadać dostęp w AKV. Przejdźmy zatem do tej usługi na zakładkę Access policies gdzie musimy kliknąć Add Access Policy:
Nasz ADF ma mieć dostęp do sekretów dlatego wybieramy Secret Permissions, a tam Get oraz List (chcemy aby ADF był w stanie jedynie wylistować sekrety i je odczytać, w razie potrzeby można dodać większy zakres uprawnień). W dalszej kolejności w sekcji Select Principal możemy wyszukać po nazwie nasze Managed Identity i je wybrać:
Po zdefiniowaniu wszystkich uprawnień nie zapomnijmy o kliknięciu Save:
Mamy zatem ustawione dostępy i zdefiniowane sekrety – teraz musimy podpiąć Key Vaulta pod konkretne Linked Service. Zaczniemy od Data lake’a – jak widać na poniższym zrzucie bezpośrdnio z AKV możemy pobrać Access Key do ADLS – wystarczy podać nazwę odpowiedniego sekretu:
Na powyższym zrzucie możecie zauważyć, że mamy możliwość wskazania wersji sekretu – AKV tworzy wersje wszystkich sekretów, jeśli nie wskażemy konkretnej wersji wzięta zostanie najnowsza. Dalej przechodzimy do bazy danych gdzie możemy podpiąć Key Vaulta w kilku kontekstach:
Możemy zatem pobierać z Key Vaulta cały Connection String lub tylko i wyłącznie hasło. Właśnie na takiej zasadzie działa integracja z AKV w ADF – w zależności od tego jakiego konektora używamy możemy parametryzować całe połączenie lub jego wrażliwy element. Póki co wybieramy parametryzację hasła robiąc to analogicznie jak w poprzednim przypadku.
Wygląda na to, że wszystko jest tak jak być powinno. Po opublikowaniu naszego ADFa, możemy uruchomić testowe Copy Activity i zobaczyć czy wszystko przebiegło prawidłowo:
To oczywiście nie jedyna możliwość integracji! Jak każda usługa w ramach Azure tak również Key Vault posiada swoje API do którego możemy się odwołać aby pobrać konkretne informacje. Powiedzmy, że będziemy chcieli pobrać z AKV nazwę użytkownika, który ma być użyty do połączenia z bazą. Aby połączyć się do API wybieramy Web Activity, które w moim przypadku nazwałem “Get Db user name”. Obie aktywności połączyłem strzałką tak jak jest to widoczne na poniższym zrzucie ekranowym:
W ramach Key Vaulta przechowujemy zazwyczaj różnego rodzaju dane wrażliwe jak chociażby hasła jednak możemy tam również trzymać różnego rodzaju konfiguracje, które być może nie są wrażliwe ale warto je trzymać w jednym miejscu. JEśli pobieramy za pomocą Web Activity dane wrażliwe warto pamiętać aby w ustawieniach zaznaczyć checkbox Secure output dzięki czemu dane które pobierzemy nie będą zapisane jawnym tekstem np. w logach.
Output z tej aktywności wygląda wtedy w następujący sposób:
W przypadku gdy ta opcja nie zostanie zaznaczona wtedy wyjściowy JSON wygląda już w standardowy sposób:
Warto zaznaczyć, że zabezpieczone pole ma typ SecureString niezabezpieczone to po prostu String. Jeśli parametryzujemy poszczególne właściwości Linked Service jak np. użytkownik bazodanowy która w ADF ma typ “String” to nie przekażemy tam bezpośrednio wartości typu Secure String – warto o tym pamiętać aby uniknąć nieporozumień.
Przechodząc dalej zakładka Settings przedstawia się następująco:
Pobieramy dane z AKV metodą GET, żadnych dodatkowych opcji nie potrzebujemy wskazujemy jedynie, że będziemy się uwierzytelniać poprzez Managed Identity (MSI) i wskazujemy Resource na https://vault.azure.net. Może pojawić się pytanie skąd mamy wziąć URL, który będzie użyty w żądaniu? Wystarczy wrócić do AKV i tam we właściwościach konkretnego sekretu znajdziemy URL:
do tego URLa musimy dopisać parametr z wersją API – cały URL wygląda następująco:
https://seequalitykv.vault.azure.net/secrets/dbuser/08324b67fb5549fe9122ef47b2942082?api-version=7.0
Powyższy URL pobiera konkretną wersję sekretu, dlatego jeśli chcemy pobierać zawsze najnowszą to z URL wystarczy usunąć identyfikator konkretnej wersji:
https://seequalitykv.vault.azure.net/secrets/dbuser?api-version=7.0
Mamy zatem ustawione pobranie sekretu poprzez API. Teraz tą pobraną wartość musimy użyć jako część naszego łańcucha połączeniowego – ta operacja przebiega już w typowo ADF’owy sposób. Przechodzimy do Linked Service do Azure SQL Database i tam dodajemy parametr, a następnie odwołujemy się do niego w parametrze User name tak jak zostało to przedstawione poniżej:
Mamy już parametr w Linked Service więc teraz dodajemy parametr nieco wyżej czyli w Data set i wartość tego parametru przekazujemy do Linked Service:
Przechodząc do Copy Activity przekazujemy parametr jaki pobraliśmy w Web Activity używając następującego kodu:
@activity('Get Db user name').output.value
Po uruchomieniu wszystko wygląda tak jak powinno:
To by było na tyle jeśli chodzi o wstępne informacje na temat integracji obu usług w ramach chmury Azure. Jest to stosunkowo proste w konfiguracji, a pozwala nam bezpiecznie podejść do implementacji naszych rozwiązań. Polecam używanie AKV niemal w każdym projekcie gdzie używamy ADF’a jeśli jest to tylko możliwe. Dodatkowo jeśli mamy wbudowaną parametryzację tak jak to przedstawiłem w przypadku Access Key do Data Lake, lub hasła do Azure SQL to używajmy tej wbudowanej metody – połączenie przez REST API zostawmy sobie w rezerwie dla innych przypadków dzięki czemu utrzymamy nasze pipeline’y w nieco bardziej przejrzystej i łatwiejszej do utrzymania formie. Dziękuję za uwagę.
Dodatkowe linki:
- What is Azure Key Vault (link)
- Azure Key Vault REST API (link)
- Azure Key Vault Authentication (link)
- Avoiding Issues: Monitoring Query Pushdowns in Databricks Federated Queries - October 27, 2024
- Microsoft Fabric: Using Workspace Identity for Authentication - September 25, 2024
- Executing SQL queries from Azure DevOps using Service Connection credentials - August 28, 2024
Last comments