Delen via


Python-apps verifiëren bij Azure-services tijdens lokale ontwikkeling met behulp van service-principals

Bij het bouwen van cloudtoepassingen moeten ontwikkelaars hun apps vaak lokaal uitvoeren en testen. Zelfs tijdens lokale ontwikkeling moet de toepassing worden geverifieerd bij alle Azure-services waarmee deze communiceert. In dit artikel wordt uitgelegd hoe u specifieke service-principal-identiteiten configureert voor gebruik tijdens lokale ontwikkeling.

Een diagram waarin wordt getoond hoe een app die wordt uitgevoerd in de lokale ontwikkelaar de toepassingsservice-principal verkrijgt van een .env-bestand en die identiteit vervolgens gebruikt om verbinding te maken met Azure-resources.

Toegewezen toepassingsservice-principals voor lokale ontwikkeling ondersteunen het principe van minimale bevoegdheden door de toegang te beperken tot alleen de Azure-resources die tijdens de ontwikkeling door de app zijn vereist. Het gebruik van een speciale toepassingsservice-principal vermindert het risico op onbedoelde toegang tot andere resources en helpt bij het voorkomen van machtigingsgerelateerde fouten bij het overstappen naar productie, waarbij bredere machtigingen tot problemen kunnen leiden.

Wanneer u toepassingen registreert voor lokale ontwikkeling in Azure, is het raadzaam het volgende te doen:

  • Maak afzonderlijke app-registraties voor elke ontwikkelaar: hiermee beschikt elke ontwikkelaar over een eigen service-principal, om te voorkomen dat referenties hoeven te worden gedeeld en gedetailleerder toegangsbeheer moet worden ingeschakeld.
  • Afzonderlijke app-registraties maken voor elke toepassing: hiermee zorgt u ervoor dat elke app alleen over de benodigde machtigingen beschikt, waardoor de potentiële kwetsbaarheid voor aanvallen wordt verminderd.

Als u verificatie wilt inschakelen tijdens lokale ontwikkeling, stelt u omgevingsvariabelen in met de referenties van de toepassingsservice-principal. De Azure SDK voor Python detecteert deze variabelen en gebruikt deze om aanvragen voor Azure-services te verifiëren.

1 - De toepassing registreren in Azure

Toepassingsservice-principalobjecten worden gemaakt wanneer u een app registreert in Azure. Deze registratie kan worden uitgevoerd met behulp van Azure Portal of de Azure CLI. Het registratieproces maakt een app-registratie in Microsoft Entra ID (voorheen Azure Active Directory) en genereert een service-principal-object voor de app. Het service-principal-object wordt gebruikt om de app te verifiëren bij Azure-services. Het app-registratieproces genereert ook een clientgeheim (wachtwoord) voor de app. Dit geheim wordt gebruikt om de app te verifiëren bij Azure-services. Het clientgeheim wordt nooit opgeslagen in broncodebeheer, maar in een .env bestand in de toepassingsmap. Het .env bestand wordt gelezen door de toepassing tijdens runtime om omgevingsvariabelen in te stellen die door de Azure SDK voor Python worden gebruikt om de app te verifiëren. In de volgende stappen ziet u hoe u een app registreert in Azure en een service-principal voor de app maakt. De stappen worden weergegeven voor zowel de Azure CLI als de Azure-portal.

Azure CLI-opdrachten kunnen worden uitgevoerd in Azure Cloud Shell of op een werkstation waarop de Azure CLI is geïnstalleerd.

Gebruik eerst de opdracht az ad sp create-for-rbac om een nieuwe service-principal voor de app te maken. Met de opdracht wordt ook tegelijkertijd de app-registratie voor de app gemaakt.

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

De uitvoer van deze opdracht is vergelijkbaar met de volgende. Noteer deze waarden of houd dit venster open, omdat u deze waarden nodig hebt in de volgende stappen en de waarde voor het wachtwoord (clientgeheim) niet meer kunt weergeven. U kunt echter later een nieuw wachtwoord toevoegen zonder de service-principal of bestaande wachtwoorden indien nodig ongeldig te maken.

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

Vervolgens moet u de appID waarde ophalen en opslaan in een variabele. Deze waarde wordt gebruikt om omgevingsvariabelen in te stellen in uw lokale ontwikkelomgeving, zodat de Azure SDK voor Python kan worden geverifieerd bij Azure met behulp van de service-principal.

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

2 - Een Microsoft Entra-beveiligingsgroep maken voor lokale ontwikkeling

Aangezien er doorgaans meerdere ontwikkelaars zijn die aan een toepassing werken, is het raadzaam om een Microsoft Entra-beveiligingsgroep te maken om de rollen (machtigingen) die de app nodig heeft in lokale ontwikkeling in te kapselen in plaats van de rollen toe te wijzen aan afzonderlijke service-principal-objecten. Dit biedt de volgende voordelen:

  • Elke ontwikkelaar weet zeker dat dezelfde rollen zijn toegewezen omdat rollen op groepsniveau worden toegewezen.
  • Als er een nieuwe rol nodig is voor de app, hoeft deze alleen te worden toegevoegd aan de Microsoft Entra-groep voor de app.
  • Als een nieuwe ontwikkelaar lid wordt van het team, wordt er een nieuwe toepassingsservice-principal gemaakt voor de ontwikkelaar en toegevoegd aan de groep, zodat de ontwikkelaar over de juiste machtigingen beschikt om aan de app te werken.

De opdracht az ad group create wordt gebruikt voor het maken van beveiligingsgroepen in Microsoft Entra ID. De parameters --display-name en --main-nickname zijn vereist. De naam die aan de groep wordt gegeven, moet zijn gebaseerd op de naam van de toepassing. Het is ook handig om een term zoals 'local-dev' op te nemen in de naam van de groep om het doel van de groep aan te geven.

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

Als u leden aan de groep wilt toevoegen, hebt u de object-id van de service-principal van de toepassing nodig. Dit verschilt van de toepassings-id. Gebruik de az ad sp lijst om de beschikbare service-principals weer te geven. De --filter parameteropdracht accepteert OData-stijlfilters en kan worden gebruikt om de lijst te filteren zoals wordt weergegeven. De --query parameter beperkt zich tot alleen kolommen die van belang zijn.

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

De opdracht az ad group member add kan vervolgens worden gebruikt om leden toe te voegen aan groepen.

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

Notitie

Standaard is het maken van Microsoft Entra-beveiligingsgroepen beperkt tot bepaalde bevoorrechte rollen in een directory. Als u geen groep kunt maken, neemt u contact op met een beheerder voor uw adreslijst. Als u geen leden kunt toevoegen aan een bestaande groep, neemt u contact op met de groepseigenaar of een adreslijstbeheerder. Zie Microsoft Entra-groepen en groepslidmaatschap beheren voor meer informatie.

3 - Rollen toewijzen aan de toepassing

Vervolgens moet u bepalen welke rollen (machtigingen) uw app nodig heeft voor welke resources en welke rollen aan uw app worden toegewezen. In dit voorbeeld worden de rollen toegewezen aan de Microsoft Entra-groep die in stap 2 is gemaakt. Rollen kunnen worden toegewezen aan een resource, resourcegroep of abonnementsbereik. In dit voorbeeld ziet u hoe u rollen toewijst aan het bereik van de resourcegroep, omdat de meeste toepassingen al hun Azure-resources groeperen in één resourcegroep.

Aan een gebruiker, groep of toepassingsservice-principal wordt een rol toegewezen in Azure met behulp van de opdracht az role assignment create . U kunt een groep opgeven met de bijbehorende object-id. U kunt een toepassingsservice-principal opgeven met de bijbehorende 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"

![!OPMERKING] Om te voorkomen dat Git Bash /subscriptions/... als een bestandspad behandelt, voeg ./ toe aan de tekenreeks voor de scope-parameter en gebruik dubbele aanhalingstekens rond de hele tekenreeks.

Gebruik de opdracht az role definition list om de rolnamen op te halen die kunnen worden toegewezen.

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

Als u bijvoorbeeld de service-principal van de toepassing met de appId 00001111-aaaa-2222-bbbb-3333cccc4444 lees-, schrijf- en verwijdertoegang wilt geven tot Azure Storage-blobcontainers en -gegevens in alle opslagaccounts binnen de resourcegroep msdocs-python-sdk-auth-example in de abonnement-ID aaaa0a0a-bb1b-cc2c-dd3d-eeeeee4e4e4e, wijst u de service-principal van de toepassing toe aan de rol Storage Blob Data Contributor met behulp van de volgende opdracht.

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"

Zie het artikel Azure-rollen toewijzen met behulp van de Azure CLI voor informatie over het toewijzen van machtigingen op resource- of abonnementsniveau met behulp van de Azure CLI.

4 - Omgevingsvariabelen voor lokale ontwikkeling instellen

Het DefaultAzureCredential-object zoekt tijdens de uitvoeringstijd naar de informatie van de service-principal in een set omgevingsvariabelen. Omdat de meeste ontwikkelaars aan meerdere toepassingen werken, is het raadzaam om een pakket zoals python-dotenv te gebruiken voor toegang tot de omgeving vanuit een .env bestand dat tijdens de ontwikkeling in de map van de toepassing is opgeslagen. Dit is het bereik van de omgevingsvariabelen die worden gebruikt voor het verifiëren van de toepassing bij Azure, zodat ze alleen door deze toepassing kunnen worden gebruikt.

Het .env bestand wordt nooit ingecheckt bij broncodebeheer omdat het de geheime sleutel van de toepassing voor Azure bevat. Het standaard .gitignore-bestand voor Python sluit het .env bestand automatisch uit van het inchecken.

Als u het python-dotenv-pakket wilt gebruiken, installeert u eerst het pakket in uw toepassing.

pip install python-dotenv

Maak vervolgens een .env bestand in de hoofdmap van uw toepassing. Stel de omgevingsvariabelewaarden als volgt in met waarden die zijn verkregen uit het app-registratieproces:

  • AZURE_CLIENT_ID → de waarde van de app-id.
  • AZURE_TENANT_ID → de waarde van de tenant-id.
  • AZURE_CLIENT_SECRET → het wachtwoord/de referentie die voor de app is gegenereerd.
AZURE_CLIENT_ID=00001111-aaaa-2222-bbbb-3333cccc4444
AZURE_TENANT_ID=aaaabbbb-0000-cccc-1111-dddd2222eeee
AZURE_CLIENT_SECRET=Ee5Ff~6Gg7.-Hh8Ii9Jj0Kk1Ll2Mm3_Nn4Oo5Pp6

Gebruik ten slotte in de opstartcode voor uw toepassing de python-dotenv bibliotheek om de omgevingsvariabelen uit het bestand bij het .env opstarten te lezen.

from dotenv import load_dotenv

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

5 - DefaultAzureCredential implementeren in uw toepassing

Als u Azure SDK-clientobjecten wilt verifiëren bij Azure, moet uw toepassing de DefaultAzureCredential klasse van het azure.identity pakket gebruiken. In dit scenario worden de omgevingsvariabelen DefaultAzureCredential, AZURE_CLIENT_ID, en AZURE_TENANT_ID gedetecteerd en gelezen om de service-principalgegevens van de toepassing op te halen waarmee verbinding met Azure kan worden gemaakt.

Begin met het toevoegen van het pakket azure.identity aan uw toepassing.

pip install azure-identity

Vervolgens wilt u voor elke Python-code die een Azure SDK-clientobject maakt in uw app het volgende doen:

  1. Importeer de DefaultAzureCredential klasse uit de azure.identity module.
  2. Maak een DefaultAzureCredential object.
  3. Geef het DefaultAzureCredential object door aan de objectconstructor van de Azure SDK-client.

Een voorbeeld hiervan wordt weergegeven in het volgende codesegment.

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)