Infrastructure Deployment via Azure Developer CLI for Terraform
December 28, 2023 ยท View on GitHub
Important
There are known issues when using the Terraform provider in combination with GitHub Codespaces i.e., the login flow via the Azure CLI gets stuck in the callback. You find the details in this issue of the azd repository as well as in this issue in the Azure CLI repository. The described workaround in the second issue did not do the trick for us. Hence, we currently cannot support GitHub Codespaces in this type of infrastructure setup.
Prerequisite
To use the Azure Developer CLI (azd) you need to have it available in your setup. If you are using the dev container "Azure Developer CLI (Terraform)" defined in this repository or opened the repository via GitHub Codespaces you are ready to go.
Deployment with Terraform
The basic steps of using azd to setup remain unchanged as described here. There are three spots that differ from a technical perspective, namely:
- The login flow via Azure CLI
- The specification of Terraform as IaC in the
azure.yamlmanifest. - The definition of the infrastructure via Terraform files and modules
In the following sections describe the points that need to be taken in to account if you want to use Terraform.
The login flow
To deploy the infrastructure via Terraform azd uses the Azure Terraform Provider under the hood. This provider (not azd) is using the Azure CLI login flow. As a consequence when using Terraform you must enforce azd to make use of this flow:
- Configure
azdto make use of the Azure CLI via the commandazd config set auth.useAzCliAuth true. - If you are using the
devcontaineror GitHub Codespaces, make that you open the devcontainer "Azure Developer CLI (Terraform)" that contains all necessary prerequisites.
Adjustment of manifest
The main file configuring the behavior of azd is the azure.yml file in the root repository. In order to make use of Terraform we must change it to use it for the infrastructure deployment as the default is bicep. To achieve this add the following section to the file to specify the infrastructure provider as well as the path to the Terraform files:
infra:
provider: terraform
path: ./infra-terraform
Note
The default path is infra. As we already have our .bicep resources defined there, we use a different path that we have to explicitly specify in the manifest.
Infrastructure setup
The Terraform files are located in the infra-terraform folder. As you can see the structure contains the modules provided by the azd team containing the Terraform modules that represent the core building blocks of your application. These modules are use in the main.tf file to define the setup of our app.
In the following section we present the single files of the Terraform-based setup:
The "provider.tf" file
This files defines what Terraform provider should be usd in order to do the setup. In addition the provider features for how to handle the purging of an Azure Key Vault as well as how deal with non-empty Resource Groups are defined in this file.
The "variables.tf" file
This files defines the input variables for the main.tf file. They can be seen like function arguments and are used in the setup of the infrastructure to e.g., provide the value for a specific resource configuration.
Here we also placed our quickstarter specific variables that define the access to SAP system's OData services.
The "output.tf" file
This file defines the output of the provisioning e.g., the URL endpoint of the application. The values correspond to function return values. They will be displayed in the CLI output when the provisioning was successfully executed.
The "main.tfvars.json" file
This files is the so called variable definitions file. This is one way to set the input variables defined in the variables.tf.
The "main.tf" file
This file is the core of the Terraform infrastructure configuration. Here we define the infrastructure setup of our application by combining the different building blocks provided via the Terraform modules. One example is the configuration of the module to provision the Azure App Service:
module "api" {
source = "./modules/appservicenode"
location = var.location
rg_name = azurerm_resource_group.rg.name
resource_token = local.resource_token
tags = merge(local.tags, { "azd-service-name" : "sap-cloud-sdk-api" })
service_name = "sap-cloud-sdk-api"
appservice_plan_id = module.appserviceplan.APPSERVICE_PLAN_ID
app_settings = {
"SCM_DO_BUILD_DURING_DEPLOYMENT" = "true"
"AZURE_KEY_VAULT_ENDPOINT" = module.keyvault.AZURE_KEY_VAULT_ENDPOINT
"APPLICATIONINSIGHTS_CONNECTION_STRING" = module.applicationinsights.APPLICATIONINSIGHTS_CONNECTION_STRING
"ODATA_URL" = var.oDataUrl
"ODATA_USERNAME" = var.oDataUsername
"ODATA_USERPWD" = "@Microsoft.KeyVault(SecretUri=${module.keyvault.AZURE_KEY_VAULT_ENDPOINT}secrets/${local.abbrKeyVaultVaults}secret-odata-password)"
"APIKEY" = "@Microsoft.KeyVault(SecretUri=${module.keyvault.AZURE_KEY_VAULT_ENDPOINT}secrets/${local.abbrKeyVaultVaults}secret-apikey)"
"APIKEY_HEADERNAME" = var.ApiKeyHeaderName
}
app_command_line = ""
always_on = false
identity = [{
type = "SystemAssigned"
}]
}
As you can see we use the variables defined in the variables.tf file to configure e.g., the app settings. The components are basically the same as in the Bicep flow, so we do not repeat them in detail here.
Mind the differences
The Terraform-based setup in the azd was introduced a later than the one using Bicep. Due to that and due to the differences between them, some things work differently. Here are two things that we think are worth to mention.
Purging of Azure Key Vault
When using Bicep to provide your infrastructure you get asked by the CLI if you want to purge you Azure Key Vault when deprovisioning your infrastructure. This is not the case when using Terraform. If you want to make sure that the Key Vault is purged when deprovisioning your infrastructure you must make an adjustment in the provider.tf file namely you must set the purge_soft_delete_on_destroy to false:
key_vault {
purge_soft_delete_on_destroy = false
}
The purging is automatically done once you delete your infrastructure.
Note
We do not recommend the automatic purging of the Azure Key Vault in a productive environment
Changes in the appservicenode module
In order to enable you to deploy the Azure App Service in the SKU F1 i.e., the free plan, we had to adjust some modules delivered by the azd team. One parameter available in the Bicep variant is missing in the Terraform setup, namely the site configuration always_on. This is set to true which prevents the deployment to a free plan. To enable this we made the following adjustments:
- Introduction of the parameter as a variable in the
infra-terraform\modules\appservicenode\appservicenode_variables.tf
variable "always_on" {
description = "The always on setting for the app service."
type = bool
default = true
}
- Exchanging the hard-coded value for the parameter with the newly defined variable in the
infra-terraform/modules/appservicenode/appservicenode.tffile:
resource "azurerm_linux_web_app" "web" {
name = azurecaf_name.web_name.result
location = var.location
resource_group_name = var.rg_name
service_plan_id = var.appservice_plan_id
https_only = true
tags = var.tags
site_config {
always_on = var.always_on
ftps_state = "FtpsOnly"
app_command_line = var.app_command_line
application_stack {
node_version = var.node_version
}
}
With these changes we were able to set the variable in the definition of the Azure App Service in the main.tf file.
More information
You find more information about azd and Terraform here.