I'm having an issue with getting my Web App to write to my Storage blob in Terraform in Azure.
As far as I can tell I have created everything, all I want it to do is send some .Net Log Files there in blob format. The connection is to happen through Key Vault, I have specified a key and made the relevant key vault policy.
Please see my code bellow everything builds but I get no logs dumped in the Storage Account. Do I have to create a storage blob or does the web app do that? I created one before but then nothing wrote to it.
Provider:
# Terraform Block
terraform {
required_version = ">= 1.0"
required_providers {
azurerm = {
source = "hashicorp/azurerm"
version = ">= 2.0"
}
random = {
source = "hashicorp/random"
version = ">= 3.0"
}
}
#Terraform State Storage Account
backend "azurerm" {}
}
# Providers Block
provider "azurerm" {
features {}
}
# Random String Resource
resource "random_string" "myrandom" {
length = 6
number = false
upper = false
special = false
}
Web App:
resource "azurerm_app_service_plan" "websiteappserviceplan" {
name = "appserviceplan-dgyn27h2dfoyojc"
location = azurerm_resource_group.Classroom_In_The_Cloud_Terraform.location
resource_group_name = azurerm_resource_group.Classroom_In_The_Cloud_Terraform.name
sku {
tier = "Standard"
size = "B1"
}
}
resource "azurerm_app_service" "website_app" {
name = var.website_name
location = azurerm_resource_group.Classroom_In_The_Cloud_Terraform.location
resource_group_name = azurerm_resource_group.Classroom_In_The_Cloud_Terraform.name
app_service_plan_id = azurerm_app_service_plan.websiteappserviceplan.id
#storage_account {
#name = azurerm_storage_account.website_logs_key.name
#type = "AzureBlob"
#access_key = lookup(azurerm_storage_account.value,"access_key")
#}
app_settings = {
"KEY_VAULT_URL" = azurerm_key_vault.nscsecrets.vault_uri
"DIAGNOSTICS_AZUREBLOBCONTAINERSASURL" = azurerm_storage_container.website_logs_container.name
"DIAGNOSTICS_AZUREBLOBRETENTIONINDAYS" = 365
}
connection_string {
name = "StorageAccount"
type = "Custom"
value = azurerm_storage_account.website_log_storage.primary_access_key
}
identity {
type = "SystemAssigned"
}
}
Storage Account:
resource "azurerm_storage_account" "website_log_storage" {
name = "cicweblogsstorageacc"
resource_group_name = azurerm_resource_group.Classroom_In_The_Cloud_Terraform.name
location = azurerm_resource_group.Classroom_In_The_Cloud_Terraform.location
account_tier = "Standard"
account_replication_type = "LRS"
identity {
type = "SystemAssigned"
}
}
resource "azurerm_storage_container" "website_logs_container" {
name = "${var.website_name}-cont"
storage_account_name = azurerm_storage_account.website_log_storage.name
container_access_type = "private"
}
#resource "azurerm_storage_blob" "website_logs_blob" {
# name = "website-logs.zip"
# storage_account_name = azurerm_storage_account.website_log_storage.name
# storage_container_name = azurerm_storage_container.website_logs_container.name
# type = "Block"
#}
resource "azurerm_storage_account_customer_managed_key" "website_log_key" {
depends_on = [azurerm_key_vault_access_policy.website_logs_storage_accesspolicy,
azurerm_key_vault_key.website_logs_key
]
storage_account_id = azurerm_storage_account.website_log_storage.id
key_vault_id = azurerm_key_vault.nscsecrets.id
key_name = azurerm_key_vault_key.website_logs_key.name
}
Key Vault:
// This gets the Azure AD Tenant ID information to deploy for KeyVault.
resource "azurerm_key_vault" "nscsecrets" {
name = "${var.key_vault_name}-${random_string.myrandom.id}"
resource_group_name = azurerm_resource_group.Classroom_In_The_Cloud_Terraform.name
location = azurerm_resource_group.Classroom_In_The_Cloud_Terraform.location
sku_name = "standard"
tenant_id = data.azurerm_client_config.current.tenant_id
soft_delete_retention_days = 7
purge_protection_enabled = true
}
resource "azurerm_key_vault_access_policy" "client" { // This is for AD Users Logged into Azure to give them the right access when creating resources.
key_vault_id = azurerm_key_vault.nscsecrets.id
tenant_id = data.azurerm_client_config.current.tenant_id
object_id = data.azurerm_client_config.current.object_id
secret_permissions = ["Backup", "Delete", "Get", "List", "Purge", "Recover", "Restore", "Set", ]
key_permissions = ["Backup", "Create", "Decrypt", "Delete", "Encrypt", "Get", "Import", "List", "Purge", "Recover", "Restore", "Sign", "UnwrapKey", "Update", "Verify", "WrapKey", ]
storage_permissions = ["Backup", "Delete", "DeleteSAS", "Get", "GetSAS", "List", "ListSAS", "Purge", "Recover", "RegenerateKey", "Restore", "Set", "SetSAS", "Update", ]
}
resource "azurerm_key_vault_access_policy" "service_principal" { // This is for the Service Principal in the pipeline to be able to make changes to Key Vault.
key_vault_id = azurerm_key_vault.nscsecrets.id
tenant_id = data.azurerm_client_config.current.tenant_id
object_id = data.azuread_service_principal.current.object_id
secret_permissions = ["Backup", "Delete", "Get", "List", "Purge", "Recover", "Restore", "Set", ]
key_permissions = ["Backup", "Create", "Decrypt", "Delete", "Encrypt", "Get", "Import", "List", "Purge", "Recover", "Restore", "Sign", "UnwrapKey", "Update", "Verify", "WrapKey", ]
storage_permissions = ["Backup", "Delete", "DeleteSAS", "Get", "GetSAS", "List", "ListSAS", "Purge", "Recover", "RegenerateKey", "Restore", "Set", "SetSAS", "Update", ]
}
resource "azurerm_key_vault_access_policy" "website_accesspolicy" {
key_vault_id = azurerm_key_vault.nscsecrets.id
tenant_id = azurerm_app_service.website_app.identity[0].tenant_id
object_id = azurerm_app_service.website_app.identity[0].principal_id
secret_permissions = ["get"]
}
resource "azurerm_key_vault_access_policy" "website_logs_storage_accesspolicy" { // This is for the Storage Account for Website Logs.
key_vault_id = azurerm_key_vault.nscsecrets.id
tenant_id = data.azurerm_client_config.current.tenant_id
object_id = azurerm_storage_account.website_log_storage.identity[0].principal_id
key_permissions = ["get", "create", "delete", "list", "restore", "recover", "unwrapkey", "wrapkey", "purge", "encrypt", "decrypt", "sign", "verify", ]
secret_permissions = ["Backup", "Delete", "Get", "List", "Purge", "Recover", "Restore", "Set", ]
}
resource "azurerm_key_vault_key" "website_logs_key" {
name = "website-logs-key"
key_vault_id = azurerm_key_vault.nscsecrets.id
key_type = "RSA"
key_size = 2048
key_opts = ["decrypt", "encrypt", "sign", "unwrapKey", "verify", "wrapKey", ]
depends_on = [
azurerm_key_vault_access_policy.client,
azurerm_key_vault_access_policy.website_logs_storage_accesspolicy
]
}
CodePudding user response:
I tested this on my environment by doing some changes to your code and it worked for me .
There is no need to provide these values in app settings i.e.
"DIAGNOSTICS_AZUREBLOBCONTAINERSASURL"
&"DIAGNOSTICS_AZUREBLOBRETENTIONINDAYS"
as when you are enabling logs they will get automatically populated.You should use
connection_string { name = "StorageAccount" type = "Custom" value = azurerm_storage_account.website_log_storage.primary_connection_string }
Instead of
connection_string { name = "StorageAccount" type = "Custom" value = azurerm_storage_account.website_log_storage.primary_access_key }
So, after the modifications and some additions the overall code will be like below :
provider "azurerm" {
features {}
}
provider "random"{}
provider "time" {}
resource "random_string" "myrandom" {
length = 6
number = false
upper = false
special = false
}
data "azurerm_client_config" "current"{}
data "azurerm_resource_group" "Classroom_In_The_Cloud_Terraform"{
name="yourresourcegroup"
}
variable "website_name" {
default = "ansuman-app"
}
// This gets the Azure AD Tenant ID information to deploy for KeyVault.
resource "azurerm_key_vault" "nscsecrets" {
name = "${var.website_name}-${random_string.myrandom.id}"
resource_group_name = data.azurerm_resource_group.Classroom_In_The_Cloud_Terraform.name
location = data.azurerm_resource_group.Classroom_In_The_Cloud_Terraform.location
sku_name = "standard"
tenant_id = data.azurerm_client_config.current.tenant_id
soft_delete_retention_days = 7
}
resource "azurerm_key_vault_access_policy" "client" { // This is for AD Users Logged into Azure to give them the right access when creating resources.
key_vault_id = azurerm_key_vault.nscsecrets.id
tenant_id = data.azurerm_client_config.current.tenant_id
object_id = data.azurerm_client_config.current.object_id
secret_permissions = ["Backup", "Delete", "Get", "List", "Purge", "Recover", "Restore", "Set", ]
key_permissions = ["Backup", "Create", "Decrypt", "Delete", "Encrypt", "Get", "Import", "List", "Purge", "Recover", "Restore", "Sign", "UnwrapKey", "Update", "Verify", "WrapKey", ]
storage_permissions = ["Backup", "Delete", "DeleteSAS", "Get", "GetSAS", "List", "ListSAS", "Purge", "Recover", "RegenerateKey", "Restore", "Set", "SetSAS", "Update", ]
}
resource "azurerm_key_vault_access_policy" "website_accesspolicy" {
key_vault_id = azurerm_key_vault.nscsecrets.id
tenant_id = azurerm_app_service.website_app.identity[0].tenant_id
object_id = azurerm_app_service.website_app.identity[0].principal_id
secret_permissions = ["get"]
}
resource "azurerm_key_vault_access_policy" "website_logs_storage_accesspolicy" { // This is for the Storage Account for Website Logs.
key_vault_id = azurerm_key_vault.nscsecrets.id
tenant_id = data.azurerm_client_config.current.tenant_id
object_id = azurerm_storage_account.website_log_storage.identity[0].principal_id
key_permissions = ["get", "create", "delete", "list", "restore", "recover", "unwrapkey", "wrapkey", "purge", "encrypt", "decrypt", "sign", "verify", ]
secret_permissions = ["Backup", "Delete", "Get", "List", "Purge", "Recover", "Restore", "Set", ]
}
resource "azurerm_key_vault_key" "website_logs_key" {
name = "website-logs-key"
key_vault_id = azurerm_key_vault.nscsecrets.id
key_type = "RSA"
key_size = 2048
key_opts = ["decrypt", "encrypt", "sign", "unwrapKey", "verify", "wrapKey", ]
depends_on = [
azurerm_key_vault_access_policy.client,
azurerm_key_vault_access_policy.website_logs_storage_accesspolicy
]
}
resource "azurerm_storage_account" "website_log_storage" {
name = "ansumanstorageacc12345"
resource_group_name = data.azurerm_resource_group.Classroom_In_The_Cloud_Terraform.name
location = data.azurerm_resource_group.Classroom_In_The_Cloud_Terraform.location
account_tier = "Standard"
account_replication_type = "GRS"
identity {
type = "SystemAssigned"
}
}
resource "azurerm_storage_container" "website_logs_container" {
name = "${var.website_name}-cont"
storage_account_name = azurerm_storage_account.website_log_storage.name
}
resource "time_rotating" "main" {
rotation_rfc3339 = null
rotation_years = 2
triggers = {
end_date = null
years = 2
}
}
data "azurerm_storage_account_blob_container_sas" "website_logs_container_sas" {
connection_string = azurerm_storage_account.website_log_storage.primary_connection_string
container_name = azurerm_storage_container.website_logs_container.name
start = timestamp()
expiry = time_rotating.main.rotation_rfc3339
permissions {
read = true
add = true
create = true
write = true
delete = true
list = true
}
cache_control = "max-age=5"
content_disposition = "inline"
content_encoding = "deflate"
content_language = "en-US"
content_type = "application/json"
}
resource "azurerm_app_service_plan" "websiteappserviceplan" {
name = "appserviceplan-dgyn27h2dfoyojc"
location = data.azurerm_resource_group.Classroom_In_The_Cloud_Terraform.location
resource_group_name = data.azurerm_resource_group.Classroom_In_The_Cloud_Terraform.name
sku {
tier = "Standard"
size = "B1"
}
}
resource "azurerm_app_service" "website_app" {
name = var.website_name
location = data.azurerm_resource_group.Classroom_In_The_Cloud_Terraform.location
resource_group_name = data.azurerm_resource_group.Classroom_In_The_Cloud_Terraform.name
app_service_plan_id = azurerm_app_service_plan.websiteappserviceplan.id
app_settings = {
"KEY_VAULT_URL" = azurerm_key_vault.nscsecrets.vault_uri
}
site_config {
always_on = true
dotnet_framework_version = "v5.0"
app_command_line = "dotnet EventManagement.Web.dll"
}
logs{
detailed_error_messages_enabled = true
failed_request_tracing_enabled = true
application_logs {
azure_blob_storage {
level="Information"
sas_url = format("https://${azurerm_storage_account.website_log_storage.name}.blob.core.windows.net/${azurerm_storage_container.website_logs_container.name}%s", data.azurerm_storage_account_blob_container_sas.website_logs_container_sas.sas)
retention_in_days = 365
}
}
http_logs {
azure_blob_storage{
sas_url=format("https://${azurerm_storage_account.website_log_storage.name}.blob.core.windows.net/${azurerm_storage_container.website_logs_container.name}%s", data.azurerm_storage_account_blob_container_sas.website_logs_container_sas.sas)
retention_in_days = 365
}
}
}
connection_string {
name = "StorageAccount"
type = "Custom"
value = azurerm_storage_account.website_log_storage.primary_connection_string
}
identity {
type = "SystemAssigned"
}
}
Output:
Note : The above is only for terraform modifications. So after the new app service is created and before you deploy the .net app sample code to the app service you have to do some other modifications to the app code like below.
After this you should be able to see the files as below:
Reference for more information on logs:
Configuring Logging in Azure App Services | Blog (ardalis.com)