Jak połączyć się z Databricks to Azure SQL Server?

Problem:

Wykonanie połączenia między Databricks i bazą danych SQL Servera w chmurze Azure.

Co będzie potrzebne?

  1. Databricks 😉
  2. Azure SQL Server utworzony w Azure Portal
  3. Otwarte połączenia sieciowe - Databricks i SQL Server mają mieć możliwość komunikacji. Jeżeli masz problemy na tym poziomie, to niestety nie będzie przedmiotem tego wpisu.
  4. Service principal - żeby połączyć się z Databricks do SQL Servera w bezpieczny i prosty sposób
  5. Key Vault - do przechowywania sekretów
  6. Biblioteki Python - biblioteka do wykonania połączenia JDBC i do używania modułu Azure Identity

Wszystko gotowe? Zaczynamy!

Service principal

Zakładam, że wiesz jak stworzyć service principala w Azure Active Directory:

https://learn.microsoft.com/en-us/azure/active-directory/develop/app-objects-and-service-principals

Po stworzeniu service pricipala z zakładki szczegóły będziesz potrzebował: Application Id i Tenant id:

Z zakładki Certificates & Secrets będziesz też potrzebował Secret dla tego service principala, będziemy go za chwilę wstawiać do KeyVault'a.

Ważne!

Ten service principal musi mieć dostęp do bazy danych. W tym celu musisz stworzyć w bazie danych użytkownika dla service principala:

CREATE USER [ServicePrincipalName] FROM EXTERNAL PROVIDER

I dodać prawa, na przykład, tylko do odczytu:

ALTER ROLE db_datareader ADD MEMBER [trsalesbi-qa-euw-sp-01];

Albo gdy będziesz chciał dodać trochę więcej 😉

ALTER ROLE db_datawriter ADD MEMBER [trsalesbi-qa-euw-sp-01];
ALTER ROLE db_ddladmin ADD MEMBER [trsalesbi-qa-euw-sp-01];

Key Vault

Dobrą praktyką jest, żeby secrety w Databricks przechowywać w Key Vault.

Jak zrbić połączenie pomiędzy Azure Key Vault i Databricks opisane jest tutaj:
https://learn.microsoft.com/en-us/azure/databricks/security/secrets/secret-scopes

Co najważniejsze z tej dokumentacji to stworzenie połączenia między Azure KeyVault i Databricks.

https://#secrets/createScope

Jeżeli nie wiesz, czy masz już zdefiniowane połączenie między Azure Key Vault i Databricks możesz to sprawdzić używając Databricks CLI:

databricks secrets list-scopes

Możesz to też sprawdzić używając rest api

https://learn.microsoft.com/en-us/azure/databricks/dev-tools/api/latest/secrets#--list-secret-scopes

Endpoit powinien jest taki:

2.0/secrets/scopes/list

Po połączeniu Key Vaulta i Databricksa dodajesz tam service principal application id oraz secert:

Biblioteki Python

W konfiguracji clustra w zakładce Libraries dodaj biblioteki:

Potrzebujesz dwie biblioteki z pypi pobierz:
azure-identity

Natomiast z Maven'a będziesz potrzebował:
com.microsoft.azure:spark-mssql-connector_2.12_3.0:1.0.0-alpha
azure-identity

Za chwilę będziesz używał ich w notebooku.

Notebook

Zmęczony konfiguracją? Czas na trochę kodowania:

Zacznijmy od importu bibliotek:

import json
import requests
from azure.identity import ClientSecretCredential

W poniższym kodzie wstaw swój tenant id.

Następnie zmieniasz nazwę Databricks secret scope i podajesz klucze jakie definiowałęś w KeyVault.

tenant_id = 'your-tenant-id-from-azuread'
#key-vault-dbxsecrets - this is databricks secret scope, that points to Azure Active Directory Key Vault
client_id = dbutils.secrets.get(scope = 'key-vault-dbxsecrets', key = 'your-sp-appid')
client_secret = dbutils.secrets.get(scope = 'key-vault-dbxsecrets', key = 'your-sp-secret')

Po pobraniu sekretów pora jeszcze raz udać się do Azure portalu i tym razem skopiować nazwę serwera i bazy danych, mi najłatwiej było to pobrać wziąć z Database connection strings:

server_name = 'your-azure-sql-server-name'
db_name = 'your-azure-database-name'
db_scope = 'https://database.windows.net/.default'
azure_sql_url = f'jdbc:sqlserver://{server_name}.database.windows.net'
database = f'{db_name}'

Wreszcie pora na pobranie tokena

auth = ClientSecretCredential(authority = 'https://login.microsoftonline.com/',
                                                        tenant_id = tenant_id,
                                                        client_id = client_id,
                                                        client_secret = client_secret)
db_access_token = auth.get_token(db_scope)
db_access_token = db_access_token.token

Jeżeli wszystko poszło dobrze, to możesz teraz pobrać dane z tabeli:

spark.read.format('jdbc').option('url', azure_sql_url).option('dbtable', table_name).option('database', database).option('accessToken', db_access_token).load()

Cały notebook znajdziesz oczywiście na Githubie.

Niestety to nie jest krótki proces, jeżeli robisz to "manualnie". Jeżeli robisz to często zapewne da się to zautomatyzować przy użyciu CLI.

Daj znać z czym miałeś największy problem, i co zajęło Ci najwięcej czasu. Będzie mi też miło, jeżeli dasz mi znać, że udało Ci się połączyć 🙂