Delen via


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

Ontwikkelaars moeten hun apps vaak lokaal uitvoeren en testen bij het bouwen van cloudtoepassingen. 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 volgen het principe van minimale bevoegdheden. Ze verlenen alleen toegang tot de Azure-resources die de app nodig heeft tijdens de ontwikkeling. Deze beperkte toegang vermindert het risico dat andere resources onbedoeld worden bereikt. Het helpt ook bij het voorkomen van problemen met betrekking tot machtigingen bij het verplaatsen naar productie, waarbij bredere machtigingen problemen kunnen veroorzaken.

Bij het registreren van toepassingen voor lokale ontwikkeling in Azure:

  • Afzonderlijke app-registraties maken voor elke ontwikkelaar: deze benadering biedt elke ontwikkelaar 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: Deze aanpak zorgt 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.

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 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. Tijdens runtime leest de toepassing het .env bestand is en stelt de omgevingsvariabelen in 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)

Een Microsoft Entra-beveiligingsgroep maken voor lokale ontwikkeling

Omdat meerdere ontwikkelaars meestal aan dezelfde toepassing werken, is het beter om machtigingen te beheren via een Microsoft Entra-beveiligingsgroep. Maak een beveiligingsgroep die de rollen bevat die de app nodig heeft voor lokale ontwikkeling, in plaats van rollen afzonderlijk toe te wijzen aan de service-principal van elke ontwikkelaar. Het gebruik van een beveiligingsgroep 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 de kolommen tot alleen de kolommen waarin u geïnteresseerd bent.

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.

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.

Gebruik de az role assignment create opdracht om een rol toe te wijzen aan een gebruiker, groep of toepassingsservice-principal. 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.

Omgevingsvariabelen voor lokale ontwikkeling instellen

Het DefaultAzureCredential object zoekt tijdens runtime naar de informatie van de serviceprincipal in een set omgevingsvariabelen. Omdat de meeste ontwikkelaars aan meerdere toepassingen werken, kunt u een pakket zoals python-dotenv gebruiken om toegang te krijgen tot een omgeving vanuit een .env-bestand dat tijdens de ontwikkeling in de applicatiemap is opgeslagen. Met deze instelling worden de omgevingsvariabelen beperkt, zodat alleen deze toepassing ze kan gebruiken om te authenticeren met Azure.

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")

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 detecteert DefaultAzureCredential dat de omgevingsvariabelen AZURE_CLIENT_ID, AZURE_TENANT_ID en AZURE_CLIENT_SECRET zijn ingesteld en leest deze variabelen vervolgens om de service-principalgegevens van de toepassing te verkrijgen voor verbinding met Azure.

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

pip install azure-identity

Vervolgens voor python-code waarmee een Azure SDK-clientobject in uw app wordt gemaakt:

  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)