Function App Security Restrictions

The DR failover Azure Function is configured with multiple layers of security to ensure it can ONLY be triggered by Azure Monitor alerts, not by arbitrary HTTP requests.

The security architecture is shown in the following diagram:

Function App Security Restrictions Architecture

Security Controls Implemented:

Layer Control Configuration Purpose
Network IP Restriction ip_restriction_default_action = "Deny" Deny all traffic by default
Network Service Tag Allow service_tag = "ActionGroup" Only allow Azure Monitor Action Groups
Transport HTTPS Only https_only = true Enforce encrypted connections
Transport TLS 1.2 Minimum minimum_tls_version = "1.2" Prevent downgrade attacks
Transport FTPS Disabled ftps_state = "Disabled" No FTP access to function files
Application Function Key auth_level = func.AuthLevel.FUNCTION Require function key in URL
Deployment SCM Restrictions scm_ip_restriction_default_action = "Deny" Restrict deployment access

Terraform Configuration (modules/azure/dr-failover-function/main.tf):

terraform
resource "azurerm_linux_function_app" "dr_failover" {
  # ... other configuration ...

  # Security: Enforce HTTPS only
  https_only = true

  site_config {
    # Security: Require HTTPS and minimum TLS version
    ftps_state          = "Disabled"
    minimum_tls_version = "1.2"

    # Security: Restrict access to Azure Monitor Action Groups only
    # Azure Action Groups use the ActionGroup service tag to call webhooks/functions
    # This ensures only Azure Monitor alerts can trigger the DR failover function
    ip_restriction_default_action = "Deny"

    ip_restriction {
      name        = "AllowAzureMonitor"
      service_tag = "ActionGroup"
      priority    = 100
      action      = "Allow"
    }

    # SCM (deployment) site restrictions - deny all external access
    scm_ip_restriction_default_action = "Deny"

    scm_ip_restriction {
      name        = "AllowAzureCloud"
      service_tag = "AzureCloud"
      priority    = 100
      action      = "Allow"
    }
  }
}

Why ActionGroup Service Tag:

Azure Monitor Action Groups call webhooks and Azure Functions from a specific set of IP addresses defined by the ActionGroup service tag. By denying all traffic except this service tag, the function cannot be triggered by:

  • Direct HTTP requests from the internet

  • Curl commands or scripts

  • Other Azure services

  • Internal corporate networks

Only Azure Monitor alerts routed through Action Groups can reach the function.

Verification:

shell
# Verify security settings are in the Terraform plan
terraform init -backend-config=backend-configs/production-secondary.hcl -reconfigure
terraform plan -var-file=secondary-<region>.tfvars | grep -A5 "ip_restriction"

# After apply, verify function URL is available (won't work from local - blocked by IP restriction)
terraform output dr-failover-function_url

# Verify function outbound IPs for AKS API access
terraform output dr-failover-function_outbound_ip_cidrs

Testing the Alert Chain

The function cannot be called directly due to IP restrictions. To test the complete alert chain end-to-end, temporarily disable the primary Traffic Manager endpoint and confirm the Azure Monitor alert triggers the Function App (which scales humio-operator 0→1 on the standby cluster).

Safety: This forces the global DR hostname to stop routing to the primary endpoint. Do this only during a controlled DR test window.

shell
# In the PRIMARY workspace (the one that created Traffic Manager):
terraform workspace select primary

TM_RG="$(terraform output -raw azure-load-balancer-resource-group)"
TM_PROFILE="$(terraform output -raw traffic_manager_fqdn | cut -d. -f1)"
PRIMARY_ENDPOINT_ID="$(terraform output -raw traffic_manager_primary_endpoint_id)"
PRIMARY_ENDPOINT_NAME="$(az resource show --ids "$PRIMARY_ENDPOINT_ID" --query name -o tsv)"

# Disable primary endpoint (forces Traffic Manager to prefer the secondary endpoint)
az network traffic-manager endpoint update \
  --resource-group "$TM_RG" \
  --profile-name "$TM_PROFILE" \
  --type externalEndpoints \
  --name "$PRIMARY_ENDPOINT_NAME" \
  --endpoint-status Disabled

# Wait for the alert/function chain (~1-5 minutes), then verify on the secondary:
kubectl --context aks-secondary -n logging get deploy humio-operator

# Re-enable primary endpoint after testing
az network traffic-manager endpoint update \
  --resource-group "$TM_RG" \
  --profile-name "$TM_PROFILE" \
  --type externalEndpoints \
  --name "$PRIMARY_ENDPOINT_NAME" \
  --endpoint-status Enabled

Note

This repo does not currently include a test/simulate-azure-dr-failover.sh helper script.

Direct curl calls to the function URL will return 403 Forbidden because your IP is not in the ActionGroup service tag. This is expected behavior confirming the security restrictions are working.