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

feat: avm/res/cache/redis: add support for AKV secrets export #4138

Merged
merged 5 commits into from
Jan 22, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
167 changes: 161 additions & 6 deletions avm/res/cache/redis/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ This module deploys a Redis Cache.
| `Microsoft.Cache/redis/accessPolicyAssignments` | [2024-04-01-preview](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Cache/2024-04-01-preview/redis/accessPolicyAssignments) |
| `Microsoft.Cache/redis/linkedServers` | [2024-03-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Cache/2024-03-01/redis/linkedServers) |
| `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 @@ -36,9 +37,10 @@ The following section provides usage examples for the module, which were used to

- [Using only defaults](#example-1-using-only-defaults)
- [Using EntraID authentication](#example-2-using-entraid-authentication)
- [Using large parameter set](#example-3-using-large-parameter-set)
- [Passive Geo-Replicated Redis Cache](#example-4-passive-geo-replicated-redis-cache)
- [WAF-aligned](#example-5-waf-aligned)
- [Deploying with a key vault reference to save secrets](#example-3-deploying-with-a-key-vault-reference-to-save-secrets)
- [Using large parameter set](#example-4-using-large-parameter-set)
- [Passive Geo-Replicated Redis Cache](#example-5-passive-geo-replicated-redis-cache)
- [WAF-aligned](#example-6-waf-aligned)

### Example 1: _Using only defaults_

Expand Down Expand Up @@ -222,7 +224,94 @@ param redisConfiguration = {
</details>
<p>

### Example 3: _Using large parameter set_
### Example 3: _Deploying with a key vault reference to save secrets_

This instance deploys the module saving all its secrets in a key vault.


<details>

<summary>via Bicep module</summary>

```bicep
module redis 'br/public:avm/res/cache/redis:<version>' = {
name: 'redisDeployment'
params: {
// Required parameters
name: 'kvref'
// Non-required parameters
location: '<location>'
secretsExportConfiguration: {
keyVaultResourceId: '<keyVaultResourceId>'
primaryAccessKeyName: 'custom-primaryAccessKey-name'
primaryConnectionStringName: 'custom-primaryConnectionString-name'
secondaryAccessKeyName: 'custom-secondaryAccessKey-name'
secondaryConnectionStringName: 'custom-secondaryConnectionString-name'
}
}
}
```

</details>
<p>

<details>

<summary>via JSON parameters file</summary>

```json
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#",
"contentVersion": "1.0.0.0",
"parameters": {
// Required parameters
"name": {
"value": "kvref"
},
// Non-required parameters
"location": {
"value": "<location>"
},
"secretsExportConfiguration": {
"value": {
"keyVaultResourceId": "<keyVaultResourceId>",
"primaryAccessKeyName": "custom-primaryAccessKey-name",
"primaryConnectionStringName": "custom-primaryConnectionString-name",
"secondaryAccessKeyName": "custom-secondaryAccessKey-name",
"secondaryConnectionStringName": "custom-secondaryConnectionString-name"
}
}
}
}
```

</details>
<p>

<details>

<summary>via Bicep parameters file</summary>

```bicep-params
using 'br/public:avm/res/cache/redis:<version>'

// Required parameters
param name = 'kvref'
// Non-required parameters
param location = '<location>'
param secretsExportConfiguration = {
keyVaultResourceId: '<keyVaultResourceId>'
primaryAccessKeyName: 'custom-primaryAccessKey-name'
primaryConnectionStringName: 'custom-primaryConnectionString-name'
secondaryAccessKeyName: 'custom-secondaryAccessKey-name'
secondaryConnectionStringName: 'custom-secondaryConnectionString-name'
}
```

</details>
<p>

### Example 4: _Using large parameter set_

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

Expand Down Expand Up @@ -623,7 +712,7 @@ param zones = [
</details>
<p>

### Example 4: _Passive Geo-Replicated Redis Cache_
### Example 5: _Passive Geo-Replicated Redis Cache_

This instance deploys the module with geo-replication enabled.

Expand Down Expand Up @@ -763,7 +852,7 @@ param zoneRedundant = false
</details>
<p>

### Example 5: _WAF-aligned_
### Example 6: _WAF-aligned_

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

Expand Down Expand Up @@ -1051,6 +1140,7 @@ param zones = [
| [`replicasPerMaster`](#parameter-replicaspermaster) | int | The number of replicas to be created per primary. |
| [`replicasPerPrimary`](#parameter-replicasperprimary) | int | The number of replicas to be created per primary. Needs to be the same as replicasPerMaster for a Premium Cluster Cache. |
| [`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. |
| [`shardCount`](#parameter-shardcount) | int | The number of shards to be created on a Premium Cluster Cache. |
| [`skuName`](#parameter-skuname) | string | The type of Redis cache to deploy. |
| [`staticIP`](#parameter-staticip) | string | Static IP address. Optionally, may be specified when deploying a Redis cache inside an existing Azure Virtual Network; auto assigned by default. |
Expand Down Expand Up @@ -2000,6 +2090,69 @@ The principal type of the assigned principal ID.
```
- MinValue: 1

### Parameter: `secretsExportConfiguration`

Key vault reference and secret settings for the module's secrets export.

- Required: No
- Type: object
- MinValue: 1

**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 |
| :-- | :-- | :-- |
| [`primaryAccessKeyName`](#parameter-secretsexportconfigurationprimaryaccesskeyname) | string | The primaryAccessKey secret name to create. |
| [`primaryConnectionStringName`](#parameter-secretsexportconfigurationprimaryconnectionstringname) | string | The primaryConnectionString secret name to create. |
| [`secondaryAccessKeyName`](#parameter-secretsexportconfigurationsecondaryaccesskeyname) | string | The secondaryAccessKey secret name to create. |
| [`secondaryConnectionStringName`](#parameter-secretsexportconfigurationsecondaryconnectionstringname) | string | The secondaryConnectionString 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
- MinValue: 1

### Parameter: `secretsExportConfiguration.primaryAccessKeyName`

The primaryAccessKey secret name to create.

- Required: No
- Type: string
- MinValue: 1

### Parameter: `secretsExportConfiguration.primaryConnectionStringName`

The primaryConnectionString secret name to create.

- Required: No
- Type: string
- MinValue: 1

### Parameter: `secretsExportConfiguration.secondaryAccessKeyName`

The secondaryAccessKey secret name to create.

- Required: No
- Type: string
- MinValue: 1

### Parameter: `secretsExportConfiguration.secondaryConnectionStringName`

The secondaryConnectionString secret name to create.

- Required: No
- Type: string
- MinValue: 1

### Parameter: `shardCount`

The number of shards to be created on a Premium Cluster Cache.
Expand Down Expand Up @@ -2090,6 +2243,7 @@ If the zoneRedundant parameter is true, replicas will be provisioned in the avai

| 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. |
| `hostName` | string | Redis hostname. |
| `location` | string | The location the resource was deployed into. |
| `name` | string | The name of the Redis Cache. |
Expand All @@ -2107,6 +2261,7 @@ This section gives you an overview of all local-referenced module files (i.e., o
| Reference | Type |
| :-- | :-- |
| `br/public:avm/res/network/private-endpoint:0.7.1` | Remote reference |
| `br/public:avm/utl/types/avm-common-types:0.4.1` | Remote reference |

## Notes

Expand Down
2 changes: 1 addition & 1 deletion avm/res/cache/redis/linked-servers/main.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"_generator": {
"name": "bicep",
"version": "0.32.4.45862",
"templateHash": "9818219089257499387"
"templateHash": "3113734842268106241"
},
"name": "Redis Cache Linked Servers",
"description": "This module connects a primary and secondary Redis Cache together for geo-replication."
Expand Down
73 changes: 73 additions & 0 deletions avm/res/cache/redis/main.bicep
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,9 @@ param accessPolicies accessPolicyType[] = []
@description('Optional. Array of access policy assignments.')
param accessPolicyAssignments accessPolicyAssignmentType[] = []

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

var availabilityZones = skuName == 'Premium'
? zoneRedundant ? !empty(zones) ? zones : pickZones('Microsoft.Cache', 'redis', location, 3) : []
: []
Expand Down Expand Up @@ -356,6 +359,52 @@ module redis_geoReplication 'linked-servers/main.bicep' = if (!empty(geoReplicat
dependsOn: redis_privateEndpoints
}

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!, 'primaryAccessKeyName')
? [
{
name: secretsExportConfiguration!.primaryAccessKeyName
value: redis.listKeys().primaryKey
}
]
: [],
contains(secretsExportConfiguration!, 'primaryConnectionStringName')
? [
{
name: secretsExportConfiguration!.primaryConnectionStringName
value: 'rediss://:${redis.listKeys().primaryKey}@${redis.properties.hostName}:6380'
}
]
: [],
contains(secretsExportConfiguration!, 'secondaryAccessKeyName')
? [
{
name: secretsExportConfiguration!.secondaryAccessKeyName
value: redis.listKeys().secondaryKey
}
]
: [],
contains(secretsExportConfiguration!, 'secondaryConnectionStringName')
? [
{
name: secretsExportConfiguration!.secondaryConnectionStringName
value: 'rediss://:${redis.listKeys().secondaryKey}@${redis.properties.hostName}:6380'
}
]
: []
)
}
}

@description('The name of the Redis Cache.')
output name string = redis.name

Expand Down Expand Up @@ -391,6 +440,12 @@ output privateEndpoints array = [
}
]

import { secretsOutputType } from 'br/public:avm/utl/types/avm-common-types:0.4.1'
@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 @@ -583,3 +638,21 @@ type accessPolicyAssignmentType = {
@description('Required. Name of the access policy to be assigned.')
accessPolicyName: string
}

@export()
type secretsExportConfigurationType = {
@description('Required. The resource ID of the key vault where to store the secrets of this module.')
keyVaultResourceId: string

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

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

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

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