How to configure an Azure app service to pull images from an ACR with terraform?
Asked Answered
H

3

10

I have the following terraform module to setup app services under the same plan:

provider "azurerm" {
}

variable "env" {
    type = string
    description = "The SDLC environment (qa, dev, prod, etc...)"
}

variable "appsvc_names" {
    type = list(string)
    description = "The names of the app services to create under the same app service plan"
}

locals {
    location = "eastus2"
    resource_group_name = "app505-dfpg-${var.env}-web-${local.location}"
    acr_name = "app505dfpgnedeploycr88836"
}

resource "azurerm_app_service_plan" "asp" {
    name                = "${local.resource_group_name}-asp"
    location            = local.location
    resource_group_name = local.resource_group_name
    kind                = "Linux"
    reserved            = true

    sku {
        tier = "Basic"
        size = "B1"
    }
}

resource "azurerm_app_service" "appsvc" {
    for_each            = toset(var.appsvc_names)

    name                = "${local.resource_group_name}-${each.value}-appsvc"
    location            = local.location
    resource_group_name = local.resource_group_name
    app_service_plan_id = azurerm_app_service_plan.asp.id

    site_config {
        linux_fx_version = "DOCKER|${local.acr_name}/${each.value}:latest"
    }

    app_settings = {
        DOCKER_REGISTRY_SERVER_URL = "https://${local.acr_name}.azurecr.io"
    } 
}

output "hostnames" {
  value = {
    for appsvc in azurerm_app_service.appsvc: appsvc.name => appsvc.default_site_hostname
  }
}

I am invoking it through the following configuration:

terraform {
    backend "azurerm" {
    }
}

locals {
    appsvc_names = ["gateway"]
}

module "web" {
    source = "../../modules/web"
    env = "qa"
    appsvc_names = local.appsvc_names
}

output "hostnames" {
    description = "The hostnames of the created app services"
    value       = module.web.hostnames
}

The container registry has the images I need:

C:\> az acr login --name app505dfpgnedeploycr88836
Login Succeeded
C:\> az acr repository list  --name app505dfpgnedeploycr88836
[
  "gateway"
]
C:\> az acr repository show-tags --name app505dfpgnedeploycr88836 --repository gateway
[
  "latest"
]
C:\>

When I apply the terraform configuration everything is created fine, but inspecting the created app service resource in Azure Portal reveals that its Container Settings show no docker image:

enter image description here

Now, I can manually switch to another ACR and then back to the one I want only to get this:

enter image description here

Cannot perform credential operations for /subscriptions/0f1c414a-a389-47df-aab8-a351876ecd47/resourceGroups/app505-dfpg-ne-deploy-eastus2/providers/Microsoft.ContainerRegistry/registries/app505dfpgnedeploycr88836 as admin user is disabled. Kindly enable admin user as per docs: https://learn.microsoft.com/en-us/azure/container-registry/container-registry-authentication#admin-account

This is confusing me. According to https://learn.microsoft.com/en-us/azure/container-registry/container-registry-authentication#admin-account the admin user should not be used and so my ACR does not have one. On the other hand, I understand that I need somehow configure the app service to authenticate with the ACR.

What is the right way to do it then?

Hexahedron answered 25/1, 2020 at 23:48 Comment(0)
I
11

So this is now possible since the v2.71 version of the Azure RM provider. A couple of things have to happen...

  1. Assign a Managed Identity to the application (can also use User Assigned but a bit more work)
  2. Set the site_config.acr_use_managed_identity_credentials property to true
  3. Grant the application's identity ACRPull rights on the container.

Below is a modified version of the code above, not tested but should be ok

provider "azurerm" {
}

variable "env" {
    type = string
    description = "The SDLC environment (qa, dev, prod, etc...)"
}

variable "appsvc_names" {
    type = list(string)
    description = "The names of the app services to create under the same app service plan"
}

locals {
    location = "eastus2"
    resource_group_name = "app505-dfpg-${var.env}-web-${local.location}"
    acr_name = "app505dfpgnedeploycr88836"
}

resource "azurerm_app_service_plan" "asp" {
    name                = "${local.resource_group_name}-asp"
    location            = local.location
    resource_group_name = local.resource_group_name
    kind                = "Linux"
    reserved            = true

    sku {
        tier = "Basic"
        size = "B1"
    }
}

resource "azurerm_app_service" "appsvc" {
    for_each            = toset(var.appsvc_names)

    name                = "${local.resource_group_name}-${each.value}-appsvc"
    location            = local.location
    resource_group_name = local.resource_group_name
    app_service_plan_id = azurerm_app_service_plan.asp.id

    site_config {
        linux_fx_version = "DOCKER|${local.acr_name}/${each.value}:latest"
        acr_use_managed_identity_credentials = true
    }

    app_settings = {
        DOCKER_REGISTRY_SERVER_URL = "https://${local.acr_name}.azurecr.io"
    }

    identity {
        type = "SystemAssigned"
    }   
}

data "azurerm_container_registry" "this" {
  name                = local.acr_name
  resource_group_name = local.resource_group_name
}

resource "azurerm_role_assignment" "acr" {
  for_each             = azurerm_app_service.appsvc
  
  role_definition_name = "AcrPull"
  scope                = azurerm_container_registry.this.id
  principal_id         = each.value.identity[0].principal_id
}

output "hostnames" {
  value = {
    for appsvc in azurerm_app_service.appsvc: appsvc.name => appsvc.default_site_hostname
  }
}

EDITED 21 Dec 2021 The MS documentation issue regarding the value being reset by Azure has now been resolved and you can also control Managed Identity via the portal.

Itch answered 9/10, 2021 at 11:22 Comment(2)
Might be worth mentioning that there is an ongoing issue with ACR authentication using system-assigned identities. github.com/MicrosoftDocs/azure-docs/issues/64660Groats
@Groats That's what the paragraph (and link) below the sample code is referring to - latest info is that all regions apart from West Europe and South Central US are patched and won't have the reset issue, will update once all regions are fixedItch
J
5

So you can use service principal auth with App Service, but you'd have to create service principal grant it ACRpull permissions over the registry and use service principal login\password in App Service site_config

DOCKER_REGISTRY_SERVER_USERNAME
DOCKER_REGISTRY_SERVER_PASSWORD

Johns answered 26/1, 2020 at 14:5 Comment(2)
But that means storing its password in the version control. I could consume it as a variable and then arrange a secret variable in the Azure DevOps server, though.Hexahedron
That's very annoying from MS actually subverting the whole their idea of managed identity in this case - why do you need to give a username/password pair when, quoting their own website "The managed identity is authenticated with Azure AD, so you don’t have to store any credentials in code."Afterimage
M
0

This worked for me Enabling Admin User:

az acr update --name connectmatecr --admin-enabled true
Monies answered 16/5 at 17:21 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.