Problem:
Masz bazę danych Synapse dostępną w usłudze Azure. Posiadasz uprawnienia, żeby połączyć się do tej bazy przy użyciu service principala. To połączenie musisz wykonać w Pythonie. W jaki sposób połączyć się posiadając dane service principala do usługi Synapse?
Rozwiązanie:
Użyjemy .env do przechowywania zmienny środowiskowych. Użyjemy azure.identity żeby połączyć się z usługą i wygenerować token dostępowy. Następnie posiadając token utworzymy połączenie pyodbc.
Zawiłe? Teraz trochę bardziej szczegółowo.
Zdefiniowanie zmiennych środowiskowych
Co potrzebujemy przechowywać w zmiennych środowiskowych?
Identyfikator tenanta, service princiapal id oraz sekret. Nazwę bazy danych i serwera.
Oczywiście service principal musi mieć możliwość odczytywania danych z Synapse i dodawanie mu uprawnień jest poza zakresem tego artykułu.
Mógłbyś też tą konfigurację przechowywać w Key Vault i pewnie tak byś zrobił w środowisku produkcyjny. Tutaj używamy zmiennych środowiskowych dla uproszczenia.
Generowanie tokena
Zdefiniujmy jeszcze kontekst, dla którego będzie generowany token:
db_scope = 'https://database.windows.net/.default'
Użyjemy ClientSecretCredentials do wygenerowania tokena:
from azure.identity import ClientSecretCredential
auth = ClientSecretCredential(authority='https://login.microsoftonline.com/',
tenant_id=SynapseUtil.tenant_id,
client_id=SynapseUtil.client_id,
client_secret=SynapseUtil.client_secret)
access_token = auth.get_token(SynapseUtil.db_scope)
token = access_token.token
Ten kod wygeneruje token dostępowy do Synapsa.
Tworzenie połączenia do Synapse
Szczegóły połączenia wyglądają u mnie w ten sposób. Nie potrzebny jest ani użytkownik ani hasło.
connection_string = f"Driver={{ODBC Driver 18 for SQL Server}};Server={default_server};Database={default_database};Encrypt=yes;Connection Timeout=30"
Ta część kodu jest opisane na stronach Microsoftu. Może dlatego nie wygląda tak zrozumiale 😉
token_bytes = token.encode("UTF-16-LE")
token_struct = struct.pack(f'<I{len(token_bytes)}s', len(token_bytes), token_bytes)
SQL_COPT_SS_ACCESS_TOKEN = 1256 # This connection option is defined by microsoft in msodbcsql.h
Connection = pyodbc.connect(connection_string, attrs_before={SQL_COPT_SS_ACCESS_TOKEN: token_struct})
W powyższej linii podstawiany jest przekształcony token i otwierane połączenie do bazy. Teraz już wolna droga do zadawania zapytań 🙂
Jak zwykle cały kod znajdziesz na GitHub.
https://github.com/rgogloza/nextlevelbi/blob/master/python/synapse_util.py