Skip to content
Open
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
48 changes: 48 additions & 0 deletions modules/azure-kv/.terraform-docs.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
formatter: "markdown"

version: ""

header-from: docs/header.md
footer-from: docs/footer.md

recursive:
enabled: false
path: modules
include-main: true

sections:
hide: []
show: []

content: ""

output:
file: "README.md"
mode: inject
template: |-
<!-- BEGIN_TF_DOCS -->
{{ .Content }}
<!-- END_TF_DOCS -->

output-values:
enabled: false
from: ""

sort:
enabled: true
by: name

settings:
anchor: true
color: true
default: true
description: true
escape: true
hide-empty: false
html: true
indent: 2
lockfile: false
read-comments: true
required: true
sensitive: true
type: true
219 changes: 148 additions & 71 deletions modules/azure-kv/README.md

Large diffs are not rendered by default.

5 changes: 5 additions & 0 deletions modules/azure-kv/_examples/basic/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Basic example — `azure-kv`

Creates one Key Vault with **Azure RBAC** enabled and **no access policies**.

Set `resource_group` to an existing resource group and `name` to a **globally unique** vault name (3–24 characters: letters, numbers, and hyphens). This root only configures **`azurerm`** for your subscription; the child module still lists **`azuread`** in its `required_providers` (Terraform installs it), but this RBAC-only path does not evaluate Azure AD data sources. If you extend the stack with access policies using `type` `user`, `group`, or `service_principal`, add **`provider "azuread"`** (and credentials) so those lookups can run.
39 changes: 39 additions & 0 deletions modules/azure-kv/_examples/basic/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# Replace resource_group with an existing RG name and name with a globally unique vault name (3–24 characters: letters, numbers, hyphens).

terraform {
required_version = ">= 1.7.0"

required_providers {
azurerm = {
source = "hashicorp/azurerm"
version = ">= 4.21.0"
}
}
}

provider "azurerm" {
features {}
}

module "key_vault" {
source = "../.."

name = "kv-basicex0001"
resource_group = "example-rg"
enabled_for_disk_encryption = false
soft_delete_retention_days = 7
purge_protection_enabled = false
sku_name = "standard"
enable_rbac_authorization = true
access_policies = []

tags_from_rg = false
tags = {
example = "basic"
}
}

output "key_vault_id" {
description = "Azure resource ID of the Key Vault (only output exposed by this module)."
value = module.key_vault.id
}
6 changes: 6 additions & 0 deletions modules/azure-kv/_examples/comprehensive/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Comprehensive reference — `azure-kv`

- [`module.reference.hcl`](./module.reference.hcl) — Illustrative module block with **access policies** (direct `object_id` and Azure AD lookups by type/name).
- [`values.reference.yaml`](./values.reference.yaml) — Same inputs as YAML for `yamldecode` or external tooling.

These samples are documentation-oriented: replace names, IDs, and resource group with values valid in your tenant before apply. The variable type keeps `name` optional for compatibility, but each sample row uses a **distinct, non-empty `name`** because `main.tf` keys lookups by `name`. Keep large samples here instead of embedding them in the terraform-docs `README.md` body.
58 changes: 58 additions & 0 deletions modules/azure-kv/_examples/comprehensive/module.reference.hcl
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
# Same intent as values.reference.yaml, expressed as a module block.
# enable_rbac_authorization must be false when access_policies is non-empty.

module "key_vault" {
source = "../.."

name = "kv-myapp-ref01"
resource_group = "my-resource-group"
enabled_for_disk_encryption = true
soft_delete_retention_days = 7
purge_protection_enabled = true
sku_name = "standard"
enable_rbac_authorization = false

tags_from_rg = true
tags = {
extra = "from-module"
}

access_policies = [
{
name = "Name for the Object ID"
type = ""
object_id = "1a9590f4-27d3-4abf-9e30-5be7f46959bb"
key_permissions = ["Get", "List"]
secret_permissions = ["Get", "List"]
certificate_permissions = ["Get", "List"]
storage_permissions = ["Get", "List"]
},
{
name = "Group display name"
type = "group"
object_id = ""
key_permissions = ["Get", "List"]
secret_permissions = ["Get", "List"]
certificate_permissions = ["Get", "List"]
storage_permissions = ["Get", "List"]
},
{
name = "Service Principal display name"
type = "service_principal"
object_id = ""
key_permissions = ["Get", "List"]
secret_permissions = ["Get", "List"]
certificate_permissions = ["Get", "List"]
storage_permissions = ["Get", "List"]
},
{
name = "user@contoso.com"
type = "user"
object_id = ""
key_permissions = ["Get", "List"]
secret_permissions = ["Get", "List"]
certificate_permissions = ["Get", "List"]
storage_permissions = ["Get", "List"]
},
]
}
43 changes: 43 additions & 0 deletions modules/azure-kv/_examples/comprehensive/values.reference.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# Reference values for azure-kv (e.g. Helm / wrapper YAML).
# If enable_rbac_authorization is true, access_policies must be [].

values:
name: "kv-myapp-ref01"
tags_from_rg: true
tags:
extra: "from-yaml"
enabled_for_disk_encryption: true
resource_group: "my-resource-group"
soft_delete_retention_days: 7
purge_protection_enabled: true
sku_name: "standard"
enable_rbac_authorization: false
access_policies:
- name: "Name for the Object ID"
type: ""
object_id: "1a9590f4-27d3-4abf-9e30-5be7f46959bb"
key_permissions: ["Get", "List"]
secret_permissions: ["Get", "List"]
certificate_permissions: ["Get", "List"]
storage_permissions: ["Get", "List"]
- name: "Group display name"
type: "group"
object_id: ""
key_permissions: ["Get", "List"]
secret_permissions: ["Get", "List"]
certificate_permissions: ["Get", "List"]
storage_permissions: ["Get", "List"]
- name: "Service Principal display name"
type: "service_principal"
object_id: ""
key_permissions: ["Get", "List"]
secret_permissions: ["Get", "List"]
certificate_permissions: ["Get", "List"]
storage_permissions: ["Get", "List"]
- name: "user@contoso.com"
type: "user"
object_id: ""
key_permissions: ["Get", "List"]
secret_permissions: ["Get", "List"]
certificate_permissions: ["Get", "List"]
storage_permissions: ["Get", "List"]
24 changes: 24 additions & 0 deletions modules/azure-kv/docs/footer.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
## Examples

For detailed examples, refer to the [module examples](https://github.com/prefapp/tfm/tree/main/modules/azure-kv/_examples):

- [basic](https://github.com/prefapp/tfm/tree/main/modules/azure-kv/_examples/basic) — Key Vault with **RBAC** enabled and no access policies; set an existing resource group and a globally unique vault name (see folder README).
- [comprehensive](https://github.com/prefapp/tfm/tree/main/modules/azure-kv/_examples/comprehensive) — Reference HCL and YAML for **access policies** (object ID and Azure AD lookups) and tag options (`values.reference.yaml`; see folder README).

## Remote resources

Terraform **azurerm** links below use **4.21.0** as a baseline aligned with the minimum `azurerm` version in `versions.tf` (`>= 4.21.0`). **azuread** links use **2.53.0**, aligned with `versions.tf` (`~> 2.53.0`). Provider version constraints for your workspace appear in the **Providers** table above after regenerating this README with `terraform-docs .`, as described in [README.md generation](https://github.com/prefapp/tfm/blob/main/CONTRIBUTING.md#5-readmemd-generation).

- **Azure Key Vault**: [https://learn.microsoft.com/azure/key-vault/](https://learn.microsoft.com/azure/key-vault/)
- **azurerm_key_vault**: [https://registry.terraform.io/providers/hashicorp/azurerm/4.21.0/docs/resources/key_vault](https://registry.terraform.io/providers/hashicorp/azurerm/4.21.0/docs/resources/key_vault)
- **azurerm_client_config** (data source): [https://registry.terraform.io/providers/hashicorp/azurerm/4.21.0/docs/data-sources/client_config](https://registry.terraform.io/providers/hashicorp/azurerm/4.21.0/docs/data-sources/client_config)
- **azurerm_resource_group** (data source): [https://registry.terraform.io/providers/hashicorp/azurerm/4.21.0/docs/data-sources/resource_group](https://registry.terraform.io/providers/hashicorp/azurerm/4.21.0/docs/data-sources/resource_group)
- **azuread_user** (data source): [https://registry.terraform.io/providers/hashicorp/azuread/2.53.0/docs/data-sources/user](https://registry.terraform.io/providers/hashicorp/azuread/2.53.0/docs/data-sources/user)
- **azuread_group** (data source): [https://registry.terraform.io/providers/hashicorp/azuread/2.53.0/docs/data-sources/group](https://registry.terraform.io/providers/hashicorp/azuread/2.53.0/docs/data-sources/group)
- **azuread_service_principal** (data source): [https://registry.terraform.io/providers/hashicorp/azuread/2.53.0/docs/data-sources/service_principal](https://registry.terraform.io/providers/hashicorp/azuread/2.53.0/docs/data-sources/service_principal)
- **Terraform AzureRM provider**: [https://registry.terraform.io/providers/hashicorp/azurerm/4.21.0](https://registry.terraform.io/providers/hashicorp/azurerm/4.21.0)
- **Terraform AzureAD provider**: [https://registry.terraform.io/providers/hashicorp/azuread/2.53.0](https://registry.terraform.io/providers/hashicorp/azuread/2.53.0)

## Support

For issues, questions, or contributions related to this module, please visit the [repository's issue tracker](https://github.com/prefapp/tfm/issues).
103 changes: 103 additions & 0 deletions modules/azure-kv/docs/header.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
# **Azure Key Vault Terraform Module**

## Overview

This module creates an **Azure Key Vault** (`azurerm_key_vault`) in an **existing resource group**. It supports **Azure RBAC** on the vault or **classic access policies**, optional resolution of principals via **Azure AD** data sources (user, group, or service principal by display name or UPN), tag merge from the resource group, and lifecycle **preconditions** so access policies are not mixed with RBAC when that combination is invalid.

The module does **not** create the resource group, private endpoints, or key/secret/certificate resources; consumers add those separately if needed. Use it when you want a small, opinionated wrapper around `azurerm_key_vault` with consistent tagging and access-policy wiring for teams that still use vault access policies or are migrating toward vault-level RBAC.

## Key Features

- **Key Vault**: SKU, soft delete retention, purge protection, disk encryption integration, tenant binding.
- **Authorization model**: `enable_rbac_authorization` toggles between RBAC and access policies; when RBAC is enabled, `access_policies` must be empty.
- **Access policies**: Optional list; object fields remain optional in the type for compatibility. For real policies, use a **non-empty, unique `name`** per row (`main.tf` uses it as a `for_each` key and for Azure AD lookups). Use `type` (`user`, `group`, `service_principal`) plus `name`, or `object_id` with empty `type` for a direct principal.
- **Outputs**: Exposes the Key Vault **`id`** for downstream resources, role assignments, or references that need the Azure resource identifier.

## Prerequisites

- Existing **resource group** (`resource_group`); the module reads it for location and optional tag inheritance.
- **Key Vault name** must be **globally unique**, 3–24 characters, and use only letters, numbers, and hyphens.
- The module depends on **hashicorp/azuread** and **hashicorp/azurerm** (`versions.tf`); Terraform installs the required provider versions. Configure **`provider "azuread"`** with working credentials **only when** access policies use `type` `user`, `group`, or `service_principal` so the lookup data sources can run. For RBAC-only setups or policies that only set `object_id` (empty `type`), those data sources are not instantiated and you do not need Azure AD authentication for this module alone.
- For **access policies** with principal lookup, principals must exist and be resolvable (correct UPN, group display name, or service principal display name).

## Basic Usage

Point `source` at this module and set required inputs. Use **RBAC** (`enable_rbac_authorization = true`) with an empty `access_policies` list for the smallest surface, or **access policies** with `enable_rbac_authorization = false`.

### Example (RBAC on the vault)

```hcl
module "key_vault" {
source = "git::https://github.com/prefapp/tfm.git//modules/azure-kv?ref=<version>"

name = "kv-myapp-dev01"
resource_group = "my-resource-group"
enabled_for_disk_encryption = false
soft_delete_retention_days = 7
purge_protection_enabled = false
sku_name = "standard"
enable_rbac_authorization = true
access_policies = []

tags_from_rg = false
tags = {
environment = "dev"
}
}
```

Assign **Key Vault data plane** or **management** roles at vault scope or above when using RBAC; this module does not create role assignments.

### Example (access policies, RBAC disabled)

```hcl
module "key_vault_access_policies" {
source = "git::https://github.com/prefapp/tfm.git//modules/azure-kv?ref=<version>"

name = "kv-myapp-legacy01"
resource_group = "my-resource-group"
enabled_for_disk_encryption = false
soft_delete_retention_days = 7
purge_protection_enabled = false
sku_name = "standard"
enable_rbac_authorization = false

tags_from_rg = false
tags = {
environment = "dev"
}

access_policies = [
{
name = "workload-spn"
type = ""
object_id = "11111111-1111-1111-1111-111111111111"
key_permissions = ["Get", "List"]
secret_permissions = ["Get", "List"]
certificate_permissions = ["Get", "List"]
storage_permissions = ["Get", "List"]
},
]
}
```

Replace `object_id` with a real principal in your tenant. To resolve principals by **UPN / display name** instead, set `type` to `user`, `group`, or `service_principal` and set `name` accordingly; that path uses the Azure AD provider data sources.

## File structure

```
.
├── CHANGELOG.md
├── main.tf
├── outputs.tf
├── variables.tf
├── versions.tf
├── docs
│ ├── footer.md
│ └── header.md
├── _examples
│ ├── basic
│ └── comprehensive
├── README.md
└── .terraform-docs.yml
```
6 changes: 3 additions & 3 deletions modules/azure-kv/main.tf
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# DATA SECTION
## https://registry.terraform.io/providers/hashicorp/azurerm/3.113.0/docs/data-sources/client_config
## https://registry.terraform.io/providers/hashicorp/azurerm/4.21.0/docs/data-sources/client_config
data "azurerm_client_config" "current" {}

## https://registry.terraform.io/providers/hashicorp/azurerm/3.113.0/docs/data-sources/resource_group
## https://registry.terraform.io/providers/hashicorp/azurerm/4.21.0/docs/data-sources/resource_group
data "azurerm_resource_group" "this" {
name = var.resource_group
}
Expand Down Expand Up @@ -57,7 +57,7 @@ locals {


# RESOURCES SECTION
## https://registry.terraform.io/providers/hashicorp/azurerm/3.113.0/docs/resources/key_vault
## https://registry.terraform.io/providers/hashicorp/azurerm/4.21.0/docs/resources/key_vault
resource "azurerm_key_vault" "this" {
name = var.name
location = data.azurerm_resource_group.this.location
Expand Down
3 changes: 2 additions & 1 deletion modules/azure-kv/outputs.tf
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
output "id" {
value = azurerm_key_vault.this.id
description = "The Azure resource ID of the Key Vault."
value = azurerm_key_vault.this.id
}
Comment thread
pablosanchezpaz marked this conversation as resolved.
Loading