Udostępnij za pośrednictwem


Uwierzytelnianie aplikacji języka Python w usługach platformy Azure podczas programowania lokalnego przy użyciu jednostek usługi

Podczas tworzenia aplikacji w chmurze deweloperzy często muszą uruchamiać i testować swoje aplikacje lokalnie. Nawet podczas programowania lokalnego aplikacja musi uwierzytelniać się w dowolnych usługach platformy Azure, z którymi współdziała. W tym artykule wyjaśniono, jak skonfigurować dedykowane tożsamości jednostki usługi specjalnie do użycia podczas programowania lokalnego.

Diagram przedstawiający sposób, w jaki aplikacja uruchomiona na lokalnym komputerze deweloperskim uzyskuje nazwę główną usługi aplikacji z pliku .env, a następnie używa tej tożsamości do łączenia się z zasobami platformy Azure.

Dedykowane jednostki usługi aplikacji dla lokalnego programowania obsługują zasadę najniższych uprawnień, ograniczając dostęp tylko do zasobów platformy Azure wymaganych przez aplikację podczas programowania. Użycie dedykowanej jednostki usługi aplikacji zmniejsza ryzyko niezamierzonego dostępu do innych zasobów i pomaga zapobiegać błędom związanym z uprawnieniami podczas przechodzenia do środowiska produkcyjnego, gdzie szersze uprawnienia mogą prowadzić do problemów.

Podczas rejestrowania aplikacji na potrzeby programowania lokalnego na platformie Azure zaleca się:

  • Twórz oddzielne rejestracje aplikacji dla każdego dewelopera: zapewnia to każdemu deweloperowi własną główną usługę, unikając konieczności udostępniania poświadczeń i umożliwiając bardziej szczegółową kontrolę dostępu.
  • Utwórz oddzielne rejestracje aplikacji dla każdej aplikacji: gwarantuje to, że każda aplikacja ma tylko wymagane uprawnienia, zmniejszając potencjalny obszar ataków.

Aby włączyć uwierzytelnianie podczas programowania lokalnego, ustaw zmienne środowiskowe przy użyciu poświadczeń jednostki usługi aplikacji. Zestaw Azure SDK dla języka Python wykrywa te zmienne i używa ich do uwierzytelniania żądań w usługach platformy Azure.

1 — Rejestrowanie aplikacji na platformie Azure

Obiekty główne usługi aplikacji są tworzone podczas rejestracji aplikacji w Azure. Tę rejestrację można wykonać przy użyciu witryny Azure Portal lub interfejsu wiersza polecenia platformy Azure. Proces rejestracji tworzy rejestrację aplikacji w usłudze Microsoft Entra ID (dawniej Azure Active Directory) i generuje obiekt jednostki usługi dla aplikacji. Obiekt główny usługi służy do uwierzytelniania aplikacji w usługach platformy Azure. Proces rejestracji aplikacji generuje również klucz tajny klienta (hasło) dla aplikacji. Ten tajny kod służy do uwierzytelniania aplikacji w usługach Azure. Tajemnica klienta nigdy nie jest przechowywana w kontroli wersji, ale raczej w pliku .env w katalogu aplikacji. Plik .env jest odczytywany przez aplikację w czasie wykonywania w celu ustawienia zmiennych środowiskowych używanych przez zestaw Azure SDK dla języka Python do uwierzytelniania aplikacji. W poniższych krokach pokazano, jak zarejestrować aplikację na platformie Azure i utworzyć jednostkę usługi dla aplikacji. Kroki są wyświetlane zarówno dla interfejsu wiersza polecenia platformy Azure, jak i witryny Azure Portal.

Polecenia interfejsu wiersza polecenia platformy Azure można uruchamiać w usłudze Azure Cloud Shell lub na stacji roboczej z zainstalowanym Azure CLI.

Najpierw użyj polecenia az ad sp create-for-rbac , aby utworzyć nową jednostkę usługi dla aplikacji. Polecenie tworzy również rejestrację aplikacji dla aplikacji w tym samym czasie.

SERVICE_PRINCIPAL_NAME=<service-principal-name>
az ad sp create-for-rbac --name $SERVICE_PRINCIPAL_NAME

Dane wyjściowe tego polecenia są podobne do poniższych. Zanotuj te wartości lub pozostaw to okno otwarte, ponieważ te wartości będą potrzebne w następnych krokach i nie będą mogły ponownie wyświetlić wartości hasła (klucza tajnego klienta). Możesz jednak później dodać nowe hasło bez unieważniania tożsamości usługi lub istniejących haseł, jeśli zajdzie potrzeba.

{
  "appId": "00001111-aaaa-2222-bbbb-3333cccc4444",
  "displayName": "<service-principal-name>",
  "password": "Ee5Ff~6Gg7.-Hh8Ii9Jj0Kk1Ll2Mm3_Nn4Oo5Pp6",
  "tenant": "aaaabbbb-0000-cccc-1111-dddd2222eeee"
}

Następnie należy pobrać appID wartość i zapisać ją w zmiennej. Ta wartość służy do ustawiania zmiennych środowiskowych w lokalnym środowisku projektowym, aby zestaw Azure SDK dla języka Python mógł uwierzytelniać się na platformie Azure przy użyciu jednostki usługi.

APP_ID=$(az ad sp list \
  --all \
  --query "[?displayName=='$SERVICE_PRINCIPAL_NAME'].appId | [0]" \
  --output tsv)

2 — Utwórz grupę zabezpieczeń Microsoft Entra na potrzeby rozwoju lokalnego

Ponieważ zazwyczaj pracuje wielu deweloperów nad aplikacją, zaleca się utworzenie grupy zabezpieczeń Microsoft Entra w celu hermetyzacji ról (uprawnień), które aplikacja potrzebuje w rozwoju lokalnym, zamiast przypisywania ról do poszczególnych obiektów zasadniczych usług. Zapewnia to następujące korzyści:

  • Każdy deweloper ma przypisane te same role, ponieważ role są przypisywane na poziomie grupy.
  • Jeśli dla aplikacji jest potrzebna nowa rola, należy ją dodać tylko do grupy Microsoft Entra dla aplikacji.
  • Jeśli nowy deweloper dołączy do zespołu, zostanie utworzona nowa jednostka usługi aplikacji dla dewelopera i dodana do grupy, zapewniając deweloperowi odpowiednie uprawnienia do pracy nad aplikacją.

Polecenie az ad group create służy do tworzenia grup zabezpieczeń w identyfikatorze Entra firmy Microsoft. Parametry --display-name i --main-nickname są wymagane. Nazwa nadana grupie powinna być oparta na nazwie aplikacji. Warto również uwzględnić frazę taką jak "local-dev" w nazwie grupy, aby wskazać cel grupy.

GROUP_DISPLAY_NAME="<group-name>"
GROUP_MAIL_NICKNAME="<group-mail-nickname>"
GROUP_DESCRIPTION="<group-description>"
az ad group create \
  --display-name $GROUP_DISPLAY_NAME \
  --mail-nickname $GROUP_MAIL_NICKNAME \
  --description $GROUP_DESCRIPTION

Aby dodać członków do grupy, potrzebny jest identyfikator obiektu głównej jednostki usługi aplikacji, który różni się od identyfikatora aplikacji. Użyj polecenia az ad sp list, aby wyświetlić dostępne zasady usługi. Polecenie --filter parametru akceptuje filtry stylu OData i może służyć do filtrowania listy, jak pokazano. Parametr --query ogranicza kolumny tylko do tych, które cię interesują.

SP_OBJECT_ID=$(az ad sp list \
  --filter "startswith(displayName,'$GROUP_DISPLAY_NAME')" \
  --query "[0].id" \
  --output tsv)

Polecenie az ad group member add można następnie użyć do dodawania członków do grup.

az ad group member add \
    --group $GROUP_DISPLAY_NAME \
    --member-id $SP_OBJECT_ID

Uwaga

Domyślnie tworzenie grup zabezpieczeń firmy Microsoft Entra jest ograniczone do niektórych ról uprzywilejowanych w katalogu. Jeśli nie możesz utworzyć grupy, skontaktuj się z administratorem katalogu. Jeśli nie możesz dodać członków do istniejącej grupy, skontaktuj się z właścicielem grupy lub administratorem katalogu. Aby dowiedzieć się więcej, zobacz Zarządzanie grupami i członkostwem w grupach firmy Microsoft.

3 — Przypisywanie ról do aplikacji

Następnie należy określić, jakich ról (uprawnień) potrzebuje twoja aplikacja na temat zasobów i przypisać te role do aplikacji. W tym przykładzie role są przypisywane do grupy Microsoft Entra utworzonej w kroku 2. Role można przypisywać w zakresie zasobu, grupy zasobów lub subskrypcji. W tym przykładzie pokazano, jak przypisywać role w zakresie grupy zasobów, ponieważ większość aplikacji grupuje wszystkie zasoby platformy Azure w jedną grupę zasobów.

Użytkownik, grupa lub jednostka usługi aplikacji otrzymuje rolę w usłudze Azure z użyciem polecenia az role assignment create. Możesz określić grupę z jej identyfikatorem obiektu. Jednostkę usługi aplikacji można określić przy użyciu jej identyfikatora appId.

RESOURCE_GROUP_NAME=<resource-group-name>
SUBSCRIPTION_ID=$(az account show --query id --output tsv)
ROLE_NAME=<role-name>
az role assignment create \
  --assignee "$APP_ID" \
  --scope "./subscriptions/$SUBSCRIPTION_ID/resourceGroups/$RESOURCE_GROUP_NAME" \
  --role "$ROLE_NAME"

![!UWAGA] Aby zapobiec traktowaniu przez Git Bash "/subscriptions/..." jako ścieżki pliku, dopełnij ciąg ./ parametrem scope i użyj podwójnych cudzysłowów wokół całego ciągu.

Aby uzyskać nazwy ról, które można przypisać, użyj polecenia az role definition list.

az role definition list \
    --query "sort_by([].{roleName:roleName, description:description}, &roleName)" \
    --output table

Aby na przykład umożliwić jednostce usługi aplikacji z identyfikatorem appId 00001111-aaaa-2222-bbbb-3333cccc4444 dostęp do odczytu, zapisu i usuwania w kontenerach obiektów blob usługi Azure Storage oraz danych we wszystkich kontach magazynu w grupie zasobów msdocs-python-sdk-auth-example w subskrypcji o identyfikatorze aaaa0a0a-bb1b-cc2c-dd3d-eeeeee4e4e4e, należy przypisać jednostkę usługi aplikacji do roli Storage Blob Data Contributor przy użyciu następującego polecenia.

az role assignment create --assignee 00001111-aaaa-2222-bbbb-3333cccc4444 \
    --scope "./subscriptions/aaaa0a0a-bb1b-cc2c-dd3d-eeeeee4e4e4e/resourceGroups/msdocs-python-sdk-auth-example" \
    --role "Storage Blob Data Contributor"

Aby uzyskać informacje na temat przypisywania uprawnień na poziomie zasobu lub subskrypcji przy użyciu interfejsu wiersza polecenia platformy Azure, zobacz artykuł Przypisywanie ról platformy Azure przy użyciu interfejsu wiersza polecenia platformy Azure.

4 — Ustawianie lokalnych zmiennych środowiskowych programowania

Obiekt DefaultAzureCredential będzie szukać informacji o jednostce usługi w zestawie zmiennych środowiskowych w czasie wykonywania. Ponieważ większość deweloperów pracuje nad wieloma aplikacjami, zaleca się użycie pakietu takiego jak python-dotenv w celu uzyskania dostępu do środowiska z pliku przechowywanego .env w katalogu aplikacji podczas programowania. Obejmuje to zmienne środowiskowe używane do uwierzytelniania aplikacji na platformie Azure, tak aby mogły być używane tylko przez tę aplikację.

Plik .env nigdy nie jest ewidencjony w kontroli źródła, ponieważ zawiera klucz tajny aplikacji dla platformy Azure. Standardowy plik .gitignore dla języka Pythona automatycznie wyklucza .env plik z zatwierdzenia.

Aby użyć pakietu python-dotenv, najpierw zainstaluj pakiet w aplikacji.

pip install python-dotenv

Następnie utwórz .env plik w katalogu głównym aplikacji. Ustaw wartości zmiennych środowiskowych z wartościami uzyskanymi z procesu rejestracji aplikacji w następujący sposób:

  • AZURE_CLIENT_ID → wartość identyfikatora aplikacji.
  • AZURE_TENANT_ID → wartość identyfikatora najemcy.
  • AZURE_CLIENT_SECRET → hasło/poświadczenia wygenerowane dla aplikacji.
AZURE_CLIENT_ID=00001111-aaaa-2222-bbbb-3333cccc4444
AZURE_TENANT_ID=aaaabbbb-0000-cccc-1111-dddd2222eeee
AZURE_CLIENT_SECRET=Ee5Ff~6Gg7.-Hh8Ii9Jj0Kk1Ll2Mm3_Nn4Oo5Pp6

Na koniec w kodzie uruchamiania aplikacji użyj biblioteki python-dotenv, aby podczas uruchamiania odczytać zmienne środowiskowe z pliku .env.

from dotenv import load_dotenv

if ( os.environ['ENVIRONMENT'] == 'development'):
    print("Loading environment variables from .env file")
    load_dotenv(".env")

5 — Zaimplementowanie DefaultAzureCredential w aplikacji

Aby uwierzytelnić obiekty klienta zestawu Azure SDK na platformie Azure, aplikacja powinna używać DefaultAzureCredential klasy z azure.identity pakietu. W tym scenariuszu DefaultAzureCredential wykryje, że zmienne środowiskowe AZURE_CLIENT_ID, AZURE_TENANT_ID i AZURE_CLIENT_SECRET są ustawione, i odczyta te zmienne, aby uzyskać informacje o jednostce usługi aplikacji w celu nawiązania połączenia z platformą Azure.

Zacznij od dodania pakietu azure.identity do aplikacji.

pip install azure-identity

Następnie w przypadku dowolnego kodu w języku Python, który tworzy obiekt klienta zestawu Azure SDK w aplikacji, należy wykonać następujące czynności:

  1. Zaimportuj klasę DefaultAzureCredential z modułu azure.identity .
  2. Utwórz DefaultAzureCredential obiekt.
  3. Przekaż obiekt DefaultAzureCredential do konstruktora obiektu klienta zestawu Azure SDK.

Przykład jest pokazany w następującym segmencie kodu.

from azure.identity import DefaultAzureCredential
from azure.storage.blob import BlobServiceClient

# Acquire a credential object
token_credential = DefaultAzureCredential()

blob_service_client = BlobServiceClient(
        account_url="https://<my_account_name>.blob.core.windows.net",
        credential=token_credential)