Managing Azure Container Registry with Terraform
Learn how to set up and manage Azure Container Registry using Terraform, including replication, security, and CI/CD integration
Managing Azure Container Registry with Terraform
Azure Container Registry (ACR) is a managed Docker registry service. This guide demonstrates how to set up and manage ACR using Terraform.
Video Tutorial
Learn more about managing Azure Container Registry with Terraform in this comprehensive video tutorial:
Prerequisites
- Azure CLI configured with appropriate permissions
- Terraform installed (version 1.0.0 or later)
- Resource group created
- Understanding of container concepts
Project Structure
terraform-azure-acr/
├── main.tf
├── variables.tf
├── outputs.tf
├── modules/
│ └── acr/
│ ├── main.tf
│ ├── variables.tf
│ └── outputs.tf
└── policies/
└── security.json
Container Registry Configuration
Create modules/acr/main.tf
:
# Container Registry
resource "azurerm_container_registry" "main" {
name = "${var.project_name}acr"
resource_group_name = var.resource_group_name
location = var.location
sku = "Premium"
admin_enabled = false
georeplications {
location = var.secondary_location
zone_redundancy_enabled = true
tags = var.tags
}
network_rule_set {
default_action = "Deny"
ip_rule {
action = "Allow"
ip_range = var.allowed_ip_range
}
virtual_network {
action = "Allow"
subnet_id = azurerm_subnet.acr.id
}
}
retention_policy {
days = 7
enabled = true
}
trust_policy {
enabled = true
}
encryption {
enabled = true
key_vault_key_id = azurerm_key_vault_key.acr.id
identity_client_id = azurerm_user_assigned_identity.acr.client_id
}
identity {
type = "UserAssigned"
identity_ids = [azurerm_user_assigned_identity.acr.id]
}
zone_redundancy_enabled = true
public_network_access_enabled = false
quarantine_policy_enabled = true
tags = var.tags
}
# Replications
resource "azurerm_container_registry_replication" "main" {
for_each = var.replication_locations
location = each.key
container_registry_id = azurerm_container_registry.main.id
zone_redundancy_enabled = true
tags = var.tags
}
# Webhook
resource "azurerm_container_registry_webhook" "main" {
name = "${var.project_name}-webhook"
resource_group_name = var.resource_group_name
registry_name = azurerm_container_registry.main.name
location = var.location
service_uri = var.webhook_uri
status = "enabled"
scope = "myapp:*"
actions = ["push"]
custom_headers = {
"Content-Type" = "application/json"
}
}
# Task
resource "azurerm_container_registry_task" "main" {
name = "${var.project_name}-task"
container_registry_id = azurerm_container_registry.main.id
platform {
os = "Linux"
}
docker_step {
dockerfile_path = "Dockerfile"
context_path = "https://github.com/your-org/your-repo#main"
context_access_token = var.github_token
image_names = ["myapp:{{.Run.ID}}", "myapp:latest"]
}
timer_trigger {
name = "daily"
schedule = "0 0 * * *"
}
source_trigger {
name = "source-trigger"
events = ["commit"]
repository_url = "https://github.com/your-org/your-repo"
source_type = "Github"
branch = "main"
}
identity {
type = "UserAssigned"
identity_ids = [azurerm_user_assigned_identity.acr.id]
}
agent_pool_name = "S1"
}
# Scope Map
resource "azurerm_container_registry_scope_map" "main" {
name = "${var.project_name}-scope-map"
container_registry_name = azurerm_container_registry.main.name
resource_group_name = var.resource_group_name
actions = [
"repositories/myapp/content/read",
"repositories/myapp/content/write"
]
}
# Token
resource "azurerm_container_registry_token" "main" {
name = "${var.project_name}-token"
container_registry_name = azurerm_container_registry.main.name
resource_group_name = var.resource_group_name
scope_map_id = azurerm_container_registry_scope_map.main.id
status = "enabled"
}
Network Configuration
- Virtual Network Integration
resource "azurerm_virtual_network" "main" {
name = "${var.project_name}-vnet"
location = var.location
resource_group_name = var.resource_group_name
address_space = ["10.0.0.0/16"]
subnet {
name = "acr-subnet"
address_prefix = "10.0.1.0/24"
service_endpoints = ["Microsoft.ContainerRegistry"]
}
tags = var.tags
}
resource "azurerm_private_endpoint" "acr" {
name = "${var.project_name}-pe"
location = var.location
resource_group_name = var.resource_group_name
subnet_id = azurerm_virtual_network.main.subnet.*.id[0]
private_service_connection {
name = "${var.project_name}-psc"
private_connection_resource_id = azurerm_container_registry.main.id
is_manual_connection = false
subresource_names = ["registry"]
}
private_dns_zone_group {
name = "default"
private_dns_zone_ids = [azurerm_private_dns_zone.acr.id]
}
}
resource "azurerm_private_dns_zone" "acr" {
name = "privatelink.azurecr.io"
resource_group_name = var.resource_group_name
}
resource "azurerm_private_dns_zone_virtual_network_link" "acr" {
name = "${var.project_name}-vnet-link"
resource_group_name = var.resource_group_name
private_dns_zone_name = azurerm_private_dns_zone.acr.name
virtual_network_id = azurerm_virtual_network.main.id
}
Security Configuration
- Role Assignments
resource "azurerm_role_assignment" "acr_pull" {
scope = azurerm_container_registry.main.id
role_definition_name = "AcrPull"
principal_id = var.aks_principal_id
}
resource "azurerm_role_assignment" "acr_push" {
scope = azurerm_container_registry.main.id
role_definition_name = "AcrPush"
principal_id = var.cicd_principal_id
}
- Managed Identity
resource "azurerm_user_assigned_identity" "acr" {
name = "${var.project_name}-identity"
resource_group_name = var.resource_group_name
location = var.location
}
resource "azurerm_key_vault_access_policy" "acr" {
key_vault_id = var.key_vault_id
tenant_id = data.azurerm_client_config.current.tenant_id
object_id = azurerm_user_assigned_identity.acr.principal_id
key_permissions = [
"Get",
"UnwrapKey",
"WrapKey"
]
}
resource "azurerm_key_vault_key" "acr" {
name = "${var.project_name}-key"
key_vault_id = var.key_vault_id
key_type = "RSA"
key_size = 2048
key_opts = [
"decrypt",
"encrypt",
"sign",
"unwrapKey",
"verify",
"wrapKey",
]
}
Monitoring Configuration
- Diagnostic Settings
resource "azurerm_monitor_diagnostic_setting" "acr" {
name = "${var.project_name}-diag"
target_resource_id = azurerm_container_registry.main.id
log_analytics_workspace_id = var.log_analytics_workspace_id
log {
category = "ContainerRegistryRepositoryEvents"
enabled = true
retention_policy {
enabled = true
days = 30
}
}
metric {
category = "AllMetrics"
enabled = true
retention_policy {
enabled = true
days = 30
}
}
}
resource "azurerm_monitor_metric_alert" "acr" {
name = "${var.project_name}-storage-alert"
resource_group_name = var.resource_group_name
scopes = [azurerm_container_registry.main.id]
description = "Alert when storage usage is high"
criteria {
metric_namespace = "Microsoft.ContainerRegistry/registries"
metric_name = "StorageUsed"
aggregation = "Average"
operator = "GreaterThan"
threshold = 80
}
action {
action_group_id = var.action_group_id
}
}
Advanced Features
- Content Trust
resource "azurerm_container_registry" "trusted" {
# ... other configuration ...
trust_policy {
enabled = true
}
identity {
type = "UserAssigned"
identity_ids = [azurerm_user_assigned_identity.acr.id]
}
}
- Agent Pool
resource "azurerm_container_registry_agent_pool" "main" {
name = "${var.project_name}-pool"
resource_group_name = var.resource_group_name
location = var.location
container_registry_name = azurerm_container_registry.main.name
tier = "S1"
virtual_network_subnet_id = azurerm_subnet.acr.id
}
Best Practices
-
Performance
- Use geo-replication
- Enable zone redundancy
- Configure caching
- Use Premium SKU
-
Security
- Disable admin access
- Use RBAC
- Enable encryption
- Implement network isolation
-
CI/CD Integration
- Use webhooks
- Configure tasks
- Implement scanning
- Set up automated builds
-
Cost Optimization
- Clean up old images
- Monitor storage usage
- Use appropriate SKU
- Implement retention policies
Cost Optimization
- Resource Optimization
- Use appropriate SKU
- Implement retention policies
Conclusion
You’ve learned how to set up and manage Azure Container Registry using Terraform. This setup provides:
- Secure container storage
- Global replication
- CI/CD integration
- Monitoring and alerts
Remember to:
- Monitor storage usage
- Review security settings
- Clean up old images
- Update access controls