클라우드 애플리케이션을 빌드할 때 개발자는 종종 로컬에서 앱을 실행하고 테스트해야 합니다. 로컬 개발 중에도 애플리케이션은 상호 작용하는 모든 Azure 서비스에 인증해야 합니다. 이 문서에서는 로컬 개발 중에 사용할 전용 서비스 주체 ID를 구성하는 방법을 설명합니다.
로컬 개발을 위한 전용 애플리케이션 서비스 주체는 개발 중에 앱에 필요한 Azure 리소스에만 대한 액세스를 제한하여 최소 권한 원칙을 지원합니다. 전용 애플리케이션 서비스 주체를 사용하면 다른 리소스에 대한 의도하지 않은 액세스 위험을 줄이고 프로덕션으로 전환할 때 권한 관련 버그를 방지할 수 있습니다. 이 경우 더 광범위한 권한으로 인해 문제가 발생할 수 있습니다.
Azure에서 로컬 개발을 위해 애플리케이션을 등록하는 경우 다음을 수행하는 것이 좋습니다.
- 각 개발자에 대해 별도의 앱 등록 만들기: 자격 증명을 공유할 필요가 없도록 하고 보다 세부적인 액세스 제어를 사용하도록 설정하여 각 개발자에게 고유한 서비스 주체를 제공합니다.
- 각 애플리케이션에 대해 별도의 앱 등록 만들기: 이렇게 하면 각 앱에 필요한 권한만 있으므로 잠재적인 공격 노출 영역이 줄어듭니다.
로컬 개발 중에 인증을 사용하도록 설정하려면 애플리케이션 서비스 주체의 자격 증명으로 환경 변수를 설정합니다. Python용 Azure SDK는 이러한 변수를 검색하고 이를 사용하여 Azure 서비스에 대한 요청을 인증합니다.
1 - Azure에 애플리케이션 등록
애플리케이션 서비스 주체 개체는 Azure에서 앱을 등록할 때 만들어집니다. 이 등록은 Azure Portal 또는 Azure CLI를 사용하여 수행할 수 있습니다. 등록 프로세스는 Microsoft Entra ID(이전의 Azure Active Directory)에서 앱 등록을 만들고 앱에 대한 서비스 주체 개체를 생성합니다. 서비스 주체 개체는 Azure 서비스에 앱을 인증하는 데 사용됩니다.
또한 앱 등록 프로세스는 앱에 대한 클라이언트 암호(암호)를 생성합니다. 이 비밀은 Azure 서비스에 앱을 인증하는 데 사용됩니다. 클라이언트 암호는 원본 제어에 저장되지 않고 .env
애플리케이션 디렉터리의 파일에 저장됩니다. Python .env
용 Azure SDK가 앱을 인증하는 데 사용하는 환경 변수를 설정하기 위해 런타임 시 애플리케이션에서 파일을 읽습니다.
다음 단계에서는 Azure에서 앱을 등록하고 앱에 대한 서비스 주체를 만드는 방법을 보여 있습니다. 단계는 Azure CLI와 Azure Portal 모두에 대해 표시됩니다.
Azure CLI 명령은 Azure Cloud Shell에서 실행하거나 Azure CLI가 설치된 워크스테이션에서 실행할 수 있습니다.
먼저, az ad sp create-for-rbac 명령을 사용하여 앱에 대한 새 서비스 주체를 만듭니다. 또한 이 명령은 앱에 대한 앱 등록을 동시에 만듭니다.
SERVICE_PRINCIPAL_NAME=<service-principal-name>
az ad sp create-for-rbac --name $SERVICE_PRINCIPAL_NAME
이 명령의 출력은 다음과 유사합니다. 다음 단계에서 이러한 값이 필요하고 암호(클라이언트 암호) 값을 다시 볼 수 없으므로 이러한 값을 기록하거나 이 창을 열어 둡니다. 그러나 필요한 경우 서비스 주체 또는 기존 암호를 무효화하지 않고 나중에 새 암호를 추가할 수 있습니다.
{
"appId": "00001111-aaaa-2222-bbbb-3333cccc4444",
"displayName": "<service-principal-name>",
"password": "Ee5Ff~6Gg7.-Hh8Ii9Jj0Kk1Ll2Mm3_Nn4Oo5Pp6",
"tenant": "aaaabbbb-0000-cccc-1111-dddd2222eeee"
}
다음으로, appID
값을 가져와 변수에 저장해야 합니다. 이 값은 Python용 Azure SDK가 서비스 주체를 사용하여 Azure에 인증할 수 있도록 로컬 개발 환경에서 환경 변수를 설정하는 데 사용됩니다.
APP_ID=$(az ad sp list \
--all \
--query "[?displayName=='$SERVICE_PRINCIPAL_NAME'].appId | [0]" \
--output tsv)
2 - 로컬 개발을 위한 Microsoft Entra 보안 그룹 만들기
일반적으로 애플리케이션에서 작업하는 여러 개발자가 있으므로 개별 서비스 주체 개체에 역할을 할당하는 대신 앱이 로컬 개발에 필요한 역할(권한)을 캡슐화하는 Microsoft Entra 보안 그룹을 만드는 것이 좋습니다. 이렇게 하면 다음과 같은 이점이 제공됩니다.
- 역할은 그룹 수준에서 할당되므로 모든 개발자는 동일한 역할을 할당받게 됩니다.
- 앱에 새 역할이 필요한 경우 앱에 대한 Microsoft Entra 그룹에만 추가하면 됩니다.
- 새로운 개발자가 팀에 합류하면 개발자를 위한 새로운 애플리케이션 서비스 주체가 만들어져 그룹에 추가되어 개발자에게 앱 작업에 대한 올바른 권한이 있는지 확인합니다.
az ad group create 명령은 Microsoft Entra ID에서 보안 그룹을 만드는 데 사용됩니다.
--display-name
및 --main-nickname
매개 변수는 필수 항목입니다. 그룹에 부여되는 이름은 애플리케이션 이름을 기반으로 해야 합니다. 그룹의 목적을 나타내기 위해 그룹 이름에 'local-dev'와 같은 구를 포함하는 것도 유용합니다.
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
그룹에 구성원을 추가하려면 애플리케이션 ID와 다른 애플리케이션 서비스 주체의 개체 ID가 필요합니다. 사용 가능한 서비스 주체를 나열하려면 az ad sp list를 사용합니다.
--filter
매개 변수 명령은 OData 스타일 필터를 허용하며 표시된 대로 목록을 필터링하는 데 사용할 수 있습니다.
--query
매개 변수는 관심 있는 항목으로만 열을 제한합니다.
SP_OBJECT_ID=$(az ad sp list \
--filter "startswith(displayName,'$GROUP_DISPLAY_NAME')" \
--query "[0].id" \
--output tsv)
그런 다음 az ad group member add 명령을 사용하여 그룹에 멤버를 추가할 수 있습니다.
az ad group member add \
--group $GROUP_DISPLAY_NAME \
--member-id $SP_OBJECT_ID
메모
기본적으로 Microsoft Entra 보안 그룹 만들기는 디렉터리의 특정 권한 있는 역할로 제한됩니다. 그룹을 만들 수 없는 경우 디렉터리의 관리자에게 문의하세요. 기존 그룹에 구성원을 추가할 수 없는 경우 그룹 소유자 또는 디렉터리 관리자에게 문의하세요. 자세한 내용은 Microsoft Entra 그룹 및 그룹 구성원 관리를 참조하세요.
3 - 애플리케이션에 역할 할당
다음으로, 어떤 리소스에 대해 앱에 필요한 역할(권한)을 결정하고 해당 역할을 앱에 할당해야 합니다. 이 예제에서는 2단계에서 만든 Microsoft Entra 그룹에 역할이 할당됩니다. 역할은 리소스, 리소스 그룹 또는 구독 범위에서 할당할 수 있습니다. 이 예제에서는 대부분의 애플리케이션이 모든 Azure 리소스를 단일 리소스 그룹으로 그룹화하기 때문에 리소스 그룹 범위에서 역할을 할당하는 방법을 보여 줍니다.
az role assignment create 명령을 사용하여 Azure에서 사용자, 그룹 또는 애플리케이션 서비스 주체에게 역할이 할당됩니다. 해당 개체 ID를 사용하여 그룹을 지정할 수 있습니다. 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"
! [! 참고] Git Bash가 /subscriptions를 처리하지 못하도록 방지하려면... 파일 경로로 매개 변수의 문자열 앞에 ./를 추가하고 전체 문자열
scope
주위에 큰따옴표를 사용합니다.
할당할 수 있는 역할 이름을 얻으려면 az role definition list 명령을 사용합니다.
az role definition list \
--query "sort_by([].{roleName:roleName, description:description}, &roleName)" \
--output table
예를 들어, 00001111-aaaa-2222-bbbb-3333cccc4444
앱 ID를 가진 애플리케이션 서비스 주체에게 구독 ID가 인 계정의 aaaa0a0a-bb1b-cc2c-dd3d-eeeeee4e4e4e
리소스 그룹 내 모든 스토리지 계정의 Azure Storage Blob 컨테이너 및 데이터에 대한 읽기, 쓰기, 삭제 권한을 부여하려면, 다음 명령을 사용하여 해당 애플리케이션 서비스 주체를 Storage Blob 데이터 기여자 역할에 할당합니다.
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"
Azure CLI를 사용하여 리소스 또는 구독 수준에서 권한을 할당하는 방법에 대한 자세한 내용은 Azure CLI를 사용하여 Azure 역할 할당 문서를 참조하세요.
4 - 로컬 개발 환경 변수 설정
DefaultAzureCredential
개체는 런타임 시 환경 변수 집합에서 서비스 주체 정보를 찾습니다. 대부분의 개발자는 여러 애플리케이션에서 작업하므로 python-dotenv와 같은 패키지를 사용하여 개발 중에 애플리케이션의 디렉터리에 저장된 파일에서 .env
환경에 액세스하는 것이 좋습니다. 이 범위는 이 애플리케이션에서만 사용할 수 있도록 Azure에 애플리케이션을 인증하는 데 사용되는 환경 변수의 범위를 지정합니다.
파일이 .env
Azure에 대한 애플리케이션 비밀 키를 포함하기 때문에 소스 제어에 체크 인되지 않습니다. Python용 표준 .gitignore 파일은 체크 인에서 파일을 자동으로 제외합니다 .env
.
python-dotenv 패키지를 사용하려면 먼저 애플리케이션에 패키지를 설치합니다.
pip install python-dotenv
그런 다음 애플리케이션 루트 디렉터리에 .env
파일을 만듭니다. 다음과 같이 앱 등록 프로세스에서 가져온 값으로 환경 변수 값을 설정합니다.
-
AZURE_CLIENT_ID
→ 앱 ID 값입니다. -
AZURE_TENANT_ID
→ 테넌트 ID 값입니다. -
AZURE_CLIENT_SECRET
→ 앱에 대해 생성된 암호/자격 증명입니다.
AZURE_CLIENT_ID=00001111-aaaa-2222-bbbb-3333cccc4444
AZURE_TENANT_ID=aaaabbbb-0000-cccc-1111-dddd2222eeee
AZURE_CLIENT_SECRET=Ee5Ff~6Gg7.-Hh8Ii9Jj0Kk1Ll2Mm3_Nn4Oo5Pp6
마지막으로 애플리케이션의 시작 코드에서 라이브러리를 python-dotenv
사용하여 시작 시 파일에서 환경 변수를 .env
읽습니다.
from dotenv import load_dotenv
if ( os.environ['ENVIRONMENT'] == 'development'):
print("Loading environment variables from .env file")
load_dotenv(".env")
5 - 애플리케이션에 DefaultAzureCredential 구현
Azure에 Azure SDK 클라이언트 개체를 인증하려면 애플리케이션에서 패키지의 클래스를 DefaultAzureCredential
azure.identity
사용해야 합니다. 이 시나리오에서는 DefaultAzureCredential
가 환경 변수 AZURE_CLIENT_ID
, AZURE_TENANT_ID
, 및 AZURE_CLIENT_SECRET
가 설정되었는지를 감지하고, 이러한 변수를 읽어 애플리케이션 서비스 주체 정보를 얻어 Azure에 연결합니다.
먼저 애플리케이션에 azure.identity 패키지를 추가합니다.
pip install azure-identity
다음으로, 앱에서 Azure SDK 클라이언트 개체를 만드는 Python 코드의 경우 다음을 수행합니다.
-
DefaultAzureCredential
모듈에서azure.identity
클래스를 가져옵니다. -
DefaultAzureCredential
개체를 만듭니다. - 개체를
DefaultAzureCredential
Azure SDK 클라이언트 개체 생성자에 전달합니다.
이 예제는 다음 코드 세그먼트에 나와 있습니다.
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)