Skip to content

Commit f2f0db5

Browse files
committed
feat: Refactor Azure deployment scripts and add ASP.NET Web App blueprint
1 parent f2673ed commit f2f0db5

File tree

7 files changed

+100
-23
lines changed

7 files changed

+100
-23
lines changed

.github/agents/security-agent.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ Identify vulnerabilities and misconfigurations, assess risk, and produce a secur
1515
Prioritize review of:
1616

1717
- `src/webapp01` (ASP.NET Core Razor Pages)
18-
- `infra/`, `terraform/`, `manifests/` (IaC)
18+
- `blueprints/`, `infra/`, `terraform/`, `bicep/`, `manifests/` (IaC)
1919
- `.github/workflows/` (pipeline security)
2020
- Container configuration (Dockerfiles) where present
2121

.github/workflows/cicd.yml

Lines changed: 28 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,10 @@ on:
77
workflow_dispatch:
88
inputs:
99
azure_location:
10-
description: 'Azure region for deployment'
10+
description: "Azure region for deployment"
1111
required: true
1212
type: choice
13-
default: 'canadacentral'
13+
default: "canadacentral"
1414
options:
1515
- canadacentral
1616
- canadaeast
@@ -21,10 +21,10 @@ on:
2121
- westeurope
2222
- northeurope
2323
instance_number:
24-
description: 'Instance number for resource naming'
24+
description: "Instance number for resource naming"
2525
required: true
2626
type: string
27-
default: '002'
27+
default: "003"
2828

2929
permissions:
3030
attestations: write
@@ -34,22 +34,24 @@ permissions:
3434
security-events: write
3535

3636
env:
37-
INSTANCE_NUMBER: ${{ github.event.inputs.instance_number || '002' }}
38-
AZURE_LOCATION: ${{ github.event.inputs.azure_location || 'canadacentral' }}
39-
AZURE_WEBAPP_NAME: app-gh-aspnet-webapp-${{ github.event.inputs.instance_number || '002' }}
37+
DEFAULT_INSTANCE_NUMBER: "003"
38+
DEFAULT_AZURE_LOCATION: "canadacentral"
4039
SRC_PROJECT_PATH: "/webapp01/webapp01.csproj"
4140
AZURE_WEBAPP_PACKAGE_PATH: "./src"
4241
DOTNET_VERSION: "9.0.x"
43-
AZURE_ACR_NAME: crdevsecopscldev${{ github.event.inputs.instance_number || '002' }}
4442

4543
jobs:
4644
deploy-infrastructure:
4745
name: Deploy Azure Infrastructure
4846
runs-on: ubuntu-latest
47+
env:
48+
INSTANCE_NUMBER: ${{ github.event.inputs.instance_number || 'DEFAULT_INSTANCE' }}
49+
AZURE_LOCATION: ${{ github.event.inputs.azure_location || 'DEFAULT_LOCATION' }}
4950
outputs:
5051
acr_name: ${{ steps.deploy.outputs.acr_name }}
5152
webapp_name: ${{ steps.deploy.outputs.webapp_name }}
5253
webapp_url: ${{ steps.deploy.outputs.webapp_url }}
54+
resource_group: ${{ steps.deploy.outputs.resource_group }}
5355
steps:
5456
- uses: actions/checkout@v5
5557

@@ -64,19 +66,19 @@ jobs:
6466
id: deploy
6567
shell: pwsh
6668
run: |
67-
$instanceNumber = "${{ env.INSTANCE_NUMBER }}"
68-
$location = "${{ env.AZURE_LOCATION }}"
69-
69+
$instanceNumber = "${{ env.INSTANCE_NUMBER }}".Replace('DEFAULT_INSTANCE', '${{ env.DEFAULT_INSTANCE_NUMBER }}')
70+
$location = "${{ env.AZURE_LOCATION }}".Replace('DEFAULT_LOCATION', '${{ env.DEFAULT_AZURE_LOCATION }}')
71+
7072
# Calculate resource names based on instance number
7173
$acrName = "crdevsecopscldev$instanceNumber"
7274
$appServicePlanName = "asp-gh-aspnet-webapp-$instanceNumber"
7375
$webAppName = "app-gh-aspnet-webapp-$instanceNumber"
7476
$resourceGroupName = "rg-gh-aspnet-webapp-$instanceNumber"
7577
$containerImage = "$acrName.azurecr.io/webapp01:latest"
76-
78+
7779
# Deployment name based only on instance number for idempotence
7880
$deploymentName = "deploy-infra-$instanceNumber"
79-
81+
8082
Write-Host "=== Azure Infrastructure Deployment ===" -ForegroundColor Cyan
8183
Write-Host "Instance Number: $instanceNumber" -ForegroundColor Green
8284
Write-Host "Location: $location" -ForegroundColor Green
@@ -85,43 +87,44 @@ jobs:
8587
Write-Host "Web App Name: $webAppName" -ForegroundColor Green
8688
Write-Host "Resource Group: $resourceGroupName" -ForegroundColor Green
8789
Write-Host "Deployment Name: $deploymentName" -ForegroundColor Green
88-
90+
8991
# Deploy using inline parameters instead of parameters file
9092
az deployment sub create `
9193
--name $deploymentName `
9294
--location $location `
93-
--template-file ./infra/main.bicep `
95+
--template-file ./blueprints/gh-aspnet-webapp/bicep/main.bicep `
9496
--parameters acrName=$acrName `
9597
--parameters acrSku=Basic `
9698
--parameters appServicePlanName=$appServicePlanName `
9799
--parameters webAppName=$webAppName `
98100
--parameters location=$location `
99101
--parameters containerImage=$containerImage `
100102
--parameters resourceGroupName=$resourceGroupName
101-
103+
102104
if ($LASTEXITCODE -ne 0) {
103105
Write-Error "Deployment failed with exit code: $LASTEXITCODE"
104106
exit $LASTEXITCODE
105107
}
106-
108+
107109
Write-Host "Deployment completed successfully!" -ForegroundColor Green
108-
110+
109111
# Set outputs for subsequent jobs
110112
echo "acr_name=$acrName" >> $env:GITHUB_OUTPUT
111113
echo "webapp_name=$webAppName" >> $env:GITHUB_OUTPUT
112114
echo "webapp_url=https://$webAppName.azurewebsites.net" >> $env:GITHUB_OUTPUT
115+
echo "resource_group=$resourceGroupName" >> $env:GITHUB_OUTPUT
113116
114117
- name: Configure ACR Managed Identity
115118
shell: pwsh
116119
run: |
117120
$webAppName = "${{ steps.deploy.outputs.webapp_name }}"
118-
$resourceGroupName = "rg-gh-aspnet-webapp-${{ env.INSTANCE_NUMBER }}"
119-
121+
$resourceGroupName = "${{ steps.deploy.outputs.resource_group }}"
122+
120123
Write-Host "Configuring ACR managed identity authentication..." -ForegroundColor Yellow
121-
124+
122125
# Verify ACR managed identity configuration
123126
$config = az webapp config show --name $webAppName --resource-group $resourceGroupName --query "acrUseManagedIdentityCreds" -o tsv
124-
127+
125128
if ($config -ne "true") {
126129
Write-Host "Setting acrUseManagedIdentityCreds=true..." -ForegroundColor Cyan
127130
az webapp config set --name $webAppName --resource-group $resourceGroupName --generic-configurations '{"acrUseManagedIdentityCreds": true}'
@@ -136,6 +139,9 @@ jobs:
136139
name: Build and Deploy to Azure Web App
137140
needs: deploy-infrastructure
138141
runs-on: ubuntu-latest
142+
env:
143+
AZURE_ACR_NAME: ${{ needs.deploy-infrastructure.outputs.acr_name }}
144+
AZURE_WEBAPP_NAME: ${{ needs.deploy-infrastructure.outputs.webapp_name }}
139145
steps:
140146
# Checkout the repo
141147
- uses: actions/checkout@v5
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
# ASP.NET Web App Blueprint
2+
3+
## Overview
4+
5+
A containerized ASP.NET web application deployed to Azure App Service using Azure Container Registry (ACR) with managed identity authentication.
6+
7+
## Architecture Components
8+
9+
| Component | Azure Service | Purpose |
10+
| --- | --- | --- |
11+
| Web Application | App Service (Linux) | Hosts the containerized ASP.NET application |
12+
| Container Registry | Azure Container Registry | Stores Docker container images |
13+
| Identity | System-Assigned Managed Identity | Secure authentication to ACR without credentials |
14+
15+
## Data Flows
16+
17+
1. Container images are pushed to Azure Container Registry
18+
2. App Service pulls container images from ACR using managed identity (AcrPull role)
19+
3. Users access the web application via HTTPS
20+
21+
## Deployment
22+
23+
### Prerequisites
24+
25+
- Azure CLI installed and authenticated
26+
- Azure subscription with appropriate permissions
27+
- PowerShell (for deployment script)
28+
29+
### Parameters
30+
31+
| Parameter | Description | Default |
32+
| --- | --- | --- |
33+
| `acrName` | Name of the Azure Container Registry | Required |
34+
| `acrSku` | SKU of the Container Registry | `Basic` |
35+
| `appServicePlanName` | Name of the App Service Plan | Required |
36+
| `webAppName` | Name of the Web App | Required |
37+
| `location` | Azure region for resources | Required |
38+
| `containerImage` | Container image to deploy | Required |
39+
| `resourceGroupName` | Name of the Resource Group | `rg-webapp01-dev` |
40+
41+
### Deploy
42+
43+
```powershell
44+
cd bicep
45+
./deploy.ps1
46+
```
47+
48+
Or deploy directly with Azure CLI:
49+
50+
```bash
51+
az deployment sub create \
52+
--location <location> \
53+
--template-file ./bicep/main.bicep \
54+
--parameters ./bicep/main.parameters.json
55+
```
56+
57+
## Security Considerations
58+
59+
- Admin user disabled on ACR; managed identity used instead
60+
- System-assigned managed identity eliminates credential storage
61+
- AcrPull role assignment follows least-privilege principle
62+
- App Service runs on Linux with container isolation
63+
64+
## Outputs
65+
66+
| Output | Description |
67+
| --- | --- |
68+
| `webAppName` | Name of the deployed Web App |
69+
| `webAppUrl` | HTTPS URL of the Web App |
70+
| `acrLoginServer` | Login server URL for the Container Registry |
71+
| `webAppPrincipalId` | Principal ID of the Web App's managed identity |

infra/deploy.ps1 renamed to blueprints/gh-aspnet-webapp/bicep/deploy.ps1

File renamed without changes.

infra/main.bicep renamed to blueprints/gh-aspnet-webapp/bicep/main.bicep

File renamed without changes.

infra/main.parameters.json renamed to blueprints/gh-aspnet-webapp/bicep/main.parameters.json

File renamed without changes.

infra/resources.bicep renamed to blueprints/gh-aspnet-webapp/bicep/resources.bicep

File renamed without changes.

0 commit comments

Comments
 (0)