Skip to content

Commit 4eaa9db

Browse files
Update blog 5.4: add IdentityServer Admin app (8 resources, 3 Web Apps)
1 parent 8fdde46 commit 4eaa9db

File tree

1 file changed

+38
-18
lines changed

1 file changed

+38
-18
lines changed

blogs/series-5-devops-data/5.4-azure-bicep-infrastructure.md

Lines changed: 38 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ Clicking through the Azure Portal to create seven resources manually is slow, er
66

77
Azure Bicep solves this. One file describes the desired state. One command creates everything. Run it again and Azure updates only what changed. The same template creates both a dev environment and a production environment identically.
88

9-
This article walks through the Bicep templates that provision the full Talent Management stack — App Service Plan, two Web Apps, a Static Web App, a shared SQL Server, and two databases — and runs the deployment against a real Azure subscription.
9+
This article walks through the Bicep templates that provision the full Talent Management stack — App Service Plan, three Web Apps, a Static Web App, a shared SQL Server, and two databases — and runs the deployment against a real Azure subscription.
1010

1111
![Azure Resources Created](https://raw.githubusercontent.com/workcontrolgit/AngularNetTutorial/master/docs/images/webapi/swagger-api-endpoints.png)
1212

@@ -25,7 +25,7 @@ This article is part of the **AngularNetTutorial** series. The full-stack tutori
2525
* **`@secure()` parameters** — how to pass SQL passwords without storing them in files
2626
* **CAF naming convention** — why resources are named `app-talent-api-dev` and not `myapp1`
2727
* **Bicep outputs** — how deployed URLs flow into GitHub Actions workflows
28-
* **`az deployment group create`** — the one command that provisions all seven resources
28+
* **`az deployment group create`** — the one command that provisions all eight resources
2929

3030
---
3131

@@ -56,7 +56,7 @@ The Azure Portal is a point-and-click interface. Every decision you make — whi
5656
* **No repeatability** — no way to recreate an environment identically
5757
* **No history** — changes to resources aren't tracked in git
5858
* **No review** — no pull request for a resource configuration change
59-
* **Slow** — creating seven resources manually takes 30+ minutes
59+
* **Slow** — creating eight resources manually takes 30+ minutes
6060

6161
---
6262

@@ -84,7 +84,7 @@ infra/
8484
├── main.bicep ← entry point, composes all modules
8585
├── modules/
8686
│ ├── appServicePlan.bicep ← B1 App Service Plan
87-
│ ├── webApp.bicep ← reusable Web App (used for API and IdentityServer)
87+
│ ├── webApp.bicep ← reusable Web App (used for API, IdentityServer STS, and Admin)
8888
│ ├── staticWebApp.bicep ← Angular client, Free tier
8989
│ └── sqlServer.bicep ← logical server + 2 databases
9090
└── parameters/
@@ -119,10 +119,29 @@ module apiApp 'modules/webApp.bicep' = {
119119
}
120120
}
121121
122-
// ... identityApp, angularSwa, sqlServer modules ...
122+
module identityApp 'modules/webApp.bicep' = {
123+
name: 'identityApp'
124+
params: {
125+
webAppName: identityAppName
126+
location: location
127+
appServicePlanId: appServicePlan.outputs.id
128+
}
129+
}
130+
131+
module identityAdminApp 'modules/webApp.bicep' = {
132+
name: 'identityAdminApp'
133+
params: {
134+
webAppName: identityAdminAppName
135+
location: location
136+
appServicePlanId: appServicePlan.outputs.id
137+
}
138+
}
139+
140+
// ... angularSwa, sqlServer modules ...
123141
124142
output apiAppUrl string = apiApp.outputs.url
125143
output identityAppUrl string = identityApp.outputs.url
144+
output identityAdminAppUrl string = identityAdminApp.outputs.url
126145
output angularAppUrl string = angularSwa.outputs.url
127146
```
128147

@@ -260,14 +279,15 @@ resource apiDatabase 'Microsoft.Sql/servers/databases@2023-05-01-preview' = {
260279
261280
using '../main.bicep'
262281
263-
param appServicePlanName = 'asp-talent-b1-dev'
264-
param apiAppName = 'app-talent-api-dev'
265-
param identityAppName = 'app-talent-ids-dev'
266-
param staticWebAppName = 'swa-talent-ui-dev'
267-
param sqlServerName = 'sql-talent-dev'
268-
param apiDbName = 'sqldb-talent-api-dev'
269-
param identityDbName = 'sqldb-talent-ids-dev'
270-
param sqlAdminLogin = 'sqladmin'
282+
param appServicePlanName = 'asp-talent-b1-dev'
283+
param apiAppName = 'app-talent-api-dev'
284+
param identityAppName = 'app-talent-ids-dev'
285+
param identityAdminAppName = 'app-talent-admin-dev'
286+
param staticWebAppName = 'swa-talent-ui-dev'
287+
param sqlServerName = 'sql-talent-dev'
288+
param apiDbName = 'sqldb-talent-api-dev'
289+
param identityDbName = 'sqldb-talent-ids-dev'
290+
param sqlAdminLogin = 'sqladmin'
271291
272292
// sqlAdminPassword is NOT here — pass it at deploy time
273293
```
@@ -292,7 +312,7 @@ az group create \
292312
--location eastus
293313
```
294314

295-
Deploy all seven resources:
315+
Deploy all eight resources:
296316

297317
```bash
298318
az deployment group create \
@@ -331,19 +351,19 @@ az resource list \
331351
--output table
332352
```
333353

334-
You should see seven resources: one App Service Plan, two Web Apps, one Static Site, one SQL Server, and two SQL Databases.
354+
You should see eight resources: one App Service Plan, three Web Apps, one Static Site, one SQL Server, and two SQL Databases.
335355

336356
Navigate to each Web App in the Portal (`portal.azure.com → App Services → app-talent-api-dev`) and confirm the URL opens — it will show a default "Your web app is running" page until the .NET application is deployed in Article 5.6.
337357

338358
---
339359

340360
## 🔑 Key Design Decisions
341361

342-
**One shared App Service Plan for both .NET apps.** Azure charges at the App Service Plan level, not per Web App. Running two Web Apps on one B1 plan costs the same as running one Web App on that plan. Separate plans would double the compute cost for no benefit at this scale.
362+
**One shared App Service Plan for all three .NET apps.** Azure charges at the App Service Plan level, not per Web App. Running three Web Apps (API, IdentityServer STS, and IdentityServer Admin) on one B1 plan costs the same as running one. Separate plans would triple the compute cost for no benefit at this scale.
343363

344364
**`@secure()` for SQL password — never in the parameters file.** Bicep's `@secure()` decorator marks a parameter as sensitive. The value is excluded from deployment logs and history. Passing it via `--parameters sqlAdminPassword="$SQL_ADMIN_PASSWORD"` at deploy time, sourced from an environment variable or GitHub Secret, ensures the password never touches source control.
345365

346-
**Bicep outputs over hardcoded URLs.** `main.bicep` outputs `apiAppUrl`, `identityAppUrl`, and `angularAppUrl`. GitHub Actions workflows read these outputs instead of hardcoding URLs — if the resource name changes, the URLs update automatically.
366+
**Bicep outputs over hardcoded URLs.** `main.bicep` outputs `apiAppUrl`, `identityAppUrl`, `identityAdminAppUrl`, and `angularAppUrl`. GitHub Actions workflows read these outputs instead of hardcoding URLs — if the resource name changes, the URLs update automatically.
347367

348368
**`skipGithubActionWorkflowGeneration: true` on Static Web App.** Azure would auto-generate a GitHub Actions file and commit it to the repository. The custom workflow in Article 5.7 handles environment variable injection that the auto-generated workflow cannot. Skipping auto-generation prevents a generated workflow from conflicting with the custom one.
349369

@@ -355,7 +375,7 @@ Navigate to each Web App in the Portal (`portal.azure.com → App Services → a
355375

356376
Infrastructure as Code is not just a DevOps practice — it is documentation. Every resource configuration, every SKU choice, every firewall rule is in source control and can be reviewed, questioned, and approved through a pull request. The Bicep files in this article are the complete specification of what is running in Azure.
357377

358-
The module pattern — one reusable `webApp.bicep` used for both the API and IdentityServer — demonstrates a core Bicep principle: parameterize what varies, fix what doesn't. Adding a third Web App to this infrastructure requires one additional module call and one additional parameter. The module itself does not change.
378+
The module pattern — one reusable `webApp.bicep` used for the API, IdentityServer STS, and IdentityServer Admin — demonstrates a core Bicep principle: parameterize what varies, fix what doesn't. Adding another Web App requires one additional module call and one additional parameter. The module itself does not change.
359379

360380
**Transferable skills:**
361381

0 commit comments

Comments
 (0)