hashicorp / terraform-provider-azurerm

Terraform provider for Azure Resource Manager
https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs
Mozilla Public License 2.0
4.61k stars 4.65k forks source link

Add support for "Backup/restore over virtual network" option for Custom backup of azurerm_windows_web_app #26018

Open AjinkyaBapat opened 6 months ago

AjinkyaBapat commented 6 months ago

Is there an existing issue for this?

Community Note

Terraform Version

1.8.3

AzureRM Provider Version

3.104.0

Affected Resource(s)/Data Source(s)

azurerm_windows_web_app

Terraform Configuration Files

resource "azurerm_windows_web_app" "webapp" {
  app_settings = {
  }
  client_affinity_enabled       = true
  client_certificate_enabled    = false
  client_certificate_mode       = "Required"
  enabled                       = true
  https_only                    = true
  location                      = var.location
  name                          = var.name
  public_network_access_enabled = true
  resource_group_name           = var.resource_group_name
  service_plan_id               = var.service_plan_id
  tags                          = var.tags
  virtual_network_subnet_id     = var.subnet_id
  zip_deploy_file               = null
  identity {
    type = "SystemAssigned"
  }
  logs {
    detailed_error_messages = true
    failed_request_tracing  = false
  }
  site_config {
    always_on                   = true
    ftps_state                  = "FtpsOnly"
    http2_enabled               = false
    load_balancing_mode         = "LeastRequests"
    local_mysql_enabled         = false
    managed_pipeline_mode       = "Integrated"
    minimum_tls_version         = "1.2"
    remote_debugging_enabled    = false
    remote_debugging_version    = "VS2019"
    scm_minimum_tls_version     = "1.2"
    scm_use_main_ip_restriction = false
    use_32_bit_worker           = true
    vnet_route_all_enabled      = false
    websockets_enabled          = false
    worker_count                = 1
    application_stack {
      current_stack  = "dotnet"
      dotnet_version = "v6.0"
      php_version    = "Off"
      python         = false
    }
    cors {
      allowed_origins     = length(var.allowed_origins) > 0 ? var.allowed_origins : null
      support_credentials = var.support_credentials
    }
    virtual_application {
      physical_path = "site\\wwwroot"
      preload       = false
      virtual_path  = "/"
    }
  }

  sticky_settings {
    app_setting_names = []
  }

  backup {
    name = var.name
    enabled = true
    schedule {
      keep_at_least_one_backup = true
      start_time = "var.start_time"
      frequency_unit = "Day"
      frequency_interval = 1
      retention_period_days = 60
    }
    storage_account_url = "var.url"   
  }
}

Debug Output/Panic Output

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
  ~ update in-place

Terraform will perform the following actions:

  # module.windowsappservice["xyz"].azurerm_windows_web_app.webapp will be updated in-place
  ~ resource "azurerm_windows_web_app" "webapp" {
        id                                             = "id"
        name                                           = "xyz"
        tags                                           = {}
        # (25 unchanged attributes hidden)

      + backup {
          + enabled             = true
          + name                = "xyz"
          + storage_account_url = (sensitive value)

          + schedule {
              + frequency_interval       = 1
              + frequency_unit           = "Day"
              + keep_at_least_one_backup = true
              + retention_period_days    = 60
              + start_time               = "time"
            }
        }

        # (4 unchanged blocks hidden)
    }

Plan: 0 to add, 1 to change, 0 to destroy.

Expected Behaviour

Created Custom Backup should have "Backup/restore over virtual network Integration" Option Enbaled. "vnetBackupRestoreEnabled": true

Actual Behaviour

"vnetBackupRestoreEnabled": false

image

Since this option is not True/Checked, my backups are failing as the destination Storage account has firewall turned on and can be accessed only from the Vnet.

Steps to Reproduce

terraform apply

Important Factoids

No response

References

No response

AjinkyaBapat commented 6 months ago

Also, I couldn't find any option in the backup block of azurerm_windows_web_app to set "Backup/restore over virtual network Integration" True or False.

frostsxx commented 1 month ago

Hi!

Any updates on this? @AjinkyaBapat

patasproulis commented 1 month ago

is there any update with this thing? or we shall make manual actions for this box?

frostsxx commented 2 weeks ago

This is my current code and got it got my issue solved.

Storage Acc code:

# CREATE VNET

resource "azurerm_virtual_network" "createVNet" {
  name                = lower("vnet-${var.resourceLocation}-${var.tagEnvironment}")
  location            = var.locationRG
  resource_group_name = azurerm_resource_group.createRG.name
  address_space       = var.addressSpaceVNet

  depends_on = [azurerm_resource_group.createRG]
}

# CREATE SUBNET

resource "azurerm_subnet" "createSubnet" {
  name                 = lower("snet-${var.resourceLocation}-${var.tagEnvironment}-${var.nameSubnet}") # nameSubnet -> Project name
  resource_group_name  = azurerm_resource_group.createRG.name
  virtual_network_name = azurerm_virtual_network.createVNet.name
  address_prefixes     = var.addressPrefixesSubnet

  depends_on = [azurerm_virtual_network.createVNet]

  # Enables Web Apps to communicate with this Subnet in order to backup
  delegation {
    name = "delegation"

    service_delegation {
      name    = "Microsoft.Web/serverFarms"
      actions = ["Microsoft.Network/virtualNetworks/subnets/join/action"]
    }
  }
}

# CREATE STORAGE ACCOUNT

resource "azurerm_storage_account" "createStorageAcc" {
  name                     = lower("${var.prefixRG}${var.resourceLocation}${var.tagEnvironment}sa")
  resource_group_name      = azurerm_resource_group.createRG.name
  location                 = azurerm_resource_group.createRG.location
  account_tier             = var.accountTier
  account_replication_type = var.accountReplicationType
  access_tier              = var.accessTier
  account_kind             = "BlobStorage"

  depends_on = [azurerm_resource_group.createRG]

  # Enable Blob Soft Delete with 14 days retention
  blob_properties {
    delete_retention_policy {
      days = 14
    }

    # Enable Container Soft Delete with 14 days retention
    container_delete_retention_policy {
      days = 14
    }
  }
}

# CREATES STORAGE CONTAINER

resource "azurerm_storage_container" "createBackupContainer" {
  name                  = "container-backup-web-apps"
  storage_account_name  = azurerm_storage_account.createStorageAcc.name
  container_access_type = "container"

  depends_on = [azurerm_storage_account.createStorageAcc]
}

# LOCAL VARIABLES START/EXPIRY SAS TOKEN

locals {
  current_time = timestamp()
  expiry_date = timeadd(local.current_time, "8760h") # Adds 1 year to use SAS token
}

# GENERATES SAS (SHARED ACCESS SIGNATURE)

data "azurerm_storage_account_sas" "createSAS" {
  connection_string = azurerm_storage_account.createStorageAcc.primary_connection_string
  https_only        = true

  depends_on = [azurerm_storage_container.createBackupContainer]

  resource_types {
    service   = true
    container = true
    object    = true
  }

  services {
    blob  = true
    queue = false
    table = false
    file  = false
  }

  start  = local.current_time
  expiry = local.expiry_date

  permissions {
    read    = true
    write   = true
    delete  = true
    list    = true
    add     = true
    create  = true
    update  = true
    process = false
    tag     = false
    filter  = false
  }
}

Web App code:

# CREATE SERVICE PLAN LINUX

resource "azurerm_service_plan" "createServicePlanLinux" {
  name                = lower("${module.createRG-lcg-dev-projecttest1-rg.prefixRG}-${module.createRG-lcg-dev-projecttest1-rg.acronymResourceLocation}-${module.createRG-lcg-dev-projecttest1-rg.tagEnvironment}-${module.createRG-lcg-dev-projecttest1-rg.tagTypeOS}-asp")
  resource_group_name = module.createRG-lcg-dev-projecttest1-rg.nameRG
  location            = module.createRG-lcg-dev-projecttest1-rg.locationRG
  os_type             = module.createRG-lcg-dev-projecttest1-rg.tagTypeOS
  sku_name            = "S1"
}

# CREATE WEB APP LINUX

resource "azurerm_linux_web_app" "createWebAppLinux" {
  name                      = lower("${module.createRG-lcg-dev-projecttest1-rg.prefixRG}-${module.createRG-lcg-dev-projecttest1-rg.acronymResourceLocation}-${module.createRG-lcg-dev-projecttest1-rg.tagEnvironment}-${module.createRG-lcg-dev-projecttest1-rg.tagTypeOS}-app")
  resource_group_name       = module.createRG-lcg-dev-projecttest1-rg.nameRG
  location                  = azurerm_service_plan.createServicePlanLinux.location
  service_plan_id           = azurerm_service_plan.createServicePlanLinux.id
  virtual_network_subnet_id = azurerm_subnet.createSubnet.id # Associates the Web App to a Subnet in order to connect to a Storage Acc for backups
  https_only = true
  ftp_publish_basic_authentication_enabled = false # FTP Basic Auth Publishing Credentials setting
  webdeploy_publish_basic_authentication_enabled = false # SCM Basic Auth Publishing Credentials setting

  depends_on = [azurerm_service_plan.createServicePlanLinux]

  backup {
    name = "testBackup"
    schedule {
      frequency_interval = 30
      frequency_unit     = "Day"
    }
    storage_account_url = "https://${azurerm_storage_account.createStorageAcc.name}.blob.core.windows.net/${azurerm_storage_container.createBackupContainer.name}?${data.azurerm_storage_account_sas.createSAS.sas}"
  }
}
patasproulis commented 2 weeks ago

This is my current code and got it got my issue solved.

Storage Acc code:

# CREATE VNET

resource "azurerm_virtual_network" "createVNet" {
  name                = lower("vnet-${var.resourceLocation}-${var.tagEnvironment}")
  location            = var.locationRG
  resource_group_name = azurerm_resource_group.createRG.name
  address_space       = var.addressSpaceVNet

  depends_on = [azurerm_resource_group.createRG]
}

# CREATE SUBNET

resource "azurerm_subnet" "createSubnet" {
  name                 = lower("snet-${var.resourceLocation}-${var.tagEnvironment}-${var.nameSubnet}") # nameSubnet -> Project name
  resource_group_name  = azurerm_resource_group.createRG.name
  virtual_network_name = azurerm_virtual_network.createVNet.name
  address_prefixes     = var.addressPrefixesSubnet

  depends_on = [azurerm_virtual_network.createVNet]

  # Enables Web Apps to communicate with this Subnet in order to backup
  delegation {
    name = "delegation"

    service_delegation {
      name    = "Microsoft.Web/serverFarms"
      actions = ["Microsoft.Network/virtualNetworks/subnets/join/action"]
    }
  }
}

# CREATE STORAGE ACCOUNT

resource "azurerm_storage_account" "createStorageAcc" {
  name                     = lower("${var.prefixRG}${var.resourceLocation}${var.tagEnvironment}sa")
  resource_group_name      = azurerm_resource_group.createRG.name
  location                 = azurerm_resource_group.createRG.location
  account_tier             = var.accountTier
  account_replication_type = var.accountReplicationType
  access_tier              = var.accessTier
  account_kind             = "BlobStorage"

  depends_on = [azurerm_resource_group.createRG]

  # Enable Blob Soft Delete with 14 days retention
  blob_properties {
    delete_retention_policy {
      days = 14
    }

    # Enable Container Soft Delete with 14 days retention
    container_delete_retention_policy {
      days = 14
    }
  }
}

# CREATES STORAGE CONTAINER

resource "azurerm_storage_container" "createBackupContainer" {
  name                  = "container-backup-web-apps"
  storage_account_name  = azurerm_storage_account.createStorageAcc.name
  container_access_type = "container"

  depends_on = [azurerm_storage_account.createStorageAcc]
}

# LOCAL VARIABLES START/EXPIRY SAS TOKEN

locals {
  current_time = timestamp()
  expiry_date = timeadd(local.current_time, "8760h") # Adds 1 year to use SAS token
}

# GENERATES SAS (SHARED ACCESS SIGNATURE)

data "azurerm_storage_account_sas" "createSAS" {
  connection_string = azurerm_storage_account.createStorageAcc.primary_connection_string
  https_only        = true

  depends_on = [azurerm_storage_container.createBackupContainer]

  resource_types {
    service   = true
    container = true
    object    = true
  }

  services {
    blob  = true
    queue = false
    table = false
    file  = false
  }

  start  = local.current_time
  expiry = local.expiry_date

  permissions {
    read    = true
    write   = true
    delete  = true
    list    = true
    add     = true
    create  = true
    update  = true
    process = false
    tag     = false
    filter  = false
  }
}

Web App code:

# CREATE SERVICE PLAN LINUX

resource "azurerm_service_plan" "createServicePlanLinux" {
  name                = lower("${module.createRG-lcg-dev-projecttest1-rg.prefixRG}-${module.createRG-lcg-dev-projecttest1-rg.acronymResourceLocation}-${module.createRG-lcg-dev-projecttest1-rg.tagEnvironment}-${module.createRG-lcg-dev-projecttest1-rg.tagTypeOS}-asp")
  resource_group_name = module.createRG-lcg-dev-projecttest1-rg.nameRG
  location            = module.createRG-lcg-dev-projecttest1-rg.locationRG
  os_type             = module.createRG-lcg-dev-projecttest1-rg.tagTypeOS
  sku_name            = "S1"
}

# CREATE WEB APP LINUX

resource "azurerm_linux_web_app" "createWebAppLinux" {
  name                      = lower("${module.createRG-lcg-dev-projecttest1-rg.prefixRG}-${module.createRG-lcg-dev-projecttest1-rg.acronymResourceLocation}-${module.createRG-lcg-dev-projecttest1-rg.tagEnvironment}-${module.createRG-lcg-dev-projecttest1-rg.tagTypeOS}-app")
  resource_group_name       = module.createRG-lcg-dev-projecttest1-rg.nameRG
  location                  = azurerm_service_plan.createServicePlanLinux.location
  service_plan_id           = azurerm_service_plan.createServicePlanLinux.id
  virtual_network_subnet_id = azurerm_subnet.createSubnet.id # Associates the Web App to a Subnet in order to connect to a Storage Acc for backups
  https_only = true
  ftp_publish_basic_authentication_enabled = false # FTP Basic Auth Publishing Credentials setting
  webdeploy_publish_basic_authentication_enabled = false # SCM Basic Auth Publishing Credentials setting

  depends_on = [azurerm_service_plan.createServicePlanLinux]

  backup {
    name = "testBackup"
    schedule {
      frequency_interval = 30
      frequency_unit     = "Day"
    }
    storage_account_url = "https://${azurerm_storage_account.createStorageAcc.name}.blob.core.windows.net/${azurerm_storage_container.createBackupContainer.name}?${data.azurerm_storage_account_sas.createSAS.sas}"
  }
}

This is my current code and got it got my issue solved.

Storage Acc code:

# CREATE VNET

resource "azurerm_virtual_network" "createVNet" {
  name                = lower("vnet-${var.resourceLocation}-${var.tagEnvironment}")
  location            = var.locationRG
  resource_group_name = azurerm_resource_group.createRG.name
  address_space       = var.addressSpaceVNet

  depends_on = [azurerm_resource_group.createRG]
}

# CREATE SUBNET

resource "azurerm_subnet" "createSubnet" {
  name                 = lower("snet-${var.resourceLocation}-${var.tagEnvironment}-${var.nameSubnet}") # nameSubnet -> Project name
  resource_group_name  = azurerm_resource_group.createRG.name
  virtual_network_name = azurerm_virtual_network.createVNet.name
  address_prefixes     = var.addressPrefixesSubnet

  depends_on = [azurerm_virtual_network.createVNet]

  # Enables Web Apps to communicate with this Subnet in order to backup
  delegation {
    name = "delegation"

    service_delegation {
      name    = "Microsoft.Web/serverFarms"
      actions = ["Microsoft.Network/virtualNetworks/subnets/join/action"]
    }
  }
}

# CREATE STORAGE ACCOUNT

resource "azurerm_storage_account" "createStorageAcc" {
  name                     = lower("${var.prefixRG}${var.resourceLocation}${var.tagEnvironment}sa")
  resource_group_name      = azurerm_resource_group.createRG.name
  location                 = azurerm_resource_group.createRG.location
  account_tier             = var.accountTier
  account_replication_type = var.accountReplicationType
  access_tier              = var.accessTier
  account_kind             = "BlobStorage"

  depends_on = [azurerm_resource_group.createRG]

  # Enable Blob Soft Delete with 14 days retention
  blob_properties {
    delete_retention_policy {
      days = 14
    }

    # Enable Container Soft Delete with 14 days retention
    container_delete_retention_policy {
      days = 14
    }
  }
}

# CREATES STORAGE CONTAINER

resource "azurerm_storage_container" "createBackupContainer" {
  name                  = "container-backup-web-apps"
  storage_account_name  = azurerm_storage_account.createStorageAcc.name
  container_access_type = "container"

  depends_on = [azurerm_storage_account.createStorageAcc]
}

# LOCAL VARIABLES START/EXPIRY SAS TOKEN

locals {
  current_time = timestamp()
  expiry_date = timeadd(local.current_time, "8760h") # Adds 1 year to use SAS token
}

# GENERATES SAS (SHARED ACCESS SIGNATURE)

data "azurerm_storage_account_sas" "createSAS" {
  connection_string = azurerm_storage_account.createStorageAcc.primary_connection_string
  https_only        = true

  depends_on = [azurerm_storage_container.createBackupContainer]

  resource_types {
    service   = true
    container = true
    object    = true
  }

  services {
    blob  = true
    queue = false
    table = false
    file  = false
  }

  start  = local.current_time
  expiry = local.expiry_date

  permissions {
    read    = true
    write   = true
    delete  = true
    list    = true
    add     = true
    create  = true
    update  = true
    process = false
    tag     = false
    filter  = false
  }
}

Web App code:

# CREATE SERVICE PLAN LINUX

resource "azurerm_service_plan" "createServicePlanLinux" {
  name                = lower("${module.createRG-lcg-dev-projecttest1-rg.prefixRG}-${module.createRG-lcg-dev-projecttest1-rg.acronymResourceLocation}-${module.createRG-lcg-dev-projecttest1-rg.tagEnvironment}-${module.createRG-lcg-dev-projecttest1-rg.tagTypeOS}-asp")
  resource_group_name = module.createRG-lcg-dev-projecttest1-rg.nameRG
  location            = module.createRG-lcg-dev-projecttest1-rg.locationRG
  os_type             = module.createRG-lcg-dev-projecttest1-rg.tagTypeOS
  sku_name            = "S1"
}

# CREATE WEB APP LINUX

resource "azurerm_linux_web_app" "createWebAppLinux" {
  name                      = lower("${module.createRG-lcg-dev-projecttest1-rg.prefixRG}-${module.createRG-lcg-dev-projecttest1-rg.acronymResourceLocation}-${module.createRG-lcg-dev-projecttest1-rg.tagEnvironment}-${module.createRG-lcg-dev-projecttest1-rg.tagTypeOS}-app")
  resource_group_name       = module.createRG-lcg-dev-projecttest1-rg.nameRG
  location                  = azurerm_service_plan.createServicePlanLinux.location
  service_plan_id           = azurerm_service_plan.createServicePlanLinux.id
  virtual_network_subnet_id = azurerm_subnet.createSubnet.id # Associates the Web App to a Subnet in order to connect to a Storage Acc for backups
  https_only = true
  ftp_publish_basic_authentication_enabled = false # FTP Basic Auth Publishing Credentials setting
  webdeploy_publish_basic_authentication_enabled = false # SCM Basic Auth Publishing Credentials setting

  depends_on = [azurerm_service_plan.createServicePlanLinux]

  backup {
    name = "testBackup"
    schedule {
      frequency_interval = 30
      frequency_unit     = "Day"
    }
    storage_account_url = "https://${azurerm_storage_account.createStorageAcc.name}.blob.core.windows.net/${azurerm_storage_container.createBackupContainer.name}?${data.azurerm_storage_account_sas.createSAS.sas}"
  }
}
patasproulis commented 2 weeks ago

@frostsxx You are right. Another problem I faced was that I was having changes everytime on schedyle so I followed this: lifecycle block with ignore changes. eg. backup { schedule { frequency_interval = var.backup_frequency_interval frequency_unit = var.backup_frequency_unit keep_at_least_one_backup = var.keep_at_least_one_backup retention_period_days = var.retention_period_days start_time = var.backup_start_time } name = var.backup_name storage_account_url = var.storage_account_url

} lifecycle { ignore_changes = [ backup[0].storage_account_url, backup[0].schedule[0].start_time ] }