[ { "id": "azure-lab-1", "title": "리소스 그룹 생성", "task_description": "Korea Central 지역에 `myRG`라는 리소스 그룹을 만드세요.", "expected_command": "az group create --name myRG --location koreacentral", "grading_conditions": ["az group create", "--name myRG", "--location koreacentral"], "hint": "`az group create --name <이름> --location <지역>` 형식을 사용합니다.", "explanation": "리소스 그룹은 Azure 리소스를 논리적으로 묶는 컨테이너입니다. 지역은 메타데이터 저장 위치이며 내부 리소스와 달라도 됩니다.", "difficulty": "easy" }, { "id": "azure-lab-2", "title": "스토리지 계정 생성 (Standard LRS)", "task_description": "`myRG` 리소스 그룹에 Standard_LRS 중복성을 가진 `mystorageacct` 스토리지 계정을 생성하세요.", "expected_command": "az storage account create --name mystorageacct --resource-group myRG --sku Standard_LRS --kind StorageV2", "grading_conditions": ["az storage account create", "--name mystorageacct", "--resource-group myRG", "--sku Standard_LRS"], "hint": "`az storage account create`에 `--sku`와 `--kind` 옵션을 추가합니다.", "explanation": "StorageV2(범용 v2)는 현재 권장 스토리지 종류입니다. LRS는 단일 데이터센터 내 3복제로 가장 저렴한 중복성입니다.", "difficulty": "easy" }, { "id": "azure-lab-3", "title": "가상 네트워크와 서브넷 생성", "task_description": "`myRG`에 주소 공간 `10.0.0.0/16`, 서브넷 `default`(`10.0.0.0/24`)를 가진 VNet `myVNet`을 생성하세요.", "expected_command": "az network vnet create --name myVNet --resource-group myRG --address-prefix 10.0.0.0/16 --subnet-name default --subnet-prefix 10.0.0.0/24", "grading_conditions": ["az network vnet create", "--name myVNet", "--address-prefix 10.0.0.0/16", "--subnet-name default", "--subnet-prefix 10.0.0.0/24"], "hint": "`az network vnet create`에 `--address-prefix`와 `--subnet-name`, `--subnet-prefix`를 함께 지정합니다.", "explanation": "VNet 주소 공간(/16)과 서브넷 범위(/24)는 포함 관계여야 합니다. Azure는 각 서브넷에서 5개 IP를 예약합니다.", "difficulty": "easy" }, { "id": "azure-lab-4", "title": "NSG 규칙으로 SSH 허용", "task_description": "NSG `myNSG`에 우선순위 100으로 TCP 포트 22 인바운드를 허용하는 규칙 `allow-ssh`를 추가하세요.", "expected_command": "az network nsg rule create --nsg-name myNSG --resource-group myRG --name allow-ssh --priority 100 --access Allow --protocol Tcp --destination-port-ranges 22", "grading_conditions": ["az network nsg rule create", "--nsg-name myNSG", "--name allow-ssh", "--priority 100", "--access Allow", "--destination-port-ranges 22"], "hint": "`az network nsg rule create`에 `--priority`, `--access`, `--protocol`, `--destination-port-ranges`를 지정합니다.", "explanation": "NSG 규칙은 우선순위 숫자가 낮을수록 먼저 적용됩니다. 100은 기본 규칙(65000~65500)보다 훨씬 높은 우선순위입니다.", "difficulty": "easy" }, { "id": "azure-lab-5", "title": "RBAC 역할 할당 (Contributor)", "task_description": "`alice@example.com`에게 `myRG` 리소스 그룹 범위의 `Contributor` 역할을 할당하세요.", "expected_command": "az role assignment create --assignee alice@example.com --role Contributor --scope /subscriptions/SUB_ID/resourceGroups/myRG", "grading_conditions": ["az role assignment create", "--assignee alice@example.com", "--role Contributor", "--scope"], "hint": "`az role assignment create`에 `--assignee`, `--role`, `--scope`를 지정합니다. scope는 리소스 그룹의 전체 ARM ID입니다.", "explanation": "Contributor는 리소스 생성/수정/삭제는 가능하지만 역할 할당은 불가합니다. Owner만 역할 할당 권한을 가집니다.", "difficulty": "medium" }, { "id": "azure-lab-6", "title": "리소스 잠금 설정 (CanNotDelete)", "task_description": "`myRG` 리소스 그룹에 `CanNotDelete` 잠금 `prod-lock`을 설정하세요.", "expected_command": "az lock create --name prod-lock --resource-group myRG --lock-type CanNotDelete", "grading_conditions": ["az lock create", "--name prod-lock", "--resource-group myRG", "--lock-type CanNotDelete"], "hint": "`az lock create`에 `--lock-type`으로 `CanNotDelete` 또는 `ReadOnly`를 선택합니다.", "explanation": "CanNotDelete 잠금은 읽기와 수정은 허용하지만 삭제를 차단합니다. Owner라도 잠금을 먼저 해제해야 삭제할 수 있습니다.", "difficulty": "easy" }, { "id": "azure-lab-7", "title": "Blob 접근 계층 변경 (Cool)", "task_description": "`mycontainer`의 `report.log` Blob을 Cool 계층으로 변경하세요.", "expected_command": "az storage blob set-tier --account-name mystorageacct --container-name mycontainer --name report.log --tier Cool", "grading_conditions": ["az storage blob set-tier", "--account-name mystorageacct", "--container-name mycontainer", "--name report.log", "--tier Cool"], "hint": "`az storage blob set-tier`에 `--tier`로 Hot/Cool/Cold/Archive를 지정합니다.", "explanation": "Cool 계층은 30일 이상 저장하는 데이터에 적합합니다. 저장 비용은 낮지만 접근 비용이 Hot보다 높습니다.", "difficulty": "easy" }, { "id": "azure-lab-8", "title": "VM 백업 활성화", "task_description": "`myVault` Recovery Services Vault에서 `myVM` 가상 머신의 백업을 `DefaultPolicy`로 활성화하세요.", "expected_command": "az backup protection enable-for-vm --vault-name myVault --resource-group myRG --vm myVM --policy-name DefaultPolicy", "grading_conditions": ["az backup protection enable-for-vm", "--vault-name myVault", "--vm myVM", "--policy-name DefaultPolicy"], "hint": "`az backup protection enable-for-vm`에 vault, vm, policy 이름을 지정합니다.", "explanation": "VM 백업 활성화 후 최초 백업은 즉시 트리거하거나 다음 예약 시간까지 기다립니다. Vault와 VM은 같은 region에 있어야 합니다.", "difficulty": "medium" }, { "id": "azure-lab-9", "title": "Key Vault 비밀 저장", "task_description": "`myKV` Key Vault에 `db-password`라는 이름으로 `MyP@ss123` 비밀을 저장하세요.", "expected_command": "az keyvault secret set --vault-name myKV --name db-password --value MyP@ss123", "grading_conditions": ["az keyvault secret set", "--vault-name myKV", "--name db-password", "--value"], "hint": "`az keyvault secret set`에 vault 이름, 비밀 이름, 값을 지정합니다.", "explanation": "비밀은 버전 관리됩니다. 같은 이름으로 다시 저장하면 새 버전이 생성되고 이전 버전은 비활성화됩니다.", "difficulty": "easy" }, { "id": "azure-lab-10", "title": "VNet 피어링 생성", "task_description": "`VNet1`에서 `VNet2`로 향하는 피어링 `VNet1-to-VNet2`를 생성하세요. (resource group: myRG)", "expected_command": "az network vnet peering create --name VNet1-to-VNet2 --vnet-name VNet1 --remote-vnet VNet2 --resource-group myRG", "grading_conditions": ["az network vnet peering create", "--name VNet1-to-VNet2", "--vnet-name VNet1", "--remote-vnet VNet2"], "hint": "피어링은 양방향을 각각 만들어야 합니다. 이 명령은 VNet1→VNet2 방향입니다.", "explanation": "VNet 피어링은 비전이적(non-transitive)입니다. A↔B, B↔C가 있어도 A에서 C로는 직접 통신 불가이며 A↔C를 별도 생성해야 합니다.", "difficulty": "medium" }, { "id": "azure-lab-11", "title": "Private Endpoint 생성 (Blob)", "task_description": "`myVNet`의 `default` 서브넷에 스토리지 계정 `mystorageacct`의 blob 서비스용 Private Endpoint `myPE`를 생성하세요.", "expected_command": "az network private-endpoint create --name myPE --resource-group myRG --vnet-name myVNet --subnet default --private-connection-resource-id /subscriptions/SUB_ID/resourceGroups/myRG/providers/Microsoft.Storage/storageAccounts/mystorageacct --group-ids blob --connection-name myPEConnection", "grading_conditions": ["az network private-endpoint create", "--name myPE", "--vnet-name myVNet", "--group-ids blob"], "hint": "`--private-connection-resource-id`에 스토리지 계정의 전체 ARM ID를 넣고, `--group-ids blob`을 지정합니다.", "explanation": "Private Endpoint는 PaaS 서비스에 VNet 내 사설 IP를 부여합니다. 생성 후 Private DNS Zone 연결이 있어야 DNS 해석이 올바르게 됩니다.", "difficulty": "hard" }, { "id": "azure-lab-12", "title": "Azure Bastion 생성", "task_description": "`myVNet`에 Public IP `myBastionIP`를 사용하는 Azure Bastion `myBastion`을 Korea Central에 생성하세요.", "expected_command": "az network bastion create --name myBastion --public-ip-address myBastionIP --resource-group myRG --vnet-name myVNet --location koreacentral", "grading_conditions": ["az network bastion create", "--name myBastion", "--public-ip-address myBastionIP", "--vnet-name myVNet"], "hint": "Bastion 생성 전 VNet에 `AzureBastionSubnet`(/27 이상)이 반드시 있어야 합니다.", "explanation": "Azure Bastion은 VM에 Public IP 없이 포털에서 RDP/SSH 접근을 제공합니다. AzureBastionSubnet 이름은 정확히 일치해야 합니다.", "difficulty": "medium" }, { "id": "azure-lab-13", "title": "App Service 웹앱 생성", "task_description": "`myPlan` App Service 플랜을 사용하는 `myWebApp` 웹앱을 Node.js 18 LTS 런타임으로 생성하세요.", "expected_command": "az webapp create --name myWebApp --resource-group myRG --plan myPlan --runtime NODE:18-lts", "grading_conditions": ["az webapp create", "--name myWebApp", "--resource-group myRG", "--plan myPlan", "--runtime"], "hint": "`az webapp create`에 `--plan`과 `--runtime`을 지정합니다. 런타임 목록은 `az webapp list-runtimes`로 확인합니다.", "explanation": "App Service는 런타임 환경과 배포 방법을 유연하게 선택할 수 있는 PaaS입니다. 같은 플랜의 앱들은 컴퓨팅 리소스를 공유합니다.", "difficulty": "easy" }, { "id": "azure-lab-14", "title": "배포 슬롯 생성 (staging)", "task_description": "`myWebApp` 웹앱에 `staging` 배포 슬롯을 생성하세요.", "expected_command": "az webapp deployment slot create --name myWebApp --resource-group myRG --slot staging", "grading_conditions": ["az webapp deployment slot create", "--name myWebApp", "--slot staging"], "hint": "`az webapp deployment slot create`에 `--slot`으로 슬롯 이름을 지정합니다. Standard 이상 플랜이 필요합니다.", "explanation": "배포 슬롯은 다운타임 없이 스테이징 버전을 테스트하고 swap으로 즉시 교체하는 데 사용됩니다.", "difficulty": "easy" }, { "id": "azure-lab-15", "title": "경보 규칙 생성 (CPU 80%)", "task_description": "`myVM`의 평균 CPU 사용률이 80%를 초과하면 `alice@example.com`으로 알림을 보내는 경보 규칙을 생성하세요.", "expected_command": "az monitor alert create --name highCPU --resource-group myRG --resource myVM --resource-type Microsoft.Compute/virtualMachines --condition avg Percentage CPU > 80 --action email alice@example.com", "grading_conditions": ["az monitor alert create", "--name highCPU", "--condition", "Percentage CPU", "> 80", "--action email alice@example.com"], "hint": "`az monitor alert create`에 `--condition`으로 메트릭 이름과 임계값을, `--action`으로 알림 방법을 지정합니다.", "explanation": "경보는 Action Group 없이는 발생해도 알 수 없습니다. --action email로 간단하게 지정하거나, 별도 Action Group을 생성해 연결합니다.", "difficulty": "medium" } ]