Skip to content

Commit

Permalink
feat: Update avm/res/event-hubs/namespace -Add support for AKV secr…
Browse files Browse the repository at this point in the history
…ets export (#4288)

## Description

Closes #3638

## Pipeline Reference

Verified locally:


![image](https://github.com/user-attachments/assets/cebe9908-f5f1-41c6-92d5-efbae3ba0700)

## Type of Change

<!-- Use the checkboxes [x] on the options that are relevant. -->

- [ ] Update to CI Environment or utilities (Non-module affecting
changes)
- [x] Azure Verified Module updates:
- [ ] Bugfix containing backwards-compatible bug fixes, and I have NOT
bumped the MAJOR or MINOR version in `version.json`:
- [ ] Someone has opened a bug report issue, and I have included "Closes
#{bug_report_issue_number}" in the PR description.
- [ ] The bug was found by the module author, and no one has opened an
issue to report it yet.
- [x] Feature update backwards compatible feature updates, and I have
bumped the MINOR version in `version.json`.
- [ ] Breaking changes and I have bumped the MAJOR version in
`version.json`.
  - [ ] Update to documentation

## Checklist

- [x] I'm sure there are no other open Pull Requests for the same
update/change
- [x] I have run `Set-AVMModule` locally to generate the supporting
module files.
- [x] My corresponding pipelines / checks run clean and green without
any errors or warnings
  • Loading branch information
weikanglim authored Jan 28, 2025
1 parent 50ac9d2 commit f7fb13b
Show file tree
Hide file tree
Showing 7 changed files with 620 additions and 21 deletions.
168 changes: 164 additions & 4 deletions avm/res/event-hub/namespace/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ This module deploys an Event Hub Namespace.
| `Microsoft.EventHub/namespaces/eventhubs/consumergroups` | [2024-01-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.EventHub/2024-01-01/namespaces/eventhubs/consumergroups) |
| `Microsoft.EventHub/namespaces/networkRuleSets` | [2024-01-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.EventHub/2024-01-01/namespaces/networkRuleSets) |
| `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 @@ -38,8 +39,9 @@ The following section provides usage examples for the module, which were used to
- [Using only defaults](#example-1-using-only-defaults)
- [Using encryption with Customer-Managed-Key](#example-2-using-encryption-with-customer-managed-key)
- [Using large parameter set](#example-3-using-large-parameter-set)
- [WAF-aligned](#example-4-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)
- [WAF-aligned](#example-5-waf-aligned)

### Example 1: _Using only defaults_

Expand Down Expand Up @@ -216,7 +218,94 @@ param skuName = 'Premium'
</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 namespace 'br/public:avm/res/event-hub/namespace:<version>' = {
name: 'namespaceDeployment'
params: {
// Required parameters
name: 'ehnkv001'
// Non-required parameters
location: '<location>'
secretsExportConfiguration: {
keyVaultResourceId: '<keyVaultResourceId>'
rootPrimaryConnectionStringName: 'primaryConnectionString-name'
rootPrimaryKeyName: 'primaryKey-name'
rootSecondaryConnectionStringName: 'secondaryConnectionString-name'
rootSecondaryKeyName: 'secondaryKey-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": "ehnkv001"
},
// Non-required parameters
"location": {
"value": "<location>"
},
"secretsExportConfiguration": {
"value": {
"keyVaultResourceId": "<keyVaultResourceId>",
"rootPrimaryConnectionStringName": "primaryConnectionString-name",
"rootPrimaryKeyName": "primaryKey-name",
"rootSecondaryConnectionStringName": "secondaryConnectionString-name",
"rootSecondaryKeyName": "secondaryKey-name"
}
}
}
}
```

</details>
<p>

<details>

<summary>via Bicep parameters file</summary>

```bicep-params
using 'br/public:avm/res/event-hub/namespace:<version>'
// Required parameters
param name = 'ehnkv001'
// Non-required parameters
param location = '<location>'
param secretsExportConfiguration = {
keyVaultResourceId: '<keyVaultResourceId>'
rootPrimaryConnectionStringName: 'primaryConnectionString-name'
rootPrimaryKeyName: 'primaryKey-name'
rootSecondaryConnectionStringName: 'secondaryConnectionString-name'
rootSecondaryKeyName: 'secondaryKey-name'
}
```

</details>
<p>

### Example 4: _Using large parameter set_

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

Expand Down Expand Up @@ -835,7 +924,7 @@ param zoneRedundant = true
</details>
<p>

### Example 4: _WAF-aligned_
### Example 5: _WAF-aligned_

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

Expand Down Expand Up @@ -1339,6 +1428,7 @@ param tags = {
| [`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. |
| [`requireInfrastructureEncryption`](#parameter-requireinfrastructureencryption) | bool | Enable infrastructure encryption (double encryption). Note, this setting requires the configuration of Customer-Managed-Keys (CMK) via the corresponding module parameters. |
| [`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. |
| [`skuCapacity`](#parameter-skucapacity) | int | The Event Hub's throughput units for Basic or Standard tiers, where value should be 0 to 20 throughput units. The Event Hubs premium units for Premium tier, where value should be 0 to 10 premium units. |
| [`skuName`](#parameter-skuname) | string | event hub plan SKU name. |
| [`tags`](#parameter-tags) | object | Tags of the resource. |
Expand Down Expand Up @@ -2399,6 +2489,75 @@ The principal type of the assigned principal ID.
- MinValue: 0
- MaxValue: 20

### Parameter: `secretsExportConfiguration`

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

- Required: No
- Type: object
- MinValue: 0
- MaxValue: 20

**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 |
| :-- | :-- | :-- |
| [`rootPrimaryConnectionStringName`](#parameter-secretsexportconfigurationrootprimaryconnectionstringname) | string | The rootPrimaryConnectionStringName secret name to create. |
| [`rootPrimaryKeyName`](#parameter-secretsexportconfigurationrootprimarykeyname) | string | The rootPrimaryKeyName secret name to create. |
| [`rootSecondaryConnectionStringName`](#parameter-secretsexportconfigurationrootsecondaryconnectionstringname) | string | The rootSecondaryConnectionStringName secret name to create. |
| [`rootSecondaryKeyName`](#parameter-secretsexportconfigurationrootsecondarykeyname) | string | The rootSecondaryKeyName 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: 0
- MaxValue: 20

### Parameter: `secretsExportConfiguration.rootPrimaryConnectionStringName`

The rootPrimaryConnectionStringName secret name to create.

- Required: No
- Type: string
- MinValue: 0
- MaxValue: 20

### Parameter: `secretsExportConfiguration.rootPrimaryKeyName`

The rootPrimaryKeyName secret name to create.

- Required: No
- Type: string
- MinValue: 0
- MaxValue: 20

### Parameter: `secretsExportConfiguration.rootSecondaryConnectionStringName`

The rootSecondaryConnectionStringName secret name to create.

- Required: No
- Type: string
- MinValue: 0
- MaxValue: 20

### Parameter: `secretsExportConfiguration.rootSecondaryKeyName`

The rootSecondaryKeyName secret name to create.

- Required: No
- Type: string
- MinValue: 0
- MaxValue: 20

### Parameter: `skuCapacity`

The Event Hub's throughput units for Basic or Standard tiers, where value should be 0 to 20 throughput units. The Event Hubs premium units for Premium tier, where value should be 0 to 10 premium units.
Expand Down Expand Up @@ -2451,6 +2610,7 @@ Switch to make the Event Hub Namespace zone redundant.
| Output | Type | Description |
| :-- | :-- | :-- |
| `eventHubResourceIds` | array | The Resources IDs of the EventHubs within this eventspace. |
| `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 eventspace. |
| `privateEndpoints` | array | The private endpoints of the eventspace. |
Expand Down
75 changes: 74 additions & 1 deletion avm/res/event-hub/namespace/main.bicep
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,9 @@ param eventhubs array = []
@description('Optional. The disaster recovery config for this namespace.')
param disasterRecoveryConfig disasterRecoveryConfigType?

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

var maximumThroughputUnitsVar = !isAutoInflateEnabled ? 0 : maximumThroughputUnits

var formattedUserAssignedIdentities = reduce(
Expand Down Expand Up @@ -227,7 +230,7 @@ resource eventHubNamespace 'Microsoft.EventHub/namespaces@2024-01-01' = {
keyName: customerManagedKey!.keyName
keyVaultUri: cMKKeyVault.properties.vaultUri
keyVersion: !empty(customerManagedKey.?keyVersion ?? '')
? customerManagedKey!.keyVersion
? customerManagedKey!.?keyVersion
: (customerManagedKey.?autoRotationEnabled ?? true)
? null
: last(split(cMKKeyVault::cMKKey.properties.keyUriWithVersion, '/'))
Expand Down Expand Up @@ -422,6 +425,52 @@ resource eventHubNamespace_diagnosticSettings 'Microsoft.Insights/diagnosticSett
}
]

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!, 'rootPrimaryConnectionStringName')
? [
{
name: secretsExportConfiguration!.?rootPrimaryConnectionStringName
value: listkeys('${eventHubNamespace.id}/AuthorizationRules/RootManageSharedAccessKey', '2024-01-01').primaryConnectionString
}
]
: [],
contains(secretsExportConfiguration!, 'rootSecondaryConnectionStringName')
? [
{
name: secretsExportConfiguration!.?rootSecondaryConnectionStringName
value: listkeys('${eventHubNamespace.id}/AuthorizationRules/RootManageSharedAccessKey', '2024-01-01').secondaryConnectionString
}
]
: [],
contains(secretsExportConfiguration!, 'rootPrimaryKeyName')
? [
{
name: secretsExportConfiguration!.?rootPrimaryKeyName
value: listkeys('${eventHubNamespace.id}/AuthorizationRules/RootManageSharedAccessKey', '2024-01-01').primaryKey
}
]
: [],
contains(secretsExportConfiguration!, 'rootSecondaryKeyName')
? [
{
name: secretsExportConfiguration!.?rootSecondaryKeyName
value: listkeys('${eventHubNamespace.id}/AuthorizationRules/RootManageSharedAccessKey', '2024-01-01').secondaryKey
}
]
: []
)
}
}

@description('The name of the eventspace.')
output name string = eventHubNamespace.name

Expand Down Expand Up @@ -453,6 +502,12 @@ output privateEndpoints privateEndpointOutputType[] = [
}
]

import { secretsOutputType } from 'br/public:avm/utl/types/avm-common-types:0.5.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 @@ -489,3 +544,21 @@ type disasterRecoveryConfigType = {
@description('Optional. Resource ID of the Primary/Secondary event hub namespace name, which is part of GEO DR pairing.')
partnerNamespaceResourceId: 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 rootPrimaryConnectionStringName secret name to create.')
rootPrimaryConnectionStringName: string?

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

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

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

0 comments on commit f7fb13b

Please sign in to comment.