Skip to content

Commit b0377e3

Browse files
committed
convert to key vault secrets
1 parent c600a37 commit b0377e3

File tree

3 files changed

+49
-15
lines changed

3 files changed

+49
-15
lines changed

README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,12 @@ Because the Linux .NET container in App Service doesn't come with the .NET SDK,
7777
- In the [.csproj](DotNretCoreSqlDb.csproj) file, include the generated *migrationsbundle* file. During the `azd package` stage, *migrationsbundle* will be added to the deploy package.
7878
- In [infra/resources.bicep](infra/resources.bicep), add the `appCommandLine` property to the web app to run the uploaded *migrationsbundle*.
7979

80+
## How does the AZD template configure passwords?
81+
82+
Two types of secrets are involved: the SQL Database administrator password and the access key for Cache for Redis, and they are both present in the respective connection strings. The [AZD template](infra/resources.bicep) in this repo manages both connection strings in a key vault that's secured behind a private endpoint.
83+
84+
To simplify the scenario, the AZD template generates a new database password each time you run `azd provision` or `azd up`, and the database connection string in the key vault is modified too. If you want to fully utilize `secretOrRandomPassword` in the [parameter file](infra/main.parameters.json) by committing the automatically generated password to the key vault the first time and reading it on subsequent `azd` commands, you must relax the networking restriction of the key vault to allow traffic from public networks. For more information, see [What is the behavior of the `secretOrRandomPassword` function?](https://learn.microsoft.com/azure/developer/azure-developer-cli/faq#what-is-the-behavior-of-the--secretorrandompassword--function).
85+
8086
## Getting help
8187
8288
If you're working with this project and running into issues, please post in [Issues](/issues).

infra/main.bicep

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@ param name string
99
@description('Primary location for all resources')
1010
param location string
1111

12+
@secure()
13+
@description('SQL Server administrator password')
14+
param databasePassword string = ''
15+
1216
param principalId string = ''
1317

1418
var resourceToken = toLower(uniqueString(subscription().id, name, location))
@@ -26,6 +30,7 @@ module resources 'resources.bicep' = {
2630
name: name
2731
location: location
2832
resourceToken: resourceToken
33+
databasePassword: databasePassword
2934
principalId: principalId
3035
}
3136
}

infra/resources.bicep

Lines changed: 38 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ param name string
22
param location string
33
param resourceToken string
44
param principalId string
5+
@secure()
6+
param databasePassword string
57

68
var appName = '${name}-${resourceToken}'
79

@@ -211,34 +213,47 @@ resource privateDnsZoneCache 'Microsoft.Network/privateDnsZones@2020-06-01' = {
211213
}
212214
}
213215

214-
// The Key Vault is used to manage Redis secrets.
216+
// The Key Vault is used to manage SQL database and redis secrets.
217+
// Current user has the admin permissions to configure key vault secrets, but by default doesn't have the permissions to read them.
215218
resource keyVault 'Microsoft.KeyVault/vaults@2022-07-01' = {
216219
name: '${take(replace(appName, '-', ''), 17)}-vault'
217220
location: location
218221
properties: {
219222
enableRbacAuthorization: true
220223
tenantId: subscription().tenantId
221224
sku: { family: 'A', name: 'standard' }
222-
publicNetworkAccess: 'Disabled'
225+
// Only allow requests from the private endpoint in the VNET.
226+
publicNetworkAccess: 'Disabled' // To see the secret in the portal, change to 'Enabled'
223227
networkAcls: {
224-
defaultAction: 'Deny'
225-
bypass: 'AzureServices'
226-
ipRules: []
227-
virtualNetworkRules: []
228+
defaultAction: 'Deny' // To see the secret in the portal, change to 'Allow'
229+
bypass: 'None'
228230
}
229231
}
230232
}
231233

234+
// Grant the current user with key vault secret user role permissions over the key vault. This lets you inspect the secrets, such as in the portal
235+
// If you remove this section, you can't read the key vault secrets, but the app still has access with its managed identity.
236+
resource keyVaultSecretUserRoleRoleDefinition 'Microsoft.Authorization/roleDefinitions@2018-01-01-preview' existing = {
237+
scope: subscription()
238+
name: '4633458b-17de-408a-b874-0445c86b69e6' // The built-in Key Vault Secret User role
239+
}
240+
resource keyVaultSecretUserRoleAssignment 'Microsoft.Authorization/roleAssignments@2020-08-01-preview' = {
241+
scope: keyVault
242+
name: guid(resourceGroup().id, principalId, keyVaultSecretUserRoleRoleDefinition.id)
243+
properties: {
244+
roleDefinitionId: keyVaultSecretUserRoleRoleDefinition.id
245+
principalId: principalId
246+
principalType: 'User'
247+
}
248+
}
249+
232250
// The SQL Database server is configured to be the minimum pricing tier
233-
// It also uses Microsoft Entra authentication with the current user as the administrator
234251
resource dbserver 'Microsoft.Sql/servers@2023-05-01-preview' = {
235252
location: location
236253
name: '${appName}-server'
237254
properties: {
238-
administrators: {
239-
login: '${appName}-server-admin'
240-
sid: principalId
241-
}
255+
administratorLogin: '${appName}-server-admin'
256+
administratorLoginPassword: databasePassword
242257
publicNetworkAccess: 'Disabled'
243258
restrictOutboundNetworkAccess: 'Disabled'
244259
}
@@ -319,7 +334,7 @@ resource web 'Microsoft.Web/sites@2022-09-01' = {
319334
properties: {
320335
applicationLogs: {
321336
fileSystem: {
322-
level: 'Verbose'
337+
level: 'Information'
323338
}
324339
}
325340
detailedErrorMessages: {
@@ -356,7 +371,7 @@ resource vaultConnector 'Microsoft.ServiceLinker/linkers@2024-04-01' = {
356371
scope: web
357372
name: 'vaultConnector'
358373
properties: {
359-
clientType: 'springBoot'
374+
clientType: 'dotnet'
360375
targetService: {
361376
type: 'AzureResource'
362377
id: keyVault.id
@@ -383,7 +398,15 @@ resource dbConnector 'Microsoft.ServiceLinker/linkers@2024-04-01' = {
383398
id: dbserver::db.id
384399
}
385400
authInfo: {
386-
authType: 'systemAssignedIdentity'
401+
authType: 'secret'
402+
name: '${appName}-server-admin'
403+
secretInfo: {
404+
secretType: 'rawValue'
405+
value: databasePassword
406+
}
407+
}
408+
secretStore: {
409+
keyVaultId: keyVault.id // Configure secrets as key vault references. No secret is exposed in App Service.
387410
}
388411
clientType: 'dotnet-connectionString' // Generate a .NET connection string. For app setting, use 'dotnet' instead
389412
vNetSolution: {
@@ -403,7 +426,7 @@ resource cacheConnector 'Microsoft.ServiceLinker/linkers@2024-04-01' = {
403426
id: resourceId('Microsoft.Cache/Redis/Databases', redisCache.name, '0')
404427
}
405428
authInfo: {
406-
authType: 'accessKey' // Configure secrets as Key Vault references. No secret is exposed in App Service.
429+
authType: 'accessKey' // Configure secrets as key vault references. No secret is exposed in App Service.
407430
}
408431
secretStore: {
409432
keyVaultId: keyVault.id

0 commit comments

Comments
 (0)