Skip to content

Commit 3658b07

Browse files
Merge pull request #13 from workcontrolgit/develop
Update blog 5.6: complete App Service settings reference and workflow fixes
2 parents c1984fd + 4f8a5e6 commit 3658b07

File tree

3 files changed

+100
-26
lines changed

3 files changed

+100
-26
lines changed

.github/workflows/deploy-api.yml

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -62,20 +62,19 @@ jobs:
6262

6363
- name: Configure App Service settings
6464
env:
65-
API_CONN: ${{ secrets.API_DB_CONNECTION_STRING }}
6665
IDS_URL: ${{ secrets.IDENTITY_SERVER_URL }}
67-
JWT_KEY: ${{ secrets.JWT_KEY }}
6866
ANGULAR_URL: ${{ secrets.ANGULAR_APP_URL }}
67+
KV_URI: ${{ secrets.KEY_VAULT_URI }}
6968
run: |
7069
az webapp config appsettings set \
7170
--resource-group ${{ env.RESOURCE_GROUP }} \
7271
--name ${{ env.APP_SERVICE_NAME }} \
7372
--settings \
74-
"ConnectionStrings__DefaultConnection=$API_CONN" \
73+
"ConnectionStrings__DefaultConnection=@Microsoft.KeyVault(SecretUri=${KV_URI}secrets/ConnectionStrings--DefaultConnection)" \
74+
"JWTSettings__Key=@Microsoft.KeyVault(SecretUri=${KV_URI}secrets/JWTSettings--Key)" \
7575
"Sts__ServerUrl=$IDS_URL" \
7676
"Sts__ValidIssuer=$IDS_URL" \
7777
"Sts__Audience=app.api.talentmanagement" \
78-
"JWTSettings__Key=$JWT_KEY" \
7978
"JWTSettings__Issuer=CoreIdentity" \
8079
"JWTSettings__Audience=CoreIdentityUser" \
8180
"JWTSettings__DurationInMinutes=60" \

.github/workflows/deploy-identityserver.yml

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -72,18 +72,18 @@ jobs:
7272

7373
- name: Configure STS App Service settings
7474
env:
75-
IDS_CONN: ${{ secrets.IDS_DB_CONNECTION_STRING }}
7675
IDS_URL: ${{ secrets.IDENTITY_SERVER_URL }}
7776
ADMIN_URL: ${{ secrets.IDENTITY_ADMIN_URL }}
77+
KV_URI: ${{ secrets.KEY_VAULT_URI }}
7878
run: |
7979
az webapp config appsettings set \
8080
--resource-group ${{ env.RESOURCE_GROUP }} \
8181
--name ${{ env.APP_SERVICE_NAME }} \
8282
--settings \
83-
"ConnectionStrings__ConfigurationDbConnection=$IDS_CONN" \
84-
"ConnectionStrings__PersistedGrantDbConnection=$IDS_CONN" \
85-
"ConnectionStrings__IdentityDbConnection=$IDS_CONN" \
86-
"ConnectionStrings__DataProtectionDbConnection=$IDS_CONN" \
83+
"ConnectionStrings__ConfigurationDbConnection=@Microsoft.KeyVault(SecretUri=${KV_URI}secrets/ConnectionStrings--IdsDbConnection)" \
84+
"ConnectionStrings__PersistedGrantDbConnection=@Microsoft.KeyVault(SecretUri=${KV_URI}secrets/ConnectionStrings--IdsDbConnection)" \
85+
"ConnectionStrings__IdentityDbConnection=@Microsoft.KeyVault(SecretUri=${KV_URI}secrets/ConnectionStrings--IdsDbConnection)" \
86+
"ConnectionStrings__DataProtectionDbConnection=@Microsoft.KeyVault(SecretUri=${KV_URI}secrets/ConnectionStrings--IdsDbConnection)" \
8787
"AdminConfiguration__IdentityServerBaseUrl=$IDS_URL" \
8888
"AdminConfiguration__IdentityAdminBaseUrl=$ADMIN_URL" \
8989
"CspTrustedDomains__0=www.gravatar.com" \
@@ -95,20 +95,20 @@ jobs:
9595
9696
- name: Configure Admin App Service settings
9797
env:
98-
IDS_CONN: ${{ secrets.IDS_DB_CONNECTION_STRING }}
9998
IDS_URL: ${{ secrets.IDENTITY_SERVER_URL }}
10099
ADMIN_URL: ${{ secrets.IDENTITY_ADMIN_URL }}
100+
KV_URI: ${{ secrets.KEY_VAULT_URI }}
101101
run: |
102102
az webapp config appsettings set \
103103
--resource-group ${{ env.RESOURCE_GROUP }} \
104104
--name ${{ env.ADMIN_APP_SERVICE_NAME }} \
105105
--settings \
106-
"ConnectionStrings__ConfigurationDbConnection=$IDS_CONN" \
107-
"ConnectionStrings__PersistedGrantDbConnection=$IDS_CONN" \
108-
"ConnectionStrings__IdentityDbConnection=$IDS_CONN" \
109-
"ConnectionStrings__AdminLogDbConnection=$IDS_CONN" \
110-
"ConnectionStrings__AdminAuditLogDbConnection=$IDS_CONN" \
111-
"ConnectionStrings__DataProtectionDbConnection=$IDS_CONN" \
106+
"ConnectionStrings__ConfigurationDbConnection=@Microsoft.KeyVault(SecretUri=${KV_URI}secrets/ConnectionStrings--IdsDbConnection)" \
107+
"ConnectionStrings__PersistedGrantDbConnection=@Microsoft.KeyVault(SecretUri=${KV_URI}secrets/ConnectionStrings--IdsDbConnection)" \
108+
"ConnectionStrings__IdentityDbConnection=@Microsoft.KeyVault(SecretUri=${KV_URI}secrets/ConnectionStrings--IdsDbConnection)" \
109+
"ConnectionStrings__AdminLogDbConnection=@Microsoft.KeyVault(SecretUri=${KV_URI}secrets/ConnectionStrings--IdsDbConnection)" \
110+
"ConnectionStrings__AdminAuditLogDbConnection=@Microsoft.KeyVault(SecretUri=${KV_URI}secrets/ConnectionStrings--IdsDbConnection)" \
111+
"ConnectionStrings__DataProtectionDbConnection=@Microsoft.KeyVault(SecretUri=${KV_URI}secrets/ConnectionStrings--IdsDbConnection)" \
112112
"AdminConfiguration__IdentityServerBaseUrl=$IDS_URL" \
113113
"AdminConfiguration__IdentityAdminRedirectUri=$ADMIN_URL/signin-oidc" \
114114
"SeedConfiguration__ApplySeed=false" \

blogs/series-5-devops-data/5.6-azure-deploy-dotnet-apps.md

Lines changed: 85 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,8 @@ https://app-talent-ids-dev.azurewebsites.net
8282
```
8383

8484
* **`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
8587

8688
**Retrieve the connection strings from the Bicep outputs:**
8789

@@ -190,23 +192,86 @@ This is the OIDC exchange described in Article 5.5. After this step, all subsequ
190192

191193
```yaml
192194
- name: Configure App Service settings
195+
env:
196+
API_CONN: ${{ secrets.API_DB_CONNECTION_STRING }}
197+
IDS_URL: ${{ secrets.IDENTITY_SERVER_URL }}
198+
JWT_KEY: ${{ secrets.JWT_KEY }}
199+
ANGULAR_URL: ${{ secrets.ANGULAR_APP_URL }}
193200
run: |
194201
az webapp config appsettings set \
195202
--resource-group ${{ env.RESOURCE_GROUP }} \
196203
--name ${{ env.APP_SERVICE_NAME }} \
197204
--settings \
198-
"ConnectionStrings__DefaultConnection=${{ secrets.API_DB_CONNECTION_STRING }}" \
199-
"Sts__ServerUrl=${{ secrets.IDENTITY_SERVER_URL }}" \
200-
"Sts__ValidIssuer=${{ secrets.IDENTITY_SERVER_URL }}" \
205+
"ConnectionStrings__DefaultConnection=$API_CONN" \
206+
"Sts__ServerUrl=$IDS_URL" \
207+
"Sts__ValidIssuer=$IDS_URL" \
201208
"Sts__Audience=app.api.talentmanagement" \
202-
"JWTSettings__Key=${{ secrets.JWT_KEY }}" \
209+
"JWTSettings__Key=$JWT_KEY" \
210+
"JWTSettings__Issuer=CoreIdentity" \
211+
"JWTSettings__Audience=CoreIdentityUser" \
212+
"JWTSettings__DurationInMinutes=60" \
213+
"FeatureManagement__AuthEnabled=true" \
214+
"Cors__AllowedOrigins__0=$ANGULAR_URL" \
215+
"Cors__AllowedOrigins__1=https://workcontrolgit.github.io" \
203216
"ASPNETCORE_ENVIRONMENT=Production"
204217
```
205218

219+
**Why `env:` block instead of `${{ secrets.X }}` inline?** Bash strips characters after `$` followed by a digit — a password like `Abc$9xyz` becomes `Abcxyz` when interpolated inline in a shell script. Mapping secrets to environment variables in the `env:` block and referencing them as `$API_CONN` avoids this. Always use `env:` when passing secrets into shell commands.
220+
206221
App Service uses double underscores (`__`) to represent the `:` separator in .NET configuration keys. `ConnectionStrings__DefaultConnection` maps to `ConnectionStrings:DefaultConnection` in the .NET configuration system, which in turn maps to `appsettings.json`'s `ConnectionStrings.DefaultConnection`. This is the standard pattern for hierarchical configuration in Azure App Service.
207222

208223
`ASPNETCORE_ENVIRONMENT=Production` causes ASP.NET Core to merge `appsettings.Production.json` (if it exists) on top of `appsettings.json`, then apply App Service settings on top of that. App Service settings always win — they cannot be overridden by a file in the deployment package.
209224

225+
### Complete App Service Settings Reference
226+
227+
All settings injected by the GitHub Actions workflows, cross-referenced against the live Azure environment.
228+
229+
**API App (`app-talent-api-dev`):**
230+
231+
* **`ConnectionStrings__DefaultConnection`** — Azure SQL connection string for the API database — source: `API_DB_CONNECTION_STRING` GitHub Secret
232+
* **`Sts__ServerUrl`** — IdentityServer URL used to fetch the OIDC discovery document — source: `IDENTITY_SERVER_URL` Secret
233+
* **`Sts__ValidIssuer`** — Expected `iss` claim in incoming JWT tokens — source: `IDENTITY_SERVER_URL` Secret
234+
* **`Sts__Audience`** — Expected `aud` claim — hardcoded: `app.api.talentmanagement`
235+
* **`JWTSettings__Key`** — Symmetric signing key for the API's own JWT issuance — source: `JWT_KEY` Secret
236+
* **`JWTSettings__Issuer`** — Issuer name in API-issued tokens — hardcoded: `CoreIdentity`
237+
* **`JWTSettings__Audience`** — Audience in API-issued tokens — hardcoded: `CoreIdentityUser`
238+
* **`JWTSettings__DurationInMinutes`** — Token lifetime — hardcoded: `60`
239+
* **`FeatureManagement__AuthEnabled`** — Enables JWT authentication globally — hardcoded: `true`
240+
* **`Cors__AllowedOrigins__0`** — Azure SWA URL — source: `ANGULAR_APP_URL` Secret
241+
* **`Cors__AllowedOrigins__1`** — GitHub Pages URL — hardcoded: `https://workcontrolgit.github.io`
242+
* **`ASPNETCORE_ENVIRONMENT`** — Runtime environment — hardcoded: `Production`
243+
244+
**IdentityServer STS (`app-talent-ids-dev`):**
245+
246+
* **`ConnectionStrings__ConfigurationDbConnection`** — Clients, scopes, resources — source: `IDS_DB_CONNECTION_STRING` Secret
247+
* **`ConnectionStrings__PersistedGrantDbConnection`** — Tokens, sessions, grants — source: `IDS_DB_CONNECTION_STRING` Secret
248+
* **`ConnectionStrings__IdentityDbConnection`** — User accounts (ASP.NET Identity) — source: `IDS_DB_CONNECTION_STRING` Secret
249+
* **`ConnectionStrings__DataProtectionDbConnection`** — ASP.NET Data Protection keys — source: `IDS_DB_CONNECTION_STRING` Secret
250+
* **`AdminConfiguration__IdentityServerBaseUrl`** — STS own public URL (used by Admin) — source: `IDENTITY_SERVER_URL` Secret
251+
* **`AdminConfiguration__IdentityAdminBaseUrl`** — Admin UI URL (used for back-channel links) — source: `IDENTITY_ADMIN_URL` Secret
252+
* **`CspTrustedDomains__0`** — hardcoded: `www.gravatar.com` (user avatars)
253+
* **`CspTrustedDomains__1`** — hardcoded: `fonts.googleapis.com`
254+
* **`CspTrustedDomains__2`** — hardcoded: `fonts.gstatic.com`
255+
* **`CspTrustedDomains__3`** — hardcoded: `workcontrolgit.github.io` (GitHub Pages Angular)
256+
* **`CspTrustedDomains__4`** — hardcoded: `mango-flower-0ced4011e.4.azurestaticapps.net` (Azure SWA Angular)
257+
* **`ASPNETCORE_ENVIRONMENT`** — hardcoded: `Production`
258+
259+
**IdentityServer Admin (`app-talent-admin-dev`):**
260+
261+
* **`ConnectionStrings__ConfigurationDbConnection`** — source: `IDS_DB_CONNECTION_STRING` Secret
262+
* **`ConnectionStrings__PersistedGrantDbConnection`** — source: `IDS_DB_CONNECTION_STRING` Secret
263+
* **`ConnectionStrings__IdentityDbConnection`** — source: `IDS_DB_CONNECTION_STRING` Secret
264+
* **`ConnectionStrings__AdminLogDbConnection`** — Admin action logs — source: `IDS_DB_CONNECTION_STRING` Secret
265+
* **`ConnectionStrings__AdminAuditLogDbConnection`** — Audit trail — source: `IDS_DB_CONNECTION_STRING` Secret
266+
* **`ConnectionStrings__DataProtectionDbConnection`** — source: `IDS_DB_CONNECTION_STRING` Secret
267+
* **`AdminConfiguration__IdentityServerBaseUrl`** — STS URL for Admin to authenticate against — source: `IDENTITY_SERVER_URL` Secret
268+
* **`AdminConfiguration__IdentityAdminRedirectUri`** — OIDC callback URL for the Admin UI — source: `IDENTITY_ADMIN_URL` Secret + `/signin-oidc`
269+
* **`SeedConfiguration__ApplySeed`** — Prevents re-seeding on every deploy — hardcoded: `false`
270+
* **`DatabaseMigrationsConfiguration__ApplyDatabaseMigrations`** — Prevents auto-migration on deploy — hardcoded: `false`
271+
* **`ASPNETCORE_ENVIRONMENT`** — hardcoded: `Production`
272+
273+
**⚠️ Stale settings to be aware of:** Running `az webapp config appsettings list` against the live apps may show additional settings not managed by the workflow — for example `CorsOrigins` (an older duplicate of `Cors__AllowedOrigins__0`) or `ASPNETCORE_DETAILEDERRORS` set manually during debugging. Settings set outside the workflow are not removed by subsequent workflow runs — only values for keys the workflow explicitly sets are updated. Remove stale settings manually via the Portal or `az webapp config appsettings delete`.
274+
210275
**Deploy:**
211276

212277
```yaml
@@ -233,16 +298,26 @@ paths:
233298

234299
IdentityServer changes trigger this workflow; API changes do not.
235300

236-
**App Service settings for IdentityServer:**
301+
**App Service settings for IdentityServer STS (using `env:` block):**
237302

238303
```yaml
239-
"ConnectionStrings__ConfigurationDbConnection=${{ secrets.IDS_DB_CONNECTION_STRING }}"
240-
"ConnectionStrings__PersistedGrantDbConnection=${{ secrets.IDS_DB_CONNECTION_STRING }}"
241-
"ConnectionStrings__IdentityDbConnection=${{ secrets.IDS_DB_CONNECTION_STRING }}"
242-
"AdminConfiguration__IdentityServerBaseUrl=${{ secrets.IDENTITY_SERVER_URL }}"
304+
- name: Configure STS App Service settings
305+
env:
306+
IDS_CONN: ${{ secrets.IDS_DB_CONNECTION_STRING }}
307+
IDS_URL: ${{ secrets.IDENTITY_SERVER_URL }}
308+
ADMIN_URL: ${{ secrets.IDENTITY_ADMIN_URL }}
309+
run: |
310+
az webapp config appsettings set \
311+
--settings \
312+
"ConnectionStrings__ConfigurationDbConnection=$IDS_CONN" \
313+
"ConnectionStrings__PersistedGrantDbConnection=$IDS_CONN" \
314+
"ConnectionStrings__IdentityDbConnection=$IDS_CONN" \
315+
"ConnectionStrings__DataProtectionDbConnection=$IDS_CONN" \
316+
"AdminConfiguration__IdentityServerBaseUrl=$IDS_URL" \
317+
"AdminConfiguration__IdentityAdminBaseUrl=$ADMIN_URL"
243318
```
244319

245-
IdentityServer uses three different connection string keys — `ConfigurationDbConnection` (clients, scopes), `PersistedGrantDbConnection` (tokens, sessions), and `IdentityDbConnection` (user accounts). All three point to the same Azure SQL database (`sqldb-talent-ids-dev`) in this tutorial. In production, separating them is common.
320+
IdentityServer uses four different connection string keys — `ConfigurationDbConnection` (clients, scopes), `PersistedGrantDbConnection` (tokens, sessions), `IdentityDbConnection` (user accounts), and `DataProtectionDbConnection` (ASP.NET Data Protection keys). All four point to the same Azure SQL database (`sqldb-talent-ids-dev`) in this tutorial. In production, separating them onto dedicated databases is common. The same `$IDS_CONN` value is reused for all four — the `env:` block means the secret is only referenced once.
246321

247322
### Step 5: Deployment Order
248323

0 commit comments

Comments
 (0)