Search code examples
terraformterraform-provider-azureazure-container-apps

Terraform, azurem create container app with image from a different subscription


I have a image registry in Azure Subscription A and I want to deploy an azure Container App in a Azure Subscription B using the image from the Azure Subscription A registry repository. I'm trying to do this using service principles as authentication. Is that possible with terraform? I can do it with scripts where I use the Azure Cli to login to Subscription A, pull the image and then login to Azure Subscription B and deploy it or even with Visual Studio's Publish (when I create the Publish profile I can chose the account for the Container App and for the Registry I can use another account) but I can't seem to manage this in terraform. This is my main.tf (I'm using variables to hide sensitive data) :

terraform {
  required_providers {
    azurerm = {
      source  = "hashicorp/azurerm"
      version = "~> 3.63.0"
    }
  }

  required_version = ">= 1.1.0"
}

provider "azurerm" {
  subscription_id = var.subsriptionA_sub_id
  tenant_id       = var.subsriptionA_tenant_id
  client_id       = var.subsriptionA_client_id
  client_secret   = var.subsriptionA_client_secret

  features {}
}

provider "azurerm" {
  alias           = "test"
  subscription_id = var.subscriptionB_sub_id
  tenant_id       = var.subscriptionB_tenant_id
  client_id       = var.subscriptionB_client_id
  client_secret   = var.subscriptionB_client_secret

  features {}
}
resource "azurerm_resource_group" "example" {
  provider = azurerm.test
  name     = var.resource_group_name
  location = var.location
}
data "azurerm_container_registry" "acr" {
  provider            = azurerm
  name                = "registryName"
  resource_group_name = var.subscriptionA_resource_group_name
}
resource "azurerm_log_analytics_workspace" "example" {
  provider            = azurerm.test
  name                = "acctest-01"
  location            = var.location
  resource_group_name = var.resource_group_name
  sku                 = "PerGB2018"
  retention_in_days   = 30
}

resource "azurerm_container_app_environment" "example" {
  provider                   = azurerm.test
  name                       = "Example-Environment"
  location                   = azurerm_resource_group.example.location
  resource_group_name        = azurerm_resource_group.example.name
  log_analytics_workspace_id = azurerm_log_analytics_workspace.example.id
}
resource "azurerm_container_app" "example" {
  provider                     = azurerm.test
  name                         = "example-app"
  container_app_environment_id = azurerm_container_app_environment.example.id
  resource_group_name          = var.resource_group_name
  revision_mode                = "Single"

  template {
    container {
      name   = "examplecontainerapp"
      image  = "${data.azurerm_container_registry.acr.login_server}/repositoryA:latest"
      cpu    = 0.25
      memory = "0.5Gi"
    }
  }
}

edit : This is the error I'm getting with this setup :

 Error: creating Container App (Subscription: SubscriptionB
│ Resource Group Name: var.resource_group_name
│ Container App Name: "example-app"): performing CreateOrUpdate: containerapps.ContainerAppsClient#CreateOrUpdate: Failure sending request: StatusCode=0 -- Original Error: Code="InvalidParameterValueInContainerTemplate" Message="The following field(s) are either invalid or missing. Field 'template.containers.examplecontainerapp.image' is invalid with details: 'Invalid value: \"${data.azurerm_container_registry.acr.login_server}/repositoryA:latest\": GET https:?scope=repositoryFromSusbscriptionA UNAUTHORIZED: authentication required, visit https://aka.ms/acr/authorization for more information.';."

edit2 : I found my solution, I needed to add these blocks, registry alone wasn't enough I needed a secret to get the password:

 secret {
    name  = "secretname"
    value = var.subsriptionA_client_secret
  }
  registry {
    server               = "server"
    username             = var.subsriptionA_client_id
    password_secret_name = "secretname"
  }

Thank you in advance!


Solution

  • I've found the solution for anyone wondering, there needs to be a registry block that takes the credential and the password needs to be from a secret (you can also use azure key vault for this from what I researched though I haven't tried that) :

    resource "azurerm_container_app" "example" {
      provider                     = azurerm.test
      name                         = "example-app"
      container_app_environment_id = azurerm_container_app_environment.example.id
      resource_group_name          = var.resource_group_name
      revision_mode                = "Single"
    
     secret {
        name  = "secretname"
        value = var.subsriptionA_client_secret
      }
      registry {
        server               = "server"
        username             = var.subsriptionA_client_id
        password_secret_name = "secretname"
      }
      template {
        container {
          name   = "examplecontainerapp"
          image  = "${data.azurerm_container_registry.acr.login_server}/repositoryA:latest"
          cpu    = 0.25
          memory = "0.5Gi"
        }
      }
    }