You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: blogs/series-5-devops-data/5.5-azure-oidc-github-actions.md
+2Lines changed: 2 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -300,6 +300,8 @@ The output should include a row with `Contributor` assigned to `github-actions-t
300
300
301
301
**`SQL_ADMIN_PASSWORD` added manually.** The SQL admin password is a genuine secret — a value that must remain confidential. The three OIDC values (`AZURE_CLIENT_ID`, `AZURE_TENANT_ID`, `AZURE_SUBSCRIPTION_ID`) are not sensitive in the same way: knowing them without the federated credential is harmless. The SQL password is kept separate and typed interactively, never written to a file or echoed in a terminal.
302
302
303
+
**GitHub Secrets vs Azure Key Vault — the clear split.** `SQL_ADMIN_PASSWORD` is the only runtime-sensitive value in GitHub Secrets for this project — and it is only used once, during the Bicep infrastructure deployment (Article 5.4). It is not used by the application itself. Database connection strings, JWT signing keys, and other **application runtime secrets** are stored in Azure Key Vault (`kv-talent-dev`), not in GitHub Secrets. The deploy workflows in Articles 5.6 and 5.7 inject `@Microsoft.KeyVault(SecretUri=...)` references into App Service settings rather than raw values. The Web App's managed identity resolves those references at runtime — the actual secret never passes through GitHub Actions at all.
Copy file name to clipboardExpand all lines: blogs/series-5-devops-data/5.6-azure-deploy-dotnet-apps.md
+47-17Lines changed: 47 additions & 17 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -23,6 +23,8 @@ This article is part of the **AngularNetTutorial** series. The full-stack tutori
23
23
***`dotnet publish`** — what the publish output contains and why it differs from the build output
24
24
***`azure/webapps-deploy`** — the action that uploads and hot-swaps the deployment
25
25
***App Service settings** — how connection strings and URLs reach the running app without touching `appsettings.json`
26
+
***Key Vault references** — why connection strings go into Key Vault, not GitHub Secrets, and how `@Microsoft.KeyVault(SecretUri=...)` wires them into App Service settings
27
+
***GitHub Secrets vs Key Vault** — the split: CI/CD auth credentials in GitHub Secrets, runtime secrets in Key Vault
26
28
***Deployment order** — why IdentityServer must be deployed and running before the API
27
29
28
30
---
@@ -41,6 +43,8 @@ This article is part of the **AngularNetTutorial** series. The full-stack tutori
41
43
42
44
The .NET API and IdentityServer each need several environment-specific values at runtime: the database connection string, the URL of IdentityServer (which the API uses to validate tokens), and the URL of the API itself (which IdentityServer uses to register the audience). These values differ between local development and Azure. Hardcoding them in `appsettings.json` would commit environment-specific secrets to source control and break the principle that the same build artifact runs in every environment.
43
45
46
+
Even storing connection strings in GitHub Secrets is not production-grade — the raw value gets injected into App Service settings where it is visible in plain text in the Portal to anyone with Contributor access. The correct approach is to store secrets in **Azure Key Vault** (provisioned in Article 5.4) and reference them from App Service settings via `@Microsoft.KeyVault(SecretUri=...)`. The App Service resolves the reference at runtime using its managed identity — the actual connection string is never visible anywhere.
47
+
44
48
Manual deployment — `dotnet publish`, zip the output, upload via the Portal — is error-prone and produces no audit trail. Running it inconsistently across developers produces inconsistent results.
45
49
46
50
---
@@ -51,28 +55,33 @@ GitHub Actions workflows are triggered by pushes to specific paths. When code ch
51
55
52
56
App Service application settings are the Azure equivalent of environment variables. They override values in `appsettings.json` at runtime without touching the committed file. The same published binary runs locally (using `appsettings.json`) and in Azure (using App Service settings that override the file).
53
57
58
+
For **non-sensitive settings** (URLs, feature flags, audience names), the workflow injects plain values directly. For **secrets** (connection strings, JWT signing key), the workflow injects a `@Microsoft.KeyVault(SecretUri=...)` reference instead of the raw value. App Service resolves these references at startup using the Web App's system-assigned managed identity — the actual secret is retrieved from Key Vault and injected into the app's environment without ever appearing in the Portal or in logs. See Article 5.9 for full detail on this pattern.
59
+
54
60
---
55
61
56
62
## 🚀 How It Works
57
63
58
64
### Step 1: Add the Remaining GitHub Secrets
59
65
60
-
Articles 5.5 set up four secrets. Two workflows need several more:
66
+
Article 5.5 set up four secrets (`AZURE_CLIENT_ID`, `AZURE_TENANT_ID`, `AZURE_SUBSCRIPTION_ID`, `SQL_ADMIN_PASSWORD`). The deploy workflows need several more.
61
67
62
68
**Navigate to:** GitHub → Repository → Settings → Secrets and variables → Actions → New repository secret
63
69
64
-
**Secrets to add:**
70
+
**GitHub Secrets vs Azure Key Vault — the split:**
65
71
66
-
***`API_DB_CONNECTION_STRING`** — the Azure SQL connection string for the API database
72
+
| Secret type | Where it lives | Why |
73
+
|---|---|---|
74
+
| CI/CD auth credentials (`AZURE_*`) | GitHub Secrets | Needed by the runner to log in to Azure |
75
+
| Infrastructure deploy password (`SQL_ADMIN_PASSWORD`) | GitHub Secrets | One-time use for Bicep provisioning only |
76
+
| Runtime secrets (connection strings, JWT key) |**Azure Key Vault**| Never exposed as plain text; resolved by managed identity at runtime |
77
+
| Non-sensitive URLs and config | GitHub Secrets | Not sensitive — just convenient to store here |
***`JWT_KEY`** — the symmetric key used by the API's local JWT authentication (copy from `appsettings.json` → `JWTSettings.Key`)
85
-
***`ANGULAR_APP_URL`** — the Azure Static Web App URL (e.g. `https://mango-flower-0ced4011e.4.azurestaticapps.net`) — added to API CORS allowed origins
86
-
***`IDENTITY_ADMIN_URL`** — the IdentityServer Admin UI URL (e.g. `https://app-talent-admin-dev.azurewebsites.net`) — used by STS and Admin app configuration
93
+
***`ANGULAR_APP_URL`** — the Azure Static Web App URL
**⚠️ One-time prerequisite:** Your local Azure CLI identity needs the **Key Vault Secrets Officer** role on `kv-talent-dev` to run `az keyvault secret set`. Grant it in the Portal: **Key Vault → kv-talent-dev → Access control (IAM) → Add role assignment → Key Vault Secrets Officer → your account**.
127
+
98
128
### Step 2: Understand the Workflow File Structure
99
129
100
130
Both workflows live in `.github/workflows/` in the parent repository. They follow the same pattern:
Copy file name to clipboardExpand all lines: blogs/series-5-devops-data/5.8-azure-post-deployment-config.md
+30-20Lines changed: 30 additions & 20 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -31,7 +31,7 @@ This article is part of the **AngularNetTutorial** series. The full-stack tutori
31
31
**Before following this article, you should have:**
32
32
33
33
***Article 5.6 complete** — IdentityServer deployed at `https://app-talent-ids-dev.azurewebsites.net`
34
-
***Article 5.7 complete** — Angular deployed at the Static Web App URL (e.g., `https://agreeable-desert-01234567.azurestaticapps.net`)
34
+
***Article 5.7 complete** — Angular deployed at the Static Web App URL (e.g., `https://mango-flower-0ced4011e.4.azurestaticapps.net`)
35
35
***The three Azure URLs** — retrieve them:
36
36
37
37
```bash
@@ -58,7 +58,7 @@ az staticwebapp show \
58
58
59
59
## 🎯 The Problem
60
60
61
-
OAuth 2.0 authorization codes and tokens can only flow to URLs that are explicitly registered in the authorization server (IdentityServer). If the Angular application running at `https://agreeable-desert-01234567.azurestaticapps.net` sends an authorization request asking IdentityServer to redirect the browser back to that URL, IdentityServer checks its registered `RedirectUris` for the `TalentManagement` client. If the production URL isn't there, IdentityServer rejects the request immediately with `invalid_redirect_uri`.
61
+
OAuth 2.0 authorization codes and tokens can only flow to URLs that are explicitly registered in the authorization server (IdentityServer). If the Angular application running at `https://mango-flower-0ced4011e.4.azurestaticapps.net` sends an authorization request asking IdentityServer to redirect the browser back to that URL, IdentityServer checks its registered `RedirectUris` for the `TalentManagement` client. If the production URL isn't there, IdentityServer rejects the request immediately with `invalid_redirect_uri`.
62
62
63
63
Similarly, the API's CORS policy controls which origins can call the API from a browser. If the Angular app's domain is not in the allowed origins list, the browser blocks the API response before Angular can read it — even though the API returned HTTP 200.
64
64
@@ -68,6 +68,8 @@ These two configurations — IdentityServer redirect URIs and API CORS origins
68
68
69
69
## 💡 The Solution
70
70
71
+
**Note on connection strings:** Database connection strings were stored in Azure Key Vault in Article 5.4 and wired into App Service settings as `@Microsoft.KeyVault(...)` references by the deploy workflows in Article 5.6. No `appsettings.json` changes are needed for connection strings — this article focuses only on IdentityServer redirect URIs and API CORS origins, which are URLs (not secrets) and are set by the deploy workflows as plain values.
72
+
71
73
Add the production Static Web App URL to three lists in `identityserverdata.json` (the file that seeds IdentityServer's database):
72
74
73
75
*`RedirectUris` — where IdentityServer may send authorization codes after login
@@ -123,7 +125,7 @@ Open `TokenService/Duende-IdentityServer/shared/identityserverdata.json`. Find t
123
125
}
124
126
```
125
127
126
-
Add the production Azure URLs to each list. Replace `https://agreeable-desert-01234567.azurestaticapps.net` with your actual Static Web App URL:
128
+
Add the production Azure URLs to each list. Replace `https://mango-flower-0ced4011e.4.azurestaticapps.net` with your actual Static Web App URL:
127
129
128
130
```json
129
131
{
@@ -136,19 +138,24 @@ Add the production Azure URLs to each list. Replace `https://agreeable-desert-01
Add the Static Web App URL to the allowed origins, then push the change or set it as an App Service setting:
180
+
The API allows CORS origins configured via App Service settings using the `Cors__AllowedOrigins__` array pattern. Two origins are needed — the Azure Static Web App and GitHub Pages:
The API middleware reads this setting at startup and adds the origin to the allowed list.
191
+
**Note:** Replace `https://mango-flower-0ced4011e.4.azurestaticapps.net` with your actual Static Web App URL. The GitHub Pages origin is the host only — no path suffix. This is handled automatically by the `deploy-api.yml` workflow on every deployment, so this manual step is only needed if you are configuring the API outside of a workflow run.
192
+
193
+
The API's CORS middleware reads `Cors:AllowedOrigins` from `IConfiguration` at startup. The `__` double-underscore in the setting name maps to the `:` separator, and the `__0` / `__1` suffixes create an array in .NET configuration.
190
194
191
195
### Step 5: Validate Each Layer in Order
192
196
@@ -240,12 +244,18 @@ After completing Steps 1–4, run through the Layer 1–6 validation in order. E
240
244
**Quick CORS verification from the browser console:**
0 commit comments