diff --git a/avm/res/sql/server/README.md b/avm/res/sql/server/README.md index e38347c937..92be8ea923 100644 --- a/avm/res/sql/server/README.md +++ b/avm/res/sql/server/README.md @@ -19,6 +19,7 @@ This module deploys an Azure SQL Server. | `Microsoft.Authorization/locks` | [2020-05-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2020-05-01/locks) | | `Microsoft.Authorization/roleAssignments` | [2022-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2022-04-01/roleAssignments) | | `Microsoft.Insights/diagnosticSettings` | [2021-05-01-preview](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Insights/2021-05-01-preview/diagnosticSettings) | +| `Microsoft.KeyVault/vaults/secrets` | [2023-07-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.KeyVault/2023-07-01/vaults/secrets) | | `Microsoft.Network/privateEndpoints` | [2023-11-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-11-01/privateEndpoints) | | `Microsoft.Network/privateEndpoints/privateDnsZoneGroups` | [2023-11-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-11-01/privateEndpoints/privateDnsZoneGroups) | | `Microsoft.Sql/servers` | [2023-08-01-preview](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Sql/servers) | @@ -45,10 +46,11 @@ The following section provides usage examples for the module, which were used to - [With an administrator](#example-1-with-an-administrator) - [With audit settings](#example-2-with-audit-settings) - [Using only defaults](#example-3-using-only-defaults) -- [Using large parameter set](#example-4-using-large-parameter-set) -- [With a secondary database](#example-5-with-a-secondary-database) -- [With vulnerability assessment](#example-6-with-vulnerability-assessment) -- [WAF-aligned](#example-7-waf-aligned) +- [Deploying with a key vault reference to save secrets](#example-4-deploying-with-a-key-vault-reference-to-save-secrets) +- [Using large parameter set](#example-5-using-large-parameter-set) +- [With a secondary database](#example-6-with-a-secondary-database) +- [With vulnerability assessment](#example-7-with-vulnerability-assessment) +- [WAF-aligned](#example-8-waf-aligned) ### Example 1: _With an administrator_ @@ -310,7 +312,115 @@ param location = ''

-### Example 4: _Using large parameter set_ +### Example 4: _Deploying with a key vault reference to save secrets_ + +This instance deploys the module saving all its secrets in a key vault. + + +

+ +via Bicep module + +```bicep +module server 'br/public:avm/res/sql/server:' = { + name: 'serverDeployment' + params: { + // Required parameters + name: 'sqlkvs001' + // Non-required parameters + administratorLogin: 'adminUserName' + administratorLoginPassword: '' + databases: [ + { + name: 'myDatabase' + } + ] + location: '' + secretsExportConfiguration: { + keyVaultResourceId: '' + sqlAdminPasswordSecretName: 'adminLoginPasswordKey' + sqlAzureConnectionStringSercretName: 'sqlConnectionStringKey' + } + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "sqlkvs001" + }, + // Non-required parameters + "administratorLogin": { + "value": "adminUserName" + }, + "administratorLoginPassword": { + "value": "" + }, + "databases": { + "value": [ + { + "name": "myDatabase" + } + ] + }, + "location": { + "value": "" + }, + "secretsExportConfiguration": { + "value": { + "keyVaultResourceId": "", + "sqlAdminPasswordSecretName": "adminLoginPasswordKey", + "sqlAzureConnectionStringSercretName": "sqlConnectionStringKey" + } + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/sql/server:' + +// Required parameters +param name = 'sqlkvs001' +// Non-required parameters +param administratorLogin = 'adminUserName' +param administratorLoginPassword = '' +param databases = [ + { + name: 'myDatabase' + } +] +param location = '' +param secretsExportConfiguration = { + keyVaultResourceId: '' + sqlAdminPasswordSecretName: 'adminLoginPasswordKey' + sqlAzureConnectionStringSercretName: 'sqlConnectionStringKey' +} +``` + +
+

+ +### Example 5: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -833,7 +943,7 @@ param vulnerabilityAssessmentsObj = {

-### Example 5: _With a secondary database_ +### Example 6: _With a secondary database_ This instance deploys the module with a secondary database. @@ -956,7 +1066,7 @@ param tags = {

-### Example 6: _With vulnerability assessment_ +### Example 7: _With vulnerability assessment_ This instance deploys the module with a vulnerability assessment. @@ -1133,7 +1243,7 @@ param vulnerabilityAssessmentsObj = {

-### Example 7: _WAF-aligned_ +### Example 8: _WAF-aligned_ This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. @@ -1579,6 +1689,7 @@ param vulnerabilityAssessmentsObj = { | [`publicNetworkAccess`](#parameter-publicnetworkaccess) | string | Whether or not public network access is allowed for this resource. For security reasons it should be disabled. If not specified, it will be disabled by default if private endpoints are set and neither firewall rules nor virtual network rules are set. | | [`restrictOutboundNetworkAccess`](#parameter-restrictoutboundnetworkaccess) | string | Whether or not to restrict outbound network access for this server. | | [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | +| [`secretsExportConfiguration`](#parameter-secretsexportconfiguration) | object | Key vault reference and secret settings for the module's secrets export. | | [`securityAlertPolicies`](#parameter-securityalertpolicies) | array | The security alert policies to create in the server. | | [`tags`](#parameter-tags) | object | Tags of the resource. | | [`virtualNetworkRules`](#parameter-virtualnetworkrules) | array | The virtual network rules to create in the server. | @@ -2411,6 +2522,47 @@ The principal type of the assigned principal ID. ] ``` +### Parameter: `secretsExportConfiguration` + +Key vault reference and secret settings for the module's secrets export. + +- Required: No +- Type: object + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`keyVaultResourceId`](#parameter-secretsexportconfigurationkeyvaultresourceid) | string | The resource ID of the key vault where to store the secrets of this module. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`sqlAdminPasswordSecretName`](#parameter-secretsexportconfigurationsqladminpasswordsecretname) | string | The sqlAdminPassword secret name to create. | +| [`sqlAzureConnectionStringSercretName`](#parameter-secretsexportconfigurationsqlazureconnectionstringsercretname) | string | The sqlAzureConnectionString secret name to create. | + +### Parameter: `secretsExportConfiguration.keyVaultResourceId` + +The resource ID of the key vault where to store the secrets of this module. + +- Required: Yes +- Type: string + +### Parameter: `secretsExportConfiguration.sqlAdminPasswordSecretName` + +The sqlAdminPassword secret name to create. + +- Required: No +- Type: string + +### Parameter: `secretsExportConfiguration.sqlAzureConnectionStringSercretName` + +The sqlAzureConnectionString secret name to create. + +- Required: No +- Type: string + ### Parameter: `securityAlertPolicies` The security alert policies to create in the server. @@ -2446,6 +2598,7 @@ The vulnerability assessment configuration. | Output | Type | Description | | :-- | :-- | :-- | +| `exportedSecrets` | | A hashtable of references to the secrets exported to the provided Key Vault. The key of each reference is each secret's name. | | `location` | string | The location the resource was deployed into. | | `name` | string | The name of the deployed SQL server. | | `privateEndpoints` | array | The private endpoints of the SQL server. | diff --git a/avm/res/sql/server/main.bicep b/avm/res/sql/server/main.bicep index e628668146..6a3921b4eb 100644 --- a/avm/res/sql/server/main.bicep +++ b/avm/res/sql/server/main.bicep @@ -105,6 +105,9 @@ param vulnerabilityAssessmentsObj object = {} @description('Optional. The audit settings configuration.') param auditSettings auditSettingsType? +@description('Optional. Key vault reference and secret settings for the module\'s secrets export.') +param secretsExportConfiguration secretsExportConfigurationType? + var builtInRoleNames = { Contributor: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c') Owner: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635') @@ -491,6 +494,36 @@ module server_audit_settings 'audit-settings/main.bicep' = if (!empty(auditSetti } } +module secretsExport 'modules/keyVaultExport.bicep' = if (secretsExportConfiguration != null) { + name: '${uniqueString(deployment().name, location)}-secrets-kv' + scope: resourceGroup( + split((secretsExportConfiguration.?keyVaultResourceId ?? '//'), '/')[2], + split((secretsExportConfiguration.?keyVaultResourceId ?? '////'), '/')[4] + ) + params: { + keyVaultName: last(split(secretsExportConfiguration.?keyVaultResourceId ?? '//', '/')) + secretsToSet: union( + [], + contains(secretsExportConfiguration!, 'sqlAdminPasswordSecretName') + ? [ + { + name: secretsExportConfiguration!.sqlAdminPasswordSecretName + value: administratorLoginPassword + } + ] + : [], + contains(secretsExportConfiguration!, 'sqlAzureConnectionStringSercretName') + ? [ + { + name: secretsExportConfiguration!.sqlAzureConnectionStringSercretName + value: 'Server=${server.properties.fullyQualifiedDomainName}; Database=${!empty(databases) ? databases[0].name : ''}; User=${administratorLogin}; Password=${administratorLoginPassword}' + } + ] + : [] + ) + } +} + @description('The name of the deployed SQL server.') output name string = server.name @@ -506,6 +539,11 @@ output systemAssignedMIPrincipalId string = server.?identity.?principalId ?? '' @description('The location the resource was deployed into.') output location string = server.location +@description('A hashtable of references to the secrets exported to the provided Key Vault. The key of each reference is each secret\'s name.') +output exportedSecrets secretsOutputType = (secretsExportConfiguration != null) + ? toObject(secretsExport.outputs.secretsSet, secret => last(split(secret.secretResourceId, '/')), secret => secret) + : {} + @description('The private endpoints of the SQL server.') output privateEndpoints array = [ for (pe, i) in (!empty(privateEndpoints) ? array(privateEndpoints) : []): { @@ -681,3 +719,20 @@ type auditSettingsType = { @description('Optional. Specifies the identifier key of the auditing storage account.') storageAccountResourceId: string? } + +type secretsExportConfigurationType = { + @description('Required. The resource ID of the key vault where to store the secrets of this module.') + keyVaultResourceId: string + + @description('Optional. The sqlAdminPassword secret name to create.') + sqlAdminPasswordSecretName: string? + + @description('Optional. The sqlAzureConnectionString secret name to create.') + sqlAzureConnectionStringSercretName: string? +}? + +import { secretSetType } from 'modules/keyVaultExport.bicep' +type secretsOutputType = { + @description('An exported secret\'s references.') + *: secretSetType +} diff --git a/avm/res/sql/server/main.json b/avm/res/sql/server/main.json index b13a78c08f..af15b03a96 100644 --- a/avm/res/sql/server/main.json +++ b/avm/res/sql/server/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "13031224188572751832" + "version": "0.30.23.60470", + "templateHash": "779644860652942835" }, "name": "Azure SQL Servers", "description": "This module deploys an Azure SQL Server.", @@ -434,6 +434,64 @@ } } } + }, + "secretsExportConfigurationType": { + "type": "object", + "properties": { + "keyVaultResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the key vault where to store the secrets of this module." + } + }, + "sqlAdminPasswordSecretName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The sqlAdminPassword secret name to create." + } + }, + "sqlAzureConnectionStringSercretName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The sqlAzureConnectionString secret name to create." + } + } + }, + "nullable": true + }, + "secretsOutputType": { + "type": "object", + "properties": {}, + "additionalProperties": { + "$ref": "#/definitions/secretSetType", + "metadata": { + "description": "An exported secret's references." + } + } + }, + "secretSetType": { + "type": "object", + "properties": { + "secretResourceId": { + "type": "string", + "metadata": { + "description": "The resourceId of the exported secret." + } + }, + "secretUri": { + "type": "string", + "metadata": { + "description": "The secret URI of the exported secret." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "modules/keyVaultExport.bicep" + } + } } }, "parameters": { @@ -614,6 +672,13 @@ "metadata": { "description": "Optional. The audit settings configuration." } + }, + "secretsExportConfiguration": { + "$ref": "#/definitions/secretsExportConfigurationType", + "nullable": true, + "metadata": { + "description": "Optional. Key vault reference and secret settings for the module's secrets export." + } } }, "variables": { @@ -780,8 +845,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "6019999815954957727" + "version": "0.30.23.60470", + "templateHash": "11407307502843440892" }, "name": "SQL Server Database", "description": "This module deploys an Azure SQL Server Database.", @@ -1258,8 +1323,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "8635162595153731245" + "version": "0.30.23.60470", + "templateHash": "10836519140305169908" }, "name": "Azure SQL Server Database Short Term Backup Retention Policies", "description": "This module deploys an Azure SQL Server Database Short-Term Backup Retention Policy.", @@ -1360,8 +1425,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "2778016138108001251" + "version": "0.30.23.60470", + "templateHash": "10064519186693398262" }, "name": "SQL Server Database Long Term Backup Retention Policies", "description": "This module deploys an Azure SQL Server Database Long-Term Backup Retention Policy.", @@ -1538,8 +1603,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "18037703368269722870" + "version": "0.30.23.60470", + "templateHash": "1486548652639885128" }, "name": "SQL Server Elastic Pool", "description": "This module deploys an Azure SQL Server Elastic Pool.", @@ -2520,8 +2585,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "7779473510493338097" + "version": "0.30.23.60470", + "templateHash": "6449556555046717103" }, "name": "Azure SQL Server Firewall Rule", "description": "This module deploys an Azure SQL Server Firewall Rule.", @@ -2626,8 +2691,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "7859066741604114060" + "version": "0.30.23.60470", + "templateHash": "4969955763304077350" }, "name": "Azure SQL Server Virtual Network Rules", "description": "This module deploys an Azure SQL Server Virtual Network Rule.", @@ -2734,8 +2799,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "6025191760768766090" + "version": "0.30.23.60470", + "templateHash": "15406914222375641032" }, "name": "Azure SQL Server Security Alert Policies", "description": "This module deploys an Azure SQL Server Security Alert Policy.", @@ -2885,8 +2950,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "5682596516926040129" + "version": "0.30.23.60470", + "templateHash": "11004049200994426011" }, "name": "Azure SQL Server Vulnerability Assessments", "description": "This module deploys an Azure SQL Server Vulnerability Assessment.", @@ -2988,8 +3053,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "17251889896692066430" + "version": "0.30.23.60470", + "templateHash": "13956215614091387428" } }, "parameters": { @@ -3077,8 +3142,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "5863771213375512760" + "version": "0.30.23.60470", + "templateHash": "17839617504395216689" }, "name": "Azure SQL Server Keys", "description": "This module deploys an Azure SQL Server Key.", @@ -3196,8 +3261,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "6914924378490463775" + "version": "0.30.23.60470", + "templateHash": "11473914706327458055" }, "name": "Azure SQL Server Encryption Protector", "description": "This module deploys an Azure SQL Server Encryption Protector.", @@ -3329,8 +3394,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "4165841300638093382" + "version": "0.30.23.60470", + "templateHash": "2456263707393734456" }, "name": "Azure SQL Server Audit Settings", "description": "This module deploys an Azure SQL Server Audit Settings.", @@ -3468,8 +3533,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "17251889896692066430" + "version": "0.30.23.60470", + "templateHash": "13956215614091387428" } }, "parameters": { @@ -3528,6 +3593,140 @@ "dependsOn": [ "server" ] + }, + "secretsExport": { + "condition": "[not(equals(parameters('secretsExportConfiguration'), null()))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-secrets-kv', uniqueString(deployment().name, parameters('location')))]", + "subscriptionId": "[split(coalesce(tryGet(parameters('secretsExportConfiguration'), 'keyVaultResourceId'), '//'), '/')[2]]", + "resourceGroup": "[split(coalesce(tryGet(parameters('secretsExportConfiguration'), 'keyVaultResourceId'), '////'), '/')[4]]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "keyVaultName": { + "value": "[last(split(coalesce(tryGet(parameters('secretsExportConfiguration'), 'keyVaultResourceId'), '//'), '/'))]" + }, + "secretsToSet": { + "value": "[union(createArray(), if(contains(parameters('secretsExportConfiguration'), 'sqlAdminPasswordSecretName'), createArray(createObject('name', parameters('secretsExportConfiguration').sqlAdminPasswordSecretName, 'value', parameters('administratorLoginPassword'))), createArray()), if(contains(parameters('secretsExportConfiguration'), 'sqlAzureConnectionStringSercretName'), createArray(createObject('name', parameters('secretsExportConfiguration').sqlAzureConnectionStringSercretName, 'value', format('Server={0}; Database={1}; User={2}; Password={3}', reference('server').fullyQualifiedDomainName, if(not(empty(parameters('databases'))), parameters('databases')[0].name, ''), parameters('administratorLogin'), parameters('administratorLoginPassword')))), createArray()))]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.30.23.60470", + "templateHash": "16142913599202614386" + } + }, + "definitions": { + "secretSetType": { + "type": "object", + "properties": { + "secretResourceId": { + "type": "string", + "metadata": { + "description": "The resourceId of the exported secret." + } + }, + "secretUri": { + "type": "string", + "metadata": { + "description": "The secret URI of the exported secret." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "secretToSetType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the secret to set." + } + }, + "value": { + "type": "securestring", + "metadata": { + "description": "Required. The value of the secret to set." + } + } + } + } + }, + "parameters": { + "keyVaultName": { + "type": "string", + "metadata": { + "description": "Required. The name of the Key Vault to set the secrets in." + } + }, + "secretsToSet": { + "type": "array", + "items": { + "$ref": "#/definitions/secretToSetType" + }, + "metadata": { + "description": "Required. The secrets to set in the Key Vault." + } + } + }, + "resources": { + "keyVault": { + "existing": true, + "type": "Microsoft.KeyVault/vaults", + "apiVersion": "2022-07-01", + "name": "[parameters('keyVaultName')]" + }, + "secrets": { + "copy": { + "name": "secrets", + "count": "[length(parameters('secretsToSet'))]" + }, + "type": "Microsoft.KeyVault/vaults/secrets", + "apiVersion": "2023-07-01", + "name": "[format('{0}/{1}', parameters('keyVaultName'), parameters('secretsToSet')[copyIndex()].name)]", + "properties": { + "value": "[parameters('secretsToSet')[copyIndex()].value]" + }, + "dependsOn": [ + "keyVault" + ] + } + }, + "outputs": { + "secretsSet": { + "type": "array", + "items": { + "$ref": "#/definitions/secretSetType" + }, + "metadata": { + "description": "The references to the secrets exported to the provided Key Vault." + }, + "copy": { + "count": "[length(range(0, length(coalesce(parameters('secretsToSet'), createArray()))))]", + "input": { + "secretResourceId": "[resourceId('Microsoft.KeyVault/vaults/secrets', parameters('keyVaultName'), parameters('secretsToSet')[range(0, length(coalesce(parameters('secretsToSet'), createArray())))[copyIndex()]].name)]", + "secretUri": "[reference(format('secrets[{0}]', range(0, length(coalesce(parameters('secretsToSet'), createArray())))[copyIndex()])).secretUri]" + } + } + } + } + } + }, + "dependsOn": [ + "server" + ] } }, "outputs": { @@ -3566,6 +3765,13 @@ }, "value": "[reference('server', '2023-08-01-preview', 'full').location]" }, + "exportedSecrets": { + "$ref": "#/definitions/secretsOutputType", + "metadata": { + "description": "A hashtable of references to the secrets exported to the provided Key Vault. The key of each reference is each secret's name." + }, + "value": "[if(not(equals(parameters('secretsExportConfiguration'), null())), toObject(reference('secretsExport').outputs.secretsSet.value, lambda('secret', last(split(lambdaVariables('secret').secretResourceId, '/'))), lambda('secret', lambdaVariables('secret'))), createObject())]" + }, "privateEndpoints": { "type": "array", "metadata": { diff --git a/avm/res/sql/server/modules/keyVaultExport.bicep b/avm/res/sql/server/modules/keyVaultExport.bicep new file mode 100644 index 0000000000..c4ff7c2f9d --- /dev/null +++ b/avm/res/sql/server/modules/keyVaultExport.bicep @@ -0,0 +1,62 @@ +// ============== // +// Parameters // +// ============== // + +@description('Required. The name of the Key Vault to set the secrets in.') +param keyVaultName string + +@description('Required. The secrets to set in the Key Vault.') +param secretsToSet secretToSetType[] + +// ============= // +// Resources // +// ============= // + +resource keyVault 'Microsoft.KeyVault/vaults@2022-07-01' existing = { + name: keyVaultName +} + +resource secrets 'Microsoft.KeyVault/vaults/secrets@2023-07-01' = [ + for secret in secretsToSet: { + name: secret.name + parent: keyVault + properties: { + value: secret.value + } + } +] + +// =========== // +// Outputs // +// =========== // + +@description('The references to the secrets exported to the provided Key Vault.') +output secretsSet secretSetType[] = [ + #disable-next-line outputs-should-not-contain-secrets // Only returning the references, not a secret value + for index in range(0, length(secretsToSet ?? [])): { + secretResourceId: secrets[index].id + secretUri: secrets[index].properties.secretUri + } +] + +// =============== // +// Definitions // +// =============== // + +@export() +type secretSetType = { + @description('The resourceId of the exported secret.') + secretResourceId: string + + @description('The secret URI of the exported secret.') + secretUri: string +} + +type secretToSetType = { + @description('Required. The name of the secret to set.') + name: string + + @description('Required. The value of the secret to set.') + @secure() + value: string +} diff --git a/avm/res/sql/server/tests/e2e/kvSecrets/dependencies.bicep b/avm/res/sql/server/tests/e2e/kvSecrets/dependencies.bicep new file mode 100644 index 0000000000..2d7a1701e3 --- /dev/null +++ b/avm/res/sql/server/tests/e2e/kvSecrets/dependencies.bicep @@ -0,0 +1,21 @@ +@description('Optional. The location to deploy to.') +param location string = resourceGroup().location + +@description('Required. The name of the keyVault to create.') +param keyVaultName string + +resource keyVault 'Microsoft.KeyVault/vaults@2022-07-01' = { + name: keyVaultName + location: location + properties: { + sku: { + family: 'A' + name: 'standard' + } + tenantId: tenant().tenantId + enableRbacAuthorization: true + } +} + +@description('The id of the Key Vault created.') +output keyVaultResourceId string = keyVault.id diff --git a/avm/res/sql/server/tests/e2e/kvSecrets/main.test.bicep b/avm/res/sql/server/tests/e2e/kvSecrets/main.test.bicep new file mode 100644 index 0000000000..31e94ee0a9 --- /dev/null +++ b/avm/res/sql/server/tests/e2e/kvSecrets/main.test.bicep @@ -0,0 +1,73 @@ +targetScope = 'subscription' + +metadata name = 'Deploying with a key vault reference to save secrets' +metadata description = 'This instance deploys the module saving all its secrets in a key vault.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-sql.servers-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'sqlkvs' + +@description('Optional. The password to leverage for the login.') +@secure() +param password string = newGuid() + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + keyVaultName: 'dep-${namePrefix}-kv-${serviceShort}' + location: resourceLocation + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + location: resourceLocation + administratorLogin: 'adminUserName' + administratorLoginPassword: password + secretsExportConfiguration: { + keyVaultResourceId: nestedDependencies.outputs.keyVaultResourceId + sqlAdminPasswordSecretName: 'adminLoginPasswordKey' + sqlAzureConnectionStringSercretName: 'sqlConnectionStringKey' + } + databases: [ + { + name: 'myDatabase' + } + ] + } + } +]