Skip to content

Commit 3f965c3

Browse files
authored
Merge pull request #82 from meshcloud/feature/acr
Feature/acr
2 parents 2008030 + 2832702 commit 3f965c3

File tree

19 files changed

+2153
-2
lines changed

19 files changed

+2153
-2
lines changed

.gitignore

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@ yarn-error.log*
1515
*.iml
1616
.angular/
1717

18-
.terraform
18+
*.terraform*
19+
*.tfstate*
20+
*tfvars*
21+
1922
.terraform.lock.hcl
20-
.env
23+
.env

modules/AGENTS.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,14 @@ aws/
9999
- Creates custom role definitions with specific permissions
100100
- Uses role assignments for principal access
101101
- Scoped to subscription or management group level
102+
- **Service Principal Creation (Optional):**
103+
- Can create Azure AD application and service principal
104+
- Supports **Workload Identity Federation (WIF)** for passwordless authentication
105+
- Falls back to application password if WIF not configured
106+
- Automatically assigns created principals to role definitions
107+
- **Two-tier permissions for networking:**
108+
- `buildingblock_deploy` role: Main deployment permissions
109+
- `buildingblock_deploy_hub` role: Hub-specific permissions for VNet peering (e.g., ACR, Key Vault)
102110

103111
**GCP Backplane Pattern:** *TBD - To be documented*
104112

@@ -232,10 +240,12 @@ category: storage
232240

233241
- **Cost Management:** Budget alerts (AWS, Azure, GCP)
234242
- **Storage:** S3 buckets, Azure storage accounts, GCS buckets
243+
- **Container Registries:** Azure Container Registry (ACR) with private networking
235244
- **Networking:** VPCs, spoke networks, subnets
236245
- **Databases:** PostgreSQL, managed database instances
237246
- **Security:** Key Vault, IAM roles, secret management
238247
- **CI/CD:** GitHub Actions integration, service connections
248+
- **Compute:** Virtual machines (Azure), AKS integration
239249

240250
## Best Practices for New Modules
241251

Lines changed: 201 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,201 @@
1+
# Azure Container Registry Building Block - Backplane
2+
3+
This directory contains the "backplane" configuration for the Azure Container Registry Building Block. The backplane sets up the necessary permissions and service principals required to deploy Azure Container Registries in Azure subscriptions.
4+
5+
## Overview
6+
7+
The backplane creates:
8+
- Custom Azure RBAC role definitions with ACR deployment permissions
9+
- Optional service principal for automated deployments (main scope)
10+
- **Optional separate service principal for hub VNet peering (least privilege)**
11+
- Role assignments for the service principals or existing principals
12+
- Support for workload identity federation or application passwords
13+
- Separate scopes: main scope (subscription or management group) and hub scope (subscription or management group)
14+
15+
## Required Permissions
16+
17+
The backplane creates two role definitions:
18+
19+
### Main Deployment Role (`buildingblock_deploy`)
20+
21+
Grants the following permissions:
22+
23+
#### Container Registry
24+
- Full CRUD operations on registries
25+
- Manage credentials, webhooks, replications, scope maps, and tokens
26+
- Import images
27+
28+
#### Networking
29+
- Create and manage private endpoints
30+
- Create and manage private DNS zones and records
31+
- Create and manage virtual networks, subnets, and VNet peerings
32+
- Join subnets and peer VNets
33+
34+
#### Resource Management
35+
- Create, read, and delete resource groups
36+
- Manage deployments
37+
- Assign roles (for AKS integration)
38+
39+
### Hub Deployment Role (`buildingblock_deploy_hub`)
40+
41+
Limited permissions for hub VNet peering:
42+
- Read resource groups and virtual networks
43+
- Manage virtual network peerings
44+
45+
## Usage
46+
47+
Choose ONE of the following authentication methods:
48+
49+
### Option 1: Workload Identity Federation (Recommended)
50+
51+
Best for GitHub Actions, Azure DevOps, and other OIDC-capable CI/CD systems. No secrets to manage.
52+
53+
```hcl
54+
module "acr_backplane" {
55+
source = "./backplane"
56+
57+
name = "container-registry"
58+
scope = "/providers/Microsoft.Management/managementGroups/landing-zones"
59+
hub_scope = "/subscriptions/00000000-0000-0000-0000-000000000000"
60+
61+
# Create main service principal with WIF
62+
create_service_principal_name = "acr-deployer"
63+
workload_identity_federation = {
64+
issuer = "https://token.actions.githubusercontent.com"
65+
subject = "repo:your-org/your-repo:ref:refs/heads/main"
66+
}
67+
68+
# Create separate hub service principal with WIF (least privilege)
69+
create_hub_service_principal_name = "acr-hub-peering"
70+
hub_workload_identity_federation = {
71+
issuer = "https://token.actions.githubusercontent.com"
72+
subject = "repo:your-org/your-repo:ref:refs/heads/main"
73+
}
74+
}
75+
```
76+
77+
### Option 2: Using Existing Service Principals
78+
79+
Use this when you already have service principals created and managed externally.
80+
81+
```hcl
82+
module "acr_backplane" {
83+
source = "./backplane"
84+
85+
name = "container-registry"
86+
scope = "/providers/Microsoft.Management/managementGroups/landing-zones"
87+
hub_scope = "/subscriptions/00000000-0000-0000-0000-000000000000"
88+
89+
# Provide object IDs of existing service principals
90+
existing_principal_ids = ["00000000-0000-0000-0000-000000000001"]
91+
existing_hub_principal_ids = ["00000000-0000-0000-0000-000000000002"]
92+
}
93+
```
94+
95+
### Option 3: Password Authentication (Not Recommended)
96+
97+
Only use when WIF is not available. Requires secure password management.
98+
99+
```hcl
100+
module "acr_backplane" {
101+
source = "./backplane"
102+
103+
name = "container-registry"
104+
scope = "/providers/Microsoft.Management/managementGroups/landing-zones"
105+
hub_scope = "/subscriptions/00000000-0000-0000-0000-000000000000"
106+
107+
# Create service principals with password authentication
108+
create_service_principal_name = "acr-deployer"
109+
create_hub_service_principal_name = "acr-hub-peering"
110+
111+
# Do NOT set workload_identity_federation - passwords will be auto-generated
112+
# Retrieve passwords from Terraform state or Azure portal
113+
}
114+
```
115+
116+
## Security Considerations
117+
118+
- The role definitions follow the principle of least privilege
119+
- Service principals should use workload identity federation when possible
120+
- Passwords are marked as sensitive and not exposed in outputs
121+
- Review the permissions before deploying to production environments
122+
- The hub role has minimal permissions for VNet peering only
123+
124+
<!-- BEGIN_TF_DOCS -->
125+
## Requirements
126+
127+
| Name | Version |
128+
|------|---------|
129+
| <a name="requirement_terraform"></a> [terraform](#requirement\_terraform) | >= 1.3.0 |
130+
| <a name="requirement_azuread"></a> [azuread](#requirement\_azuread) | ~> 3.6.0 |
131+
| <a name="requirement_azurerm"></a> [azurerm](#requirement\_azurerm) | ~> 4.36.0 |
132+
133+
## Modules
134+
135+
No modules.
136+
137+
## Resources
138+
139+
| Name | Type |
140+
|------|------|
141+
| [azuread_application.buildingblock_deploy](https://registry.terraform.io/providers/hashicorp/azuread/latest/docs/resources/application) | resource |
142+
| [azuread_application.buildingblock_deploy_hub](https://registry.terraform.io/providers/hashicorp/azuread/latest/docs/resources/application) | resource |
143+
| [azuread_application_federated_identity_credential.buildingblock_deploy](https://registry.terraform.io/providers/hashicorp/azuread/latest/docs/resources/application_federated_identity_credential) | resource |
144+
| [azuread_application_federated_identity_credential.buildingblock_deploy_hub](https://registry.terraform.io/providers/hashicorp/azuread/latest/docs/resources/application_federated_identity_credential) | resource |
145+
| [azuread_application_password.buildingblock_deploy](https://registry.terraform.io/providers/hashicorp/azuread/latest/docs/resources/application_password) | resource |
146+
| [azuread_application_password.buildingblock_deploy_hub](https://registry.terraform.io/providers/hashicorp/azuread/latest/docs/resources/application_password) | resource |
147+
| [azuread_service_principal.buildingblock_deploy](https://registry.terraform.io/providers/hashicorp/azuread/latest/docs/resources/service_principal) | resource |
148+
| [azuread_service_principal.buildingblock_deploy_hub](https://registry.terraform.io/providers/hashicorp/azuread/latest/docs/resources/service_principal) | resource |
149+
| [azurerm_role_assignment.created_principal](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/role_assignment) | resource |
150+
| [azurerm_role_assignment.created_principal_hub](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/role_assignment) | resource |
151+
| [azurerm_role_assignment.created_principal_hub_to_landingzone](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/role_assignment) | resource |
152+
| [azurerm_role_assignment.created_principal_landingzone_to_hub](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/role_assignment) | resource |
153+
| [azurerm_role_assignment.existing_principals](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/role_assignment) | resource |
154+
| [azurerm_role_assignment.existing_principals_hub](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/role_assignment) | resource |
155+
| [azurerm_role_assignment.existing_principals_hub_to_landingzone](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/role_assignment) | resource |
156+
| [azurerm_role_assignment.existing_principals_landingzone_to_hub](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/role_assignment) | resource |
157+
| [azurerm_role_definition.buildingblock_deploy](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/role_definition) | resource |
158+
| [azurerm_role_definition.buildingblock_deploy_hub](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/role_definition) | resource |
159+
| [azurerm_role_definition.buildingblock_hub_to_landingzone](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/role_definition) | resource |
160+
| [azurerm_role_definition.buildingblock_landingzone_to_hub](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/role_definition) | resource |
161+
| [azurerm_subscription.current](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/data-sources/subscription) | data source |
162+
163+
## Inputs
164+
165+
| Name | Description | Type | Default | Required |
166+
|------|-------------|------|---------|:--------:|
167+
| <a name="input_create_hub_service_principal_name"></a> [create\_hub\_service\_principal\_name](#input\_create\_hub\_service\_principal\_name) | name of a separate service principal to create for hub VNet peering (least privilege) | `string` | `null` | no |
168+
| <a name="input_create_service_principal_name"></a> [create\_service\_principal\_name](#input\_create\_service\_principal\_name) | name of a service principal to create and grant permissions to deploy the building block | `string` | `null` | no |
169+
| <a name="input_existing_hub_principal_ids"></a> [existing\_hub\_principal\_ids](#input\_existing\_hub\_principal\_ids) | set of existing principal ids that will be granted permissions to peer with the hub VNet | `set(string)` | `[]` | no |
170+
| <a name="input_existing_principal_ids"></a> [existing\_principal\_ids](#input\_existing\_principal\_ids) | set of existing principal ids that will be granted permissions to deploy the building block | `set(string)` | `[]` | no |
171+
| <a name="input_hub_scope"></a> [hub\_scope](#input\_hub\_scope) | Scope for hub VNet peering permissions (management group or subscription). Typically a hub subscription, but can be a management group containing hub resources. | `string` | n/a | yes |
172+
| <a name="input_hub_workload_identity_federation"></a> [hub\_workload\_identity\_federation](#input\_hub\_workload\_identity\_federation) | Configuration for workload identity federation for hub service principal. If not provided, an application password will be created instead. | <pre>object({<br> issuer = string<br> subject = string<br> })</pre> | `null` | no |
173+
| <a name="input_name"></a> [name](#input\_name) | name of the building block, used for naming resources | `string` | `"container-registry"` | no |
174+
| <a name="input_scope"></a> [scope](#input\_scope) | Scope where the building block should be deployable (management group or subscription), typically the parent of all Landing Zones. | `string` | n/a | yes |
175+
| <a name="input_workload_identity_federation"></a> [workload\_identity\_federation](#input\_workload\_identity\_federation) | Configuration for workload identity federation. If not provided, an application password will be created instead. | <pre>object({<br> issuer = string<br> subject = string<br> })</pre> | `null` | no |
176+
177+
## Outputs
178+
179+
| Name | Description |
180+
|------|-------------|
181+
| <a name="output_application_password"></a> [application\_password](#output\_application\_password) | Information about the created application password (excludes the actual password value for security). |
182+
| <a name="output_created_application"></a> [created\_application](#output\_created\_application) | Information about the created Azure AD application. |
183+
| <a name="output_created_hub_application"></a> [created\_hub\_application](#output\_created\_hub\_application) | Information about the created hub Azure AD application. |
184+
| <a name="output_created_hub_service_principal"></a> [created\_hub\_service\_principal](#output\_created\_hub\_service\_principal) | Information about the created hub service principal. |
185+
| <a name="output_created_service_principal"></a> [created\_service\_principal](#output\_created\_service\_principal) | Information about the created service principal. |
186+
| <a name="output_documentation_md"></a> [documentation\_md](#output\_documentation\_md) | Markdown documentation with information about the Container Registry Building Block backplane |
187+
| <a name="output_hub_application_password"></a> [hub\_application\_password](#output\_hub\_application\_password) | Information about the created hub application password (excludes the actual password value for security). |
188+
| <a name="output_hub_role_assignment_ids"></a> [hub\_role\_assignment\_ids](#output\_hub\_role\_assignment\_ids) | The IDs of the hub role assignments for all service principals. |
189+
| <a name="output_hub_role_assignment_principal_ids"></a> [hub\_role\_assignment\_principal\_ids](#output\_hub\_role\_assignment\_principal\_ids) | The principal IDs of all service principals that have been assigned the hub role. |
190+
| <a name="output_hub_role_definition_id"></a> [hub\_role\_definition\_id](#output\_hub\_role\_definition\_id) | The ID of the role definition that enables deployment of the building block to the hub. |
191+
| <a name="output_hub_role_definition_name"></a> [hub\_role\_definition\_name](#output\_hub\_role\_definition\_name) | The name of the role definition that enables deployment of the building block to the hub. |
192+
| <a name="output_hub_scope"></a> [hub\_scope](#output\_hub\_scope) | The scope (management group or subscription) where VNet peering role is applied. |
193+
| <a name="output_hub_workload_identity_federation"></a> [hub\_workload\_identity\_federation](#output\_hub\_workload\_identity\_federation) | Information about the created hub workload identity federation credential. |
194+
| <a name="output_provider_tf"></a> [provider\_tf](#output\_provider\_tf) | Ready-to-use provider.tf configuration for buildingblock deployment |
195+
| <a name="output_role_assignment_ids"></a> [role\_assignment\_ids](#output\_role\_assignment\_ids) | The IDs of the role assignments for all service principals. |
196+
| <a name="output_role_assignment_principal_ids"></a> [role\_assignment\_principal\_ids](#output\_role\_assignment\_principal\_ids) | The principal IDs of all service principals that have been assigned the role. |
197+
| <a name="output_role_definition_id"></a> [role\_definition\_id](#output\_role\_definition\_id) | The ID of the role definition that enables deployment of the building block. |
198+
| <a name="output_role_definition_name"></a> [role\_definition\_name](#output\_role\_definition\_name) | The name of the role definition that enables deployment of the building block. |
199+
| <a name="output_scope"></a> [scope](#output\_scope) | The scope where the role definition and role assignments are applied. |
200+
| <a name="output_workload_identity_federation"></a> [workload\_identity\_federation](#output\_workload\_identity\_federation) | Information about the created workload identity federation credential. |
201+
<!-- END_TF_DOCS -->
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
output "documentation_md" {
2+
value = <<EOF
3+
# Container Registry Building Block
4+
5+
The Container Registry Building Block configures an Azure Container Registry (ACR) with optional private networking for your subscriptions.
6+
7+
## Automation
8+
9+
We automate the deployment of a Container Registry Building Block using the common [Azure Building Blocks Automation Infrastructure](../automation.md).
10+
In order to deploy this building block, this infrastructure receives the following roles.
11+
12+
| Role Name | Description | Permissions |
13+
|-----------|-------------|-------------|
14+
| `${azurerm_role_definition.buildingblock_deploy.name}` | ${azurerm_role_definition.buildingblock_deploy.description} | ${join("<br>", formatlist("- `%s`", azurerm_role_definition.buildingblock_deploy.permissions[0].actions))} |
15+
| `${azurerm_role_definition.buildingblock_deploy_hub.name}` | ${azurerm_role_definition.buildingblock_deploy_hub.description} | ${join("<br>", formatlist("- `%s`", azurerm_role_definition.buildingblock_deploy_hub.permissions[0].actions))} |
16+
17+
EOF
18+
description = "Markdown documentation with information about the Container Registry Building Block backplane"
19+
}

0 commit comments

Comments
 (0)