Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: Add key vault to cognitive service - avm/res/cognitive-services/account #1932

137 changes: 123 additions & 14 deletions avm/res/cognitive-services/account/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ This module deploys a Cognitive Service.
| `Microsoft.CognitiveServices/accounts` | [2023-05-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.CognitiveServices/2023-05-01/accounts) |
| `Microsoft.CognitiveServices/accounts/deployments` | [2023-05-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.CognitiveServices/2023-05-01/accounts/deployments) |
| `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) |

Expand All @@ -33,13 +34,14 @@ The following section provides usage examples for the module, which were used to

- [Using `AIServices` with `deployments` in parameter set and private endpoints](#example-1-using-aiservices-with-deployments-in-parameter-set-and-private-endpoints)
- [Using `AIServices` with `deployments` in parameter set](#example-2-using-aiservices-with-deployments-in-parameter-set)
- [Using only defaults](#example-3-using-only-defaults)
- [Using large parameter set](#example-4-using-large-parameter-set)
- [Using `OpenAI` and `deployments` in parameter set with private endpoint](#example-5-using-openai-and-deployments-in-parameter-set-with-private-endpoint)
- [As Speech Service](#example-6-as-speech-service)
- [Using Customer-Managed-Keys with System-Assigned identity](#example-7-using-customer-managed-keys-with-system-assigned-identity)
- [Using Customer-Managed-Keys with User-Assigned identity](#example-8-using-customer-managed-keys-with-user-assigned-identity)
- [WAF-aligned](#example-9-waf-aligned)
- [Using defaults with key vault](#example-3-using-defaults-with-key-vault)
- [Using only defaults](#example-4-using-only-defaults)
- [Using large parameter set](#example-5-using-large-parameter-set)
- [Using `OpenAI` and `deployments` in parameter set with private endpoint](#example-6-using-openai-and-deployments-in-parameter-set-with-private-endpoint)
- [As Speech Service](#example-7-as-speech-service)
- [Using Customer-Managed-Keys with System-Assigned identity](#example-8-using-customer-managed-keys-with-system-assigned-identity)
- [Using Customer-Managed-Keys with User-Assigned identity](#example-9-using-customer-managed-keys-with-user-assigned-identity)
- [WAF-aligned](#example-10-waf-aligned)

### Example 1: _Using `AIServices` with `deployments` in parameter set and private endpoints_

Expand Down Expand Up @@ -243,7 +245,71 @@ module account 'br/public:avm/res/cognitive-services/account:<version>' = {
</details>
<p>

### Example 3: _Using only defaults_
### Example 3: _Using defaults with key vault_

This instance deploys the module with the minimum set of required parameters and stores the keys in key vault.


<details>

<summary>via Bicep module</summary>

```bicep
module account 'br/public:avm/res/cognitive-services/account:<version>' = {
name: 'accountDeployment'
params: {
// Required parameters
kind: 'SpeechServices'
name: 'csakv001'
// Non-required parameters
location: '<location>'
secretsExportConfiguration: {
accessKey1: 'Custom-key1-name'
accessKey2: 'Custom-key2-name'
keyVaultResourceId: '<keyVaultResourceId>'
}
}
}
```

</details>
<p>

<details>

<summary>via JSON Parameter file</summary>

```json
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#",
"contentVersion": "1.0.0.0",
"parameters": {
// Required parameters
"kind": {
"value": "SpeechServices"
},
"name": {
"value": "csakv001"
},
// Non-required parameters
"location": {
"value": "<location>"
},
"secretsExportConfiguration": {
"value": {
"accessKey1": "Custom-key1-name",
"accessKey2": "Custom-key2-name",
"keyVaultResourceId": "<keyVaultResourceId>"
}
}
}
}
```

</details>
<p>

### Example 4: _Using only defaults_

This instance deploys the module with the minimum set of required parameters.

Expand Down Expand Up @@ -295,7 +361,7 @@ module account 'br/public:avm/res/cognitive-services/account:<version>' = {
</details>
<p>

### Example 4: _Using large parameter set_
### Example 5: _Using large parameter set_

This instance deploys the module with most of its features enabled.

Expand Down Expand Up @@ -587,7 +653,7 @@ module account 'br/public:avm/res/cognitive-services/account:<version>' = {
</details>
<p>

### Example 5: _Using `OpenAI` and `deployments` in parameter set with private endpoint_
### Example 6: _Using `OpenAI` and `deployments` in parameter set with private endpoint_

This instance deploys the module with the AI model deployment feature and private endpoint.

Expand Down Expand Up @@ -695,7 +761,7 @@ module account 'br/public:avm/res/cognitive-services/account:<version>' = {
</details>
<p>

### Example 6: _As Speech Service_
### Example 7: _As Speech Service_

This instance deploys the module as a Speech Service.

Expand Down Expand Up @@ -809,7 +875,7 @@ module account 'br/public:avm/res/cognitive-services/account:<version>' = {
</details>
<p>

### Example 7: _Using Customer-Managed-Keys with System-Assigned identity_
### Example 8: _Using Customer-Managed-Keys with System-Assigned identity_

This instance deploys the module using Customer-Managed-Keys using a System-Assigned Identity. This required the service to be deployed twice, once as a pre-requisite to create the System-Assigned Identity, and once to use it for accessing the Customer-Managed-Key secret.

Expand Down Expand Up @@ -891,7 +957,7 @@ module account 'br/public:avm/res/cognitive-services/account:<version>' = {
</details>
<p>

### Example 8: _Using Customer-Managed-Keys with User-Assigned identity_
### Example 9: _Using Customer-Managed-Keys with User-Assigned identity_

This instance deploys the module using Customer-Managed-Keys using a User-Assigned Identity to access the Customer-Managed-Key secret.

Expand Down Expand Up @@ -979,7 +1045,7 @@ module account 'br/public:avm/res/cognitive-services/account:<version>' = {
</details>
<p>

### Example 9: _WAF-aligned_
### Example 10: _WAF-aligned_

This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework.

Expand Down Expand Up @@ -1153,6 +1219,7 @@ module account 'br/public:avm/res/cognitive-services/account:<version>' = {
| [`restore`](#parameter-restore) | bool | Restore a soft-deleted cognitive service at deployment time. Will fail if no such soft-deleted resource exists. |
| [`restrictOutboundNetworkAccess`](#parameter-restrictoutboundnetworkaccess) | bool | Restrict outbound network access. |
| [`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. |
| [`sku`](#parameter-sku) | string | SKU of the Cognitive Services resource. Use 'Get-AzCognitiveServicesAccountSku' to determine a valid combinations of 'kind' and 'SKU' for your Azure region. |
| [`tags`](#parameter-tags) | object | Tags of the resource. |
| [`userOwnedStorage`](#parameter-userownedstorage) | array | The storage accounts for this resource. |
Expand Down Expand Up @@ -2108,6 +2175,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 key vault name where to store the keys and connection strings generated by the modules. |

**Optional parameters**

| Parameter | Type | Description |
| :-- | :-- | :-- |
| [`accessKey1`](#parameter-secretsexportconfigurationaccesskey1) | string | The accessKey1 secret name to create. |
| [`accessKey2`](#parameter-secretsexportconfigurationaccesskey2) | string | The accessKey2 secret name to create. |

### Parameter: `secretsExportConfiguration.keyVaultResourceId`

The key vault name where to store the keys and connection strings generated by the modules.

- Required: Yes
- Type: string

### Parameter: `secretsExportConfiguration.accessKey1`

The accessKey1 secret name to create.

- Required: No
- Type: string

### Parameter: `secretsExportConfiguration.accessKey2`

The accessKey2 secret name to create.

- Required: No
- Type: string

### Parameter: `sku`

SKU of the Cognitive Services resource. Use 'Get-AzCognitiveServicesAccountSku' to determine a valid combinations of 'kind' and 'SKU' for your Azure region.
Expand Down Expand Up @@ -2159,6 +2267,7 @@ The storage accounts for this resource.
| :-- | :-- | :-- |
| `endpoint` | string | The service endpoint of the cognitive services account. |
| `endpoints` | | All endpoints available for the cognitive services account, types depends on the cognitive service kind. |
| `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 cognitive services account. |
| `resourceGroupName` | string | The resource group the cognitive services account was deployed into. |
Expand Down
55 changes: 55 additions & 0 deletions avm/res/cognitive-services/account/main.bicep
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,9 @@ param enableTelemetry bool = true
@description('Optional. Array of deployments about cognitive service accounts to create.')
param deployments deploymentsType

@description('Optional. Key vault reference and secret settings for the module\'s secrets export.')
param secretsExportConfiguration secretsExportConfigurationType?

var formattedUserAssignedIdentities = reduce(
map((managedIdentities.?userAssignedResourceIds ?? []), (id) => { '${id}': {} }),
{},
Expand Down Expand Up @@ -468,6 +471,36 @@ resource cognitiveService_roleAssignments 'Microsoft.Authorization/roleAssignmen
}
]

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!, 'accessKey1')
? [
{
name: secretsExportConfiguration!.accessKey1
value: cognitiveService.listKeys().key1
}
]
: [],
contains(secretsExportConfiguration!, 'accessKey2')
? [
{
name: secretsExportConfiguration!.accessKey2
value: cognitiveService.listKeys().key2
}
]
: []
)
}
}

@description('The name of the cognitive services account.')
output name string = cognitiveService.name

Expand All @@ -489,6 +522,11 @@ output systemAssignedMIPrincipalId string = cognitiveService.?identity.?principa
@description('The location the resource was deployed into.')
output location string = cognitiveService.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)
: {}

// ================ //
// Definitions //
// ================ //
Expand Down Expand Up @@ -706,3 +744,20 @@ type endpointsType = {
@description('The endpoint URI.')
endpoint: string?
}?

type secretsExportConfigurationType = {
@description('Required. The key vault name where to store the keys and connection strings generated by the modules.')
keyVaultResourceId: string

@description('Optional. The accessKey1 secret name to create.')
accessKey1: string?

@description('Optional. The accessKey2 secret name to create.')
accessKey2: string?
}

import { secretSetType } from 'modules/keyVaultExport.bicep'
type secretsOutputType = {
@description('An exported secret\'s references.')
*: secretSetType
}
Loading