I am trying to set the IP restrictions block in my Azure App Service App
When performing the Terraform plan or apply, I receive the following error:
Error: azurerm_app_service.app-service-1: : invalid or unknown key: ip_restriction
I used ip_restriction per Terraform Documentation for App Service (Web Apps) Resources
Here is the AppService deployment code i am using:
resource "azurerm_app_service" "app-service-1" {
name = "${var.app_service_1}"
location = "${data.azurerm_resource_group.core-rg.location}"
resource_group_name = "${data.azurerm_resource_group.core-rg.name}"
app_service_plan_id = "${data.azurerm_app_service_plan.app-service-plan-1.id}"
https_only = "True"
enabled = "True"
client_affinity_enabled = "True"
site_config {
always_on = "True"
#default_documents = ""
dotnet_framework_version = "v4.0"
#http2_enabled = ""
#ip_restriction = ""
#java_version = ""
#java_container = ""
#java_container_version = ""
managed_pipeline_mode = "Integrated"
min_tls_version = "1.2"
#php_version = ""
#python_version = ""
remote_debugging_enabled = "False"
#remote_debugging_version = ""
scm_type = "None"
use_32_bit_worker_process = "False"
websockets_enabled = "True"
#ftps_state = ""
}
app_settings {
"KeyVaultURI" = ""
"WEBSITE_NODE_DEFAULT_VERSION" = "6.9.1"
}
ip_restriction {
"ip_address" = ""
}
Thank you
#jamies answer is unfortunately incorrect IP_restriction is not a list taking one or more but a repeatable block.
#gvazzana is the correct format.
However, there is a trap.. that will cause the error you are seeing.
In Tf we are used to typing IP address's in full CIDR format eg 10.23.97.201/23 or 192.68.50.0/24, the azure portal for this section even displays them like this.
But for this particular block, in terraform, you have to do them old school. eg:
site_config {
# For a single IP address
ip_restriction {
ip_address = "81.145.174.78"
}
ip_restriction {
# For an address range
ip_address = "10.240.101.0"
subnet_mask = "255.255.255.0"
}
}
This is of course a pain if you have a long list of address's and ranges.
Now that terraform version 0.12.0 is upon us we should be able to take advantage of the new dynamic block styles and cidrhost and cidrmask functions in order to simplify things.
eg:
dynamic "ip_restriction" {
for_each = var.ip_address_list
content {
ip_address = cidrhost(ip_restriction.value,0)
subnet_mask = cidrmask(ip_restriction.value)
}
}
tested with
Terraform v0.12.13
For those interested, here is the method to use ipRestrictions in Terraform
ip Restrictions is part of the Site_Config {}
See how to use below:
AppService.tf:
resource "azurerm_app_service" "app-service-1" {
name = "${var.app_service_1}"
location = "${data.azurerm_resource_group.core-rg.location}"
resource_group_name = "${data.azurerm_resource_group.core-rg.name}"
app_service_plan_id = "${data.azurerm_app_service_plan.app-service-plan-1.id}"
https_only = "True"
enabled = "True"
client_affinity_enabled = "True"
site_config {
always_on = "True"
#default_documents = ""
dotnet_framework_version = "v4.0"
#http2_enabled = ""
#ip_restriction = ""
#java_version = ""
#java_container = ""
#java_container_version = ""
managed_pipeline_mode = "Integrated"
min_tls_version = "1.2"
#php_version = ""
#python_version = ""
remote_debugging_enabled = "False"
#remote_debugging_version = ""
scm_type = "None"
use_32_bit_worker_process = "False"
websockets_enabled = "True"
#ftps_state = ""
ip_restriction {
ip_address = "${var.ip_address_1}"
}
ip_restriction {
ip_address = "${var.ip_address_2}"
}
ip_restriction {
ip_address = "${var.ip_address_3}"
}
}
app_settings {
"KeyVaultURI" = ""
"WEBSITE_NODE_DEFAULT_VERSION" = "6.9.1"
}
}
So you are running into a syntax error. The documentation can be confusing to read as I have learned over the last year. If you read the section on ip_restriction it says that it takes one or more. This means that it expects an array.
There is also a section of the documentation that tells you that it inside the array it expects an object that has the properties of ip_address and subnet_mask. That is here
So to fix your issue you need the following for ip_restriction.
ip_restriction = [
{
ip_address = "10.0.0.0"
}
]
Hope this helps.
Related
I am trying to enable https for cdn endpoint custom domain. When trying to submit the code, i get the following error:
CertificateType value provided is not supported for this profile for enabling https.
The custom domain code:
resource "azurerm_cdn_endpoint_custom_domain" "endpointfrontend" {
name = "mykappdev"
cdn_endpoint_id = azurerm_cdn_endpoint.cdnendpoint.id
host_name = "${azurerm_dns_cname_record.cnamefrontend.name}.${data.azurerm_dns_zone.dnszone.name}"
cdn_managed_https {
certificate_type = "Dedicated"
protocol_type = "ServerNameIndication"
}
}
The rest of the cdn code:
resource "azurerm_cdn_profile" "cdnprofile" {
name = "mycdn${var.environment}"
location = data.azurerm_resource_group.rg.location
resource_group_name = data.azurerm_resource_group.rg.name
sku = "Standard_Microsoft"
}
resource "azurerm_cdn_endpoint" "cdnendpoint" {
name = "${var.environment}-example"
profile_name = azurerm_cdn_profile.cdnprofile.name
location = azurerm_cdn_profile.cdnprofile.location
resource_group_name = data.azurerm_resource_group.rg.name
is_https_allowed = true
origin {
name = "${var.environment}-origin"
host_name = azurerm_storage_account.frontend.primary_web_host
}
depends_on = [
azurerm_cdn_profile.cdnprofile
]
}
data "azurerm_dns_zone" "dnszone" {
name = "my.app"
resource_group_name = "rg-my"
}
Everything works fine when doing it via UI so the problem has to be in the code.
Edit the block azurerm_cdn_endpoint
resource "azurerm_cdn_endpoint" "cdnendpoint" {
name = "${var.environment}-example"
profile_name = azurerm_cdn_profile.cdnprofile.name
location = azurerm_cdn_profile.cdnprofile.location
resource_group_name = data.azurerm_resource_group.rg.name
is_https_allowed = true
origin {
name = "${var.environment}-origin"
host_name = azurerm_storage_account.frontend.primary_web_host
}
### Code added
delivery_rule {
name = "EnforceHTTPS"
order = "1"
request_scheme_condition {
operator = "Equal"
match_values = ["HTTP"]
}
url_redirect_action {
redirect_type = "Found"
protocol = "Https"
}
}
### End code added
depends_on = [
azurerm_cdn_profile.cdnprofile
]
}
Also, you can check this blog post https://www.emilygorcenski.com/post/migrating-a-static-site-to-azure-with-terraform/
Hope this helps!
After enabling custom https once per hand in the azure portal and than disabling it in portal, it was possible to change it via terraform.
I hope this helps!
How would I go about removing the location code (aus) from the Resource Group creation.
from:
rg-d-lxr-aus-app1
to
rg-d-lxr-app1
I only want this to affect the only RG and not any other resources eg vnets/keyvaults etc
app1
locals.tf
locals {
full_env_code = format("%s-%s-%s", lower(var.environment_code), lower(var.deployment_code), lower(var.location_code))
}
resource_groups.tf
module "rg-app1" {
source = "git::ssh://git#ssh.dev.azure.com/*"
resource_group_name = format("rg-%s-%s", local.full_env_code, lower(var.name_suffix))
location = var.location
}
variables.tf
variable "location" {
description = "Location in which to deploy resources"
# default = "Australia Southeast"
}
variable "environment_code" {
description = "Environment code"
# default = "d"
}
variable "environment" {
description = "Environment"
# default = "d"
}
variable "deployment_code" {
description = "Deployment code"
# default = "d"
}
variable "location_code" {
description = "Location code"
# default = "d"
}
dev.tfvars
environment = "non-prod"
environment_code = "d"
deployment_code = "my org"
location_code = "aus"
location = "Australia Southeast"
name_suffix = "app1"
Output of TF Plan
Terraform will perform the following actions:
# module.rg-sharegate.azurerm_resource_group.rg will be created
+ resource "azurerm_resource_group" "rg" {
+ id = (known after apply)
+ location = "australiasoutheast"
+ name = "rg-d-lxr-aus-app1"
}
Plan: 1 to add, 0 to change, 0 to destroy.
I am thinking we need to modify the RG module and use the split command, but i'm not sure how to go about it
module "rg-app1" {
resource_group_name = format("rg-%s-%s", local.full_env_code, lower(var.name_suffix))
You can use a mixture of built-in Terraform functions to achieve what you're after.
Local Code to recreate a MRE for you:
locals {
rg_string = "rg-d-lxr-aus-app1"
// Use split by "-" to create an array so we can use contains()
is_rg = contains(split("-", local.rg_string), "rg")
final_rg_string = local.is_rg ? replace(local.rg_string, "aus-", "") : local.rg_string
not_rg_string = "blah-d-lxr-aus-app1"
is_not_rg = contains(split("-", local.not_rg_string), "rg")
final_not_rg_string = local.is_not_rg ? replace(local.not_rg_string, "aus-", "") : local.not_rg_string
}
Result using Terraform Console:
> local.is_rg
true
> local.final_rg_string
"rg-d-lxr-app1"
> local.is_not_rg
false
> local.final_not_rg_string
"blah-d-lxr-aus-app1"
Links:
https://www.terraform.io/language/functions/replace
https://www.terraform.io/language/functions/contains
https://www.terraform.io/language/functions/split
You'll likely not need to duplicate the logic but I did just for demonstrative purposes. For example you can just use your resource_group_name and create your true/false conditions. If you need more help with that please let me know.
I have an Azure function that I need to run in an Elastic Premium plan. After deployed I see the following error:
Azure Functions runtime is unreachable
I've tried to solve it following Microsoft documentation, no luck.
Here is some thoughts about my tries :
We checked the Storage account is created
The Function's subnet already has the service endpoint for the storage account
Vnet integration is already enabled in the Function and it (subnet) is already added to the Storage firewall
We added the required properties in the Function settings:
WEBSITE_CONTENTAZUREFILECONNECTIONSTRING = dynamic created (connection string to the
Storage account)
WEBSITE_CONTENTOVERVNET = 1
WEBSITE_CONTENTSHARE = dynamic created
WEBSITE_VNET_ROUTE_ALL = 1
Here is the documentation link.
https://learn.microsoft.com/en-us/azure/azure-functions/functions-recover-storage-account
Everything was working fine when I was using the Premium (P1v2) and the error begins when I moved to Elastic (EP1).
I am deploying it using Terraform.
Here is a TF code example we are using to deploy
locals {
app_settings = {
FUNCTIONS_WORKER_RUNTIME = "python"
FUNCTION_APP_EDIT_MODE = "readonly"
WEBSITE_VNET_ROUTE_ALL = "1"
WEBSITE_CONTENTOVERVNET = "1"
}
}
module "az_service_plan_sample" {
source = "source module"
serviceplan_name = "planname"
resource_group_name = "RG Name"
region = "East US 2"
tier = "ElasticPremium"
size = "EP1"
kind = "elastic"
capacity = 40
per_site_scaling = false
depends_on = [
module.storage_account
]
}
module "storage_account_sample" {
source = "source module"
resource_group_name = "RG Name"
location = "East US 2"
name = "saname"
storage_account_replication_type = "GRS"
subnet_ids = [subnet_ids]
}
module "sample" {
source = "source module"
azure_function_name = "functionname"
resource_group_name = "RG Name"
storage_account_name = module.storage_account.storage-account-name
storage_account_access_key = module.storage_account.storage-account-primary-key
region = "East US 2"
subnet_id = subnet_ids
app_service_id = module.az_service_plan.service_plan_id
scope_role_storage_account = module.storage_account.storage-account-id
azure_function_version = "~4"
app_settings = local.app_settings
key_vault_reference_identity_id = azurerm_user_assigned_identity.az_func.id
pre_warmed_instance_count = 2
identity_type = "UserAssigned"
user_assigned_identityies = [{
id = azurerm_user_assigned_identity.az_func.id
principal_id = azurerm_user_assigned_identity.az_func.principal_id
}]
depends_on = [
module.az_service_plan_sample,
module.storage_account_sample,
azurerm_user_assigned_identity.az_func,
]
}
AFAIk, There is not a one specific reason for Azure function runtime unreachable, Please check the below workaround to solve the above issue,
We have tried to create a Function app using Elastic premium plan and its working fine at our end,
Please make sure that you have configured the correct WEBSITE_CONTENTAZUREFILECONNECTIONSTRING value same as AzureWebJobsStorage then try to STOP/START the function app.
Also try to set the pre_warmed_instance_count=1 instead of 2 as mentioned in this MICROSOFT DOCUMENTATION:-
The default pre-warmed instance count is 1, and for most scenarios this value should remain as 1.
For more information please refer this ARTICLE|AZURE LESSONS-AZURE FUNCTION RUNTIME UNREACHABLE.
When you use a Function with Elastic Premium Plan Type that has a VNET Integration, you need to add one more property called vnet_route_all_enabled to enable route outbound from your Azure Function. Also you need to first create a file in your storage account that the name of this file will be the content of this variable WEBSITE_CONTENTSHARE in your Application Settings. Below is my code suggestion:
You can check this doc to be sure: https://learn.microsoft.com/en-us/azure/azure-functions/functions-create-vnet
Below my suggest code:
locals {
app_settings = {
FUNCTIONS_WORKER_RUNTIME = "python"
FUNCTION_APP_EDIT_MODE = "readonly"
WEBSITE_VNET_ROUTE_ALL = "1"
WEBSITE_CONTENTOVERVNET = "1"
WEBSITE_CONTENTSHARE = "file-function"
}
}
module "az_service_plan_sample" {
source = "source module"
serviceplan_name = "planname"
resource_group_name = "RG Name"
region = "East US 2"
tier = "ElasticPremium"
size = "EP1"
kind = "elastic"
capacity = 40
per_site_scaling = false
depends_on = [
module.storage_account
]
}
module "storage_account_sample" {
source = "source module"
resource_group_name = "RG Name"
location = "East US 2"
name = "saname"
storage_account_replication_type = "GRS"
subnet_ids = [subnet_ids]
}
resource "azurerm_storage_share" "share_file_ingest_function" {
name = "file-function"
storage_account_name = module.storage_account_sample.name
depends_on = [
module.storage_account_sample
]
}
module "sample" {
source = "source module"
azure_function_name = "functionname"
resource_group_name = "RG Name"
storage_account_name = module.storage_account.storage-account-name
storage_account_access_key = module.storage_account.storage-account-primary-key
region = "East US 2"
subnet_id = subnet_ids
app_service_id = module.az_service_plan.service_plan_id
scope_role_storage_account = module.storage_account.storage-account-id
azure_function_version = "~4"
app_settings = local.app_settings
key_vault_reference_identity_id = azurerm_user_assigned_identity.az_func.id
pre_warmed_instance_count = 2
vnet_route_all_enabled = true
identity_type = "UserAssigned"
user_assigned_identityies = [{
id = azurerm_user_assigned_identity.az_func.id
principal_id = azurerm_user_assigned_identity.az_func.principal_id
}]
depends_on = [
module.az_service_plan_sample,
module.storage_account_sample,
azurerm_user_assigned_identity.az_func,
]
}
I am trying to create an Azure VM image using packer. My packer template looks like this
variable "version" {
type = string
default = "1.0.0"
}
variable "created_by" {
type = string
}
source "azure-arm" "development_subscription" {
azure_tags = {
CreatedBy = var.created_by
CreatedDate = formatdate("DD/MM/YYYY hh:mm:ss",timestamp())
}
image_offer = "WindowsServer"
image_publisher = "MicrosoftWindowsServer"
image_sku = "2022-datacenter-g2"
managed_image_name = "MyImage_${var.version}"
managed_image_resource_group_name = "Some-RG"
os_type = "Windows"
location = "ukwest"
# client_id = var.client_id
# client_secret = var.client_secret
subscription_id = "e8204745-e84f-4b2e-9e6f-545656fe0922"
vm_size = "Standard_D2s_v3"
winrm_insecure = true
winrm_timeout = "20m"
winrm_use_ssl = true
winrm_username = "packer"
}
However I keep on getting:
==> azure-arm.development_subscription: Waiting for WinRM to become available...
==> azure-arm.development_subscription: Timeout waiting for WinRM.
Other resources I've found online imply I should try increasing the timeout, but this VM doesn't seem likely to take longer than a few seconds to boot. Do I need to do something to disable the system firewall?
I was missing tenant_id. Once I added that, everything worked fine.
I tried your code it also got stuck while connecting to winRM and timed out waiting for the same .
The Major issue I found in your code is that you have not added a communicator ="WinRM" . So ,For that reason the WinRM port doesn't get open and you are not able to connect through it.
So, I added the same as solution in the below code :
variable "version" {
type = string
default = "1.0.0"
}
variable "created_by" {
type = string
default = "ajay"
}
variable "client_secret" {
default = "XXXXXXXXXXXXXXXXXXXXXXXX"
}
variable "client_id" {
default = "XXXXXXXXXXXXXXXXXXXXXXXXXX"
}
source "azure-arm" "development_subscription" {
azure_tags = {
CreatedBy = var.created_by
CreatedDate = formatdate("DD/MM/YYYY hh:mm:ss", timestamp())
}
image_offer = "WindowsServer"
image_publisher = "MicrosoftWindowsServer"
image_sku = "2022-datacenter-g2"
managed_image_name = "MyImage_${var.version}"
managed_image_resource_group_name = "ansumantest"
os_type = "Windows"
location = "ukwest"
client_id = var.client_id
client_secret = var.client_secret
subscription_id = "XXXXXXXXXXXXXXXXXXXX"
vm_size = "Standard_D2s_v3"
communicator = "winrm"
winrm_insecure = true
winrm_timeout = "20m"
winrm_use_ssl = true
winrm_username = "packer"
}
build {
name = "learn-packer"
sources = [
"source.azure-arm.development_subscription"
]
}
Output:
I ran terraform import for one SQL server & one SQL database. While running the terraform plan I see message 2 to change. But I am not able to find the change in the below plan. It's not showing any null value.
I am not sure what is the change to be in effect.
Here is the information about the terraform plan:
# azurerm_sql_database.sqldb[0m will be updated in-place[0m[0m
2020-12-24T16:01:39.1426150Z [0m [33m~[0m[0m resource "azurerm_sql_database" "sqldb" {
2020-12-24T16:01:39.1426881Z [1m[0mcollation[0m[0m = "SQL_Latin1_General_CP1_CI_AS"
2020-12-24T16:01:39.1427865Z [32m+[0m [0m[1m[0mcreate_mode[0m[0m = "Default"
2020-12-24T16:01:39.1428801Z [1m[0mcreation_date[0m[0m = "2020-07-06T15:20:16.947Z"
2020-12-24T16:01:39.1429581Z [1m[0mdefault_secondary_location[0m[0m = "East US"
2020-12-24T16:01:39.1430271Z [1m[0medition[0m[0m = "GeneralPurpose"
2020-12-24T16:01:39.1474446Z [1m[0mextended_auditing_policy[0m[0m = [
2020-12-24T16:01:39.1481428Z {
2020-12-24T16:01:39.1482165Z retention_in_days = 0
2020-12-24T16:01:39.1483057Z storage_account_access_key = ""
2020-12-24T16:01:39.1483679Z storage_account_access_key_is_secondary = false
2020-12-24T16:01:39.1484293Z storage_endpoint = ""
2020-12-24T16:01:39.1486841Z },
2020-12-24T16:01:39.1487323Z ]
2020-12-24T16:01:39.1488663Z [1m[0mid[0m[0m = "/subscriptions/78bc4018-84c1-4906-94c9-c1d5b84cc907/resourceGroups/rg-us-wus-dev-1/providers/Microsoft.Sql/servers/sql-us-wus-dev/databases/sqldb-us-wus-dev"
2020-12-24T16:01:39.1491489Z [1m[0mlocation[0m[0m = "westus"
2020-12-24T16:01:39.1492160Z [1m[0mmax_size_bytes[0m[0m = "34359738368"
2020-12-24T16:01:39.1492790Z [1m[0mname[0m[0m = "sqldb-us-wus-dev"
2020-12-24T16:01:39.1493436Z [1m[0mread_scale[0m[0m = false
2020-12-24T16:01:39.1494194Z [1m[0mrequested_service_objective_id[0m[0m = "f21733ad-9b9b-4d4e-a4fa-94a133c41718"
2020-12-24T16:01:39.1495057Z [1m[0mrequested_service_objective_name[0m[0m = "GP_Gen5_2"
2020-12-24T16:01:39.1495733Z [1m[0mresource_group_name[0m[0m = "rg-us-wus-dev-1"
2020-12-24T16:01:39.1496437Z [1m[0mserver_name[0m[0m = "sql-us-wus-dev"
2020-12-24T16:01:39.1497190Z [1m[0mtags[0m[0m = {}
2020-12-24T16:01:39.1497905Z [1m[0mzone_redundant[0m[0m = false
2020-12-24T16:01:39.1498494Z
2020-12-24T16:01:39.1498890Z threat_detection_policy {
2020-12-24T16:01:39.1499416Z [1m[0mdisabled_alerts[0m[0m = []
2020-12-24T16:01:39.1500074Z [1m[0memail_account_admins[0m[0m = "Disabled"
2020-12-24T16:01:39.1500670Z [1m[0memail_addresses[0m[0m = []
2020-12-24T16:01:39.1501143Z [1m[0mretention_days[0m[0m = 0
2020-12-24T16:01:39.1501574Z [1m[0mstate[0m[0m = "Disabled"
2020-12-24T16:01:39.1502069Z [1m[0muse_server_default[0m[0m = "Disabled"
2020-12-24T16:01:39.1502411Z }
2020-12-24T16:01:39.1502594Z
2020-12-24T16:01:39.1502851Z timeouts {}
2020-12-24T16:01:39.1503112Z }
2020-12-24T16:01:39.1503279Z
2020-12-24T16:01:39.1503637Z [1m # azurerm_sql_server.sqlserver[0m will be updated in-place[0m[0m
2020-12-24T16:01:39.1504503Z [0m [33m~[0m[0m resource "azurerm_sql_server" "sqlserver" {
2020-12-24T16:01:39.1504979Z [1m[0madministrator_login[0m[0m = "sqladmin"
2020-12-24T16:01:39.1505483Z [32m+[0m [0m[1m[0madministrator_login_password[0m[0m = (sensitive value)
2020-12-24T16:01:39.1506007Z [1m[0mconnection_policy[0m[0m = "Default"
2020-12-24T16:01:39.1506451Z [1m[0mextended_auditing_policy[0m[0m = [
2020-12-24T16:01:39.1506802Z {
2020-12-24T16:01:39.1507156Z retention_in_days = 0
2020-12-24T16:01:39.1507611Z storage_account_access_key = ""
2020-12-24T16:01:39.1508130Z storage_account_access_key_is_secondary = false
2020-12-24T16:01:39.1508695Z storage_endpoint = "https://stuxxwusdev.blob.core.windows.net/"
2020-12-24T16:01:39.1509179Z },
2020-12-24T16:01:39.1509442Z ]
2020-12-24T16:01:39.1510082Z [1m[0mfully_qualified_domain_name[0m[0m = "sql-us-wus-dev.database.windows.net"
2020-12-24T16:01:39.1511114Z [1m[0mid[0m[0m = "/subscriptions/78bc4018-84c1-4906-94c9-c1d5b84cc907/resourceGroups/rg-us-wus-dev-1/providers/Microsoft.Sql/servers/sql-us-wus-dev"
2020-12-24T16:01:39.1511895Z [1m[0mlocation[0m[0m = "westus"
2020-12-24T16:01:39.1512415Z [1m[0mname[0m[0m = "sql-us-wus-dev"
2020-12-24T16:01:39.1512991Z [1m[0mresource_group_name[0m[0m = "wus-dev"
2020-12-24T16:01:39.1513500Z [1m[0mtags[0m[0m = {}
2020-12-24T16:01:39.1514036Z [1m[0mversion[0m[0m = "12.0"
2020-12-24T16:01:39.1514327Z
2020-12-24T16:01:39.1514602Z timeouts {}
2020-12-24T16:01:39.1514890Z }
There are terraform plan symbol meanings, refer to this.
+ create
- destroy
-/+ replace (destroy and then create, or vice-versa if create-before-destroy is used)
~ update in-place i.e. change without destroying
<= read
You can check the ~ mark line to check that the specific attributes will be updated in place.
For example, it will update the retention_in_days from 6 to 0 in the terraform template code.
Please let me know if you still have any questions.