Skip to content

Commit d33c9bc

Browse files
committed
feat: add azure-acr module
1 parent 43a8563 commit d33c9bc

File tree

16 files changed

+543
-5
lines changed

16 files changed

+543
-5
lines changed

terraform/azure/aks/module/acr.tf

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,10 @@ resource "azurerm_role_assignment" "aks-cr" {
2323
skip_service_principal_aad_check = true
2424
}
2525

26+
data "azurerm_private_dns_zone" "acr" {
27+
name = "privatelink.azurecr.io"
28+
resource_group_name = local.resource_group_name
29+
}
2630

2731
resource "azurerm_private_endpoint" "aks-cr" {
2832
name = azurerm_container_registry.aks.name
@@ -38,11 +42,12 @@ resource "azurerm_private_endpoint" "aks-cr" {
3842
is_manual_connection = false
3943
}
4044

41-
# TODO ?
42-
# private_dns_zone_group {
43-
# name = "example-dns-zone-group"
44-
# private_dns_zone_ids = [azurerm_private_dns_zone.example.id]
45-
# }
45+
private_dns_zone_group {
46+
name = "acr-zonegroup"
47+
private_dns_zone_ids = [
48+
data.azurerm_private_dns_zone.acr.id
49+
]
50+
}
4651
}
4752

4853

terraform/azure/aro/Makefile

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,14 @@ get-sp-expiration-date: ## check ARO cluster ServicePrincipal credential expirat
5151
rotate-sp-credentials: ## automated ServicePrincipal credential rotation will check if the service principal exists and rotate or create a new service principal.
5252
az aro update --refresh-credentials --name $(CLUSTER_NAME) --resource-group $(CLUSTER_RG)
5353

54+
show-current-pull-secret: ## show current pull secret
55+
oc get secrets pull-secret -n openshift-config -o template='{{index .data ".dockerconfigjson"}}' | base64 -d
56+
57+
show-current-runtime-pull-secret: ## show current pull secret from runtime (kubelet config)
58+
oc exec -n openshift-apiserver `oc get pod -n openshift-apiserver -o jsonpath="{.items[0].metadata.name}"` -- cat /var/lib/kubelet/config.json
59+
60+
show-aro-entraid-callback: ## show ARO cluster's callback URL for Azure AD authentication (for use in Entra ID app registration)
61+
echo "$$(az aro show -g $(CLUSTER_RG) -n $(CLUSTER_NAME) --query consoleProfile.url -o tsv | sed 's/console-openshift-console/oauth-openshift/')oauth2callback/AAD"
5462

5563
show-state: ## show state
5664
cd stage/$(ENV) && terragrunt state list && terragrunt show

terraform/azure/azure-acr/Makefile

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
SHELL := /usr/bin/env bash
2+
.EXPORT_ALL_VARIABLES:
3+
4+
DEBUG := false
5+
ifeq ($(strip $(DEBUG)),true)
6+
TF_LOG := DEBUG
7+
TG_FLAGS := --inputs-debug
8+
endif
9+
10+
MODE := apply
11+
ifeq ($(strip $(MODE)),apply)
12+
MODE_STR := --non-interactive -- apply -auto-approve
13+
else ifeq ($(strip $(MODE)),destroy)
14+
MODE_STR := --non-interactive -- destroy -auto-approve
15+
else
16+
MODE_STR := --non-interactive -- plan
17+
endif
18+
19+
20+
ENV := dev-westeurope-shared1
21+
22+
init: init-tf-backend
23+
cd stage/$(ENV) && terragrunt run -- init -upgrade=true
24+
25+
26+
run: init ## setup ACR: make run [ENV=dev-northeurope-shared1] [MODE=apply]
27+
@cd stage/$(ENV) && terragrunt run validate && terragrunt run $(MODE_STR) $(TG_FLAGS)
28+
29+
acr-admin-login: ## login to ACR registry with docker admin credentials
30+
ACR_NAME="$$(cd stage/$(ENV) && terragrunt output -raw acr_name 2>/dev/null)" && \
31+
ACR_USERNAME="$$(cd stage/$(ENV) && terragrunt output -raw acr_username 2>/dev/null)" && \
32+
ACR_PASSWORD="$$(cd stage/$(ENV) && terragrunt output -raw acr_password 2>/dev/null)" && \
33+
docker login "$${ACR_NAME}.azurecr.io" \
34+
-u "$${ACR_USERNAME}" \
35+
-p "$${ACR_PASSWORD}"
36+
37+
acr-login: ## login to ACR registry
38+
RG="$$(cd stage/$(ENV) && terragrunt output -raw rg 2>/dev/null)" && \
39+
ACR_NAME="$$(cd stage/$(ENV) && terragrunt output -raw acr_name 2>/dev/null)" && \
40+
az acr login \
41+
--resource-group "$${RG}" \
42+
--name "$${ACR_NAME}"
43+
44+
get-container-registries: ## get names of configured container registries
45+
RG="$$(cd stage/$(ENV) && terragrunt output -raw rg 2>/dev/null)" && \
46+
az acr list \
47+
--resource-group "$${RG}" \
48+
--query "[].name" \
49+
-o tsv
50+
51+
make list-repositories: ## list repositories in ACR registry
52+
ACR_NAME="$$(cd stage/$(ENV) && terragrunt output -raw acr_name 2>/dev/null)" && \
53+
az acr repository list \
54+
--name "$${ACR_NAME}" \
55+
-o tsv
56+
57+
show-state: ## show state
58+
cd stage/$(ENV) && terragrunt state list && terragrunt show
59+
60+
clean: ## clean cached plugins and data
61+
find . -name ".terra*" -exec rm -rf {} +
62+
find . -name "target" -exec rm -rf {} +
63+
64+
upgrade-providers-version: init
65+
66+
init-tf-backend:
67+
cd stage && ./init_azurerm_tf_backend.sh
68+
69+
whoami: ## show current logon (tenant, subscription, user)
70+
@az account show
71+
72+
login: ## login to Azure Subscription
73+
az login
74+
75+
update-pull-secret: ## update ARO cluster pull secret with ACR credentials
76+
oc get secrets pull-secret -n openshift-config -o template='{{index .data ".dockerconfigjson"}}' | base64 -d > pull-secret.json
77+
ACR_NAME="$$(cd stage/$(ENV) && terragrunt output -raw acr_name 2>/dev/null)" && \
78+
ACR_USERNAME="$$(cd stage/$(ENV) && terragrunt output -raw acr_username 2>/dev/null)" && \
79+
ACR_PASSWORD="$$(cd stage/$(ENV) && terragrunt output -raw acr_password 2>/dev/null)" && \
80+
jq --arg acr "$${ACR_NAME}.azurecr.io" \
81+
--arg user "$${ACR_USERNAME}" \
82+
--arg pass "$${ACR_PASSWORD}" \
83+
'.auths += {($$acr): {"auth": ($$user + ":" + $$pass | @base64)}}' \
84+
pull-secret.json > pull-secret-modified.json && \
85+
oc set data secret/pull-secret -n openshift-config --from-file=.dockerconfigjson=./pull-secret-modified.json && \
86+
rm pull-secret.json pull-secret-modified.json
87+
88+
show-current-pull-secret: ## show current pull secret
89+
oc get secrets pull-secret -n openshift-config -o template='{{index .data ".dockerconfigjson"}}' | base64 -d
90+
91+
show-current-runtime-pull-secret: ## show current pull secret from runtime (kubelet config)
92+
oc exec -n openshift-apiserver `oc get pod -n openshift-apiserver -o jsonpath="{.items[0].metadata.name}"` -- cat /var/lib/kubelet/config.json
93+
94+
help: ## show usage and tasks (default)
95+
@eval $$(sed -E -n 's/^([\*\.a-zA-Z0-9_-]+):.*?## (.*)$$/printf "\\033[36m%-30s\\033[0m %s\\n" "\1" "\2" ;/; ta; b; :a p' $(MAKEFILE_LIST))
96+
.DEFAULT_GOAL := help
97+
.PHONY: help run clean
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
# Terraform :: AKS Classic
2+
3+
Setup Azure Container Registry (ACR)
4+
5+
* Azure RBAC (aka Azure EntraID) Roles to manage K8S RBAC, with EntraId group acting as cluster-admins
6+
7+
8+
## Prerequisites
9+
10+
* Latest Terragrunt/OpenTofu installed
11+
12+
* [Azure CLI](https://learn.microsoft.com/en-us/cli/azure/install-azure-cli-linux?pivots=apt)
13+
14+
* Azure Subscription.
15+
16+
* Logged to Azure Subscription:
17+
18+
```bash
19+
make login
20+
```
21+
22+
* Initialize Azure Storage Account and Container for keeping Terraform state
23+
24+
```bash
25+
make init
26+
```
27+
28+
* [../azure-entraid](../azure-entraid) - installed for the same stage environment (contains resource group and policies)
29+
30+
* Ensure networking is setup for evn and region: [../azure-network-setup](../azure-network-setup) - installed for the same stage environment and region
31+
Not all regions are compatible with AKS or contains desired VM sizes:
32+
33+
34+
## Usage
35+
36+
```bash
37+
# setup ACR registry
38+
make run MODE=apply [ENV=dev-westeurope-shared1]
39+
40+
# update pull secret in currently logged ARO cluster with credentials to this repo
41+
make update-pull-secret
42+
```
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
resource "azurerm_container_registry" "acr" {
2+
name = replace("${local.prefix}${var.name}", "-", "")
3+
location = local.location
4+
resource_group_name = local.resource_group_name
5+
sku = "Premium"
6+
zone_redundancy_enabled = true
7+
public_network_access_enabled = var.public
8+
9+
# whether to expose break-glass admin access to ACR, normally only EntraId access possible
10+
admin_enabled = var.admin_enabled
11+
12+
lifecycle {
13+
ignore_changes = [tags, ]
14+
}
15+
tags = var.tags
16+
}
17+
18+
data "azurerm_subnet" "private-endpoints-subnet" {
19+
name = "${data.azurerm_virtual_network.vnet.name}-${var.private_endpoints_subnet_suffix}"
20+
virtual_network_name = data.azurerm_virtual_network.vnet.name
21+
resource_group_name = local.resource_group_name
22+
}
23+
24+
data "azurerm_private_dns_zone" "acr" {
25+
name = "privatelink.azurecr.io"
26+
resource_group_name = local.resource_group_name
27+
}
28+
29+
resource "azurerm_private_endpoint" "acr" {
30+
name = azurerm_container_registry.acr.name
31+
location = local.location
32+
resource_group_name = local.resource_group_name
33+
subnet_id = data.azurerm_subnet.private-endpoints-subnet.id
34+
custom_network_interface_name = "nic${azurerm_container_registry.acr.name}"
35+
36+
private_service_connection {
37+
name = "config"
38+
private_connection_resource_id = azurerm_container_registry.acr.id
39+
subresource_names = ["registry"]
40+
is_manual_connection = false
41+
}
42+
43+
private_dns_zone_group {
44+
name = "acr-zonegroup"
45+
private_dns_zone_ids = [
46+
data.azurerm_private_dns_zone.acr.id
47+
]
48+
}
49+
50+
}
51+
52+
53+
output "acr_name" {
54+
value = azurerm_container_registry.acr.name
55+
}
56+
57+
output "acr_login_server" {
58+
value = azurerm_container_registry.acr.login_server
59+
}
60+
61+
# Available when admin=true, otherwise only EntraID access available
62+
#
63+
output "acr_username" {
64+
value = azurerm_container_registry.acr.admin_username
65+
}
66+
67+
output "acr_password" {
68+
value = azurerm_container_registry.acr.admin_password
69+
sensitive = true
70+
}
Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
data "azurerm_subscription" "current" {
2+
}
3+
4+
data "azurerm_resource_group" "rg" {
5+
name = var.env
6+
}
7+
8+
data "azurerm_virtual_network" "vnet" {
9+
name = "${local.prefix}-vnet"
10+
resource_group_name = local.resource_group_name
11+
}
12+
13+
locals {
14+
# tflint-ignore: terraform_unused_declarations
15+
subscription_id = data.azurerm_subscription.current.id
16+
resource_group_name = data.azurerm_resource_group.rg.name
17+
location = var.region
18+
19+
prefix = "${var.env}-${local.azure_region_abbreviations[var.region]}"
20+
subscription_name = data.azurerm_subscription.current.display_name
21+
azure_region_abbreviations = {
22+
"eastus" = "eus"
23+
"eastus2" = "eu2"
24+
"westus" = "wus"
25+
"westus2" = "wu2"
26+
"centralus" = "cus"
27+
"northeurope" = "neu"
28+
"westeurope" = "weu"
29+
"southeastasia" = "sea"
30+
"eastasia" = "eas"
31+
"australiaeast" = "aue"
32+
"australiasoutheast" = "aus"
33+
"japaneast" = "jpe"
34+
"japanwest" = "jpw"
35+
"canadacentral" = "cac"
36+
"canadaeast" = "cae"
37+
"germanywestcentral" = "gwc"
38+
"uksouth" = "uks"
39+
"ukwest" = "ukw"
40+
"polandcentral" = "plc"
41+
"brazilsouth" = "brs"
42+
"southafricanorth" = "san"
43+
"southafricasouth" = "sas"
44+
"francecentral" = "frc"
45+
"francesouth" = "frs"
46+
"uaecentral" = "uae"
47+
"uaenorth" = "uan"
48+
"koreacentral" = "kor"
49+
"koreasouth" = "kos"
50+
"swedencentral" = "swc"
51+
"swedensouth" = "sws"
52+
"norwayeast" = "noe"
53+
"norwaywest" = "now"
54+
"switzerlandnorth" = "swn"
55+
"switzerlandwest" = "sww"
56+
"italynorth" = "itn"
57+
"israelcentral" = "isc"
58+
"qatarcentral" = "qac"
59+
"spaincentral" = "spc"
60+
"newzealandnorth" = "nzn"
61+
"australiacentral" = "auc"
62+
"australiacentral2" = "au2"
63+
"mexicocentral" = "mxc"
64+
"indiacentral" = "inc"
65+
"indiaseast" = "ise"
66+
"indiasouth" = "iss"
67+
"indiasouth" = "isw"
68+
"japanwest" = "jpw"
69+
"chinanorth" = "chn"
70+
"chinaeast" = "che"
71+
"chinaeast2" = "ch2"
72+
"chinanorth2" = "ch3"
73+
"chinanorth3" = "ch4"
74+
"germanycentral" = "gmc"
75+
"germanynortheast" = "gne"
76+
"usgovarizona" = "uga"
77+
"usgovtexas" = "ugt"
78+
"usgovvirginia" = "ugv"
79+
"usgovpennsylvania" = "ugp"
80+
"usdodeast" = "ude"
81+
"usdodcentral" = "udc"
82+
"usgovarizona" = "uga"
83+
"usgovtexas" = "ugt"
84+
"usgovvirginia" = "ugv"
85+
"usgovpennsylvania" = "ugp"
86+
"usdodeast" = "ude"
87+
"usdodcentral" = "udc"
88+
}
89+
}
90+
91+
variable "env" {
92+
description = "Environment name"
93+
type = string
94+
}
95+
96+
variable "region" {
97+
description = "Azure region"
98+
type = string
99+
}
100+
101+
variable "name" {
102+
description = "Name of the Azure Container Registry"
103+
type = string
104+
default = "acr"
105+
}
106+
107+
108+
variable "admin_enabled" {
109+
description = "Enable admin user for the Azure Container Registry"
110+
type = bool
111+
default = false
112+
}
113+
114+
115+
variable "public" {
116+
description = "Expose ACR to public network, otherwise only private endpoint access possible"
117+
type = bool
118+
default = false
119+
}
120+
121+
variable "private_endpoints_subnet_suffix" {
122+
type = string
123+
description = "Name of subnet for private endpoints"
124+
}
125+
126+
127+
variable "tags" {
128+
description = "Tags to apply to resources"
129+
type = map(string)
130+
default = {}
131+
}
132+
133+
output "rg" {
134+
value = local.resource_group_name
135+
}

0 commit comments

Comments
 (0)