Azure  

Azure Functions at the Edge: IP Restrictions and Azure AD Authentication in a Global Payment Gateway

Table of Contents

  • Introduction

  • Why Access Control Matters in Serverless Architectures

  • Real-World Scenario: Cross-Border Payment Validation Service

  • Restricting Function Access by IP Address

  • Enforcing Azure AD Authentication on HTTP-Triggered Functions

  • Complete Secure Implementation (Python)

  • Operational Best Practices

  • Conclusion

Introduction

In enterprise cloud deployments, an Azure Function is never just “a function.” It’s an API endpoint, a data ingress point, and often a compliance boundary. Leaving it open to the public internet—even with authentication—is a critical risk. As a senior cloud architect, I enforce two non-negotiable layers of defense for any HTTP-triggered function handling sensitive operations:

  1. Network-level filtering: Allow only trusted IPs (e.g., partner systems or internal gateways)

  2. Identity-level validation: Require Azure Active Directory (Azure AD) tokens for human or service-to-service calls

This article demonstrates both techniques through a real-time, high-stakes use case: a global payment validation service.

Why Access Control Matters in Serverless Architectures

Serverless doesn’t mean “security-less.” In fact, the ephemeral nature of functions increases the attack surface if not properly constrained. Without IP and identity controls:

  • Your function becomes a target for credential brute-forcing

  • Malicious actors can trigger costly executions

  • Audit trails lack clear identity context

  • You violate PCI-DSS, ISO 27001, or SOC 2 requirements

The solution? Defense in depth—starting at the network edge.

Real-World Scenario: Cross-Border Payment Validation Service

A multinational bank operates a real-time payment validation API used by three external payment processors in the EU, US, and Singapore. Each processor must:

  • Call an Azure Function to validate transaction risk

  • Provide a valid Azure AD token issued to their registered app

  • Originate only from their pre-approved static IP ranges

Any deviation—wrong IP, missing token, invalid scope—must result in an immediate 403 response. No exceptions.

PlantUML Diagram

Restricting Function Access by IP Address

Azure Functions support access restrictions directly in the platform—no code required.

Step 1: Configure IP Restrictions in Azure Portal or via ARM/Bicep

Using Azure CLI:

az functionapp config access-restriction add \
  --resource-group payment-rg \
  --name payment-validator-func \
  --rule-name "EU-Payment-Processor" \
  --ip-address "203.0.113.0/24" \
  --priority 100 \
  --action Allow

az functionapp config access-restriction add \
  --resource-group payment-rg \
  --name payment-validator-func \
  --rule-name "US-Payment-Processor" \
  --ip-address "198.51.100.0/24" \
  --priority 110 \
  --action Allow

az functionapp config access-restriction add \
  --resource-group payment-rg \
  --name payment-validator-func \
  --rule-name "Singapore-Processor" \
  --ip-address "192.0.2.0/24" \
  --priority 120 \
  --action Allow

# Deny all other traffic by default (Azure does this automatically when rules exist)

This blocks all traffic not from the three whitelisted CIDR blocks—before your code even runs.

Enforcing Azure AD Authentication on HTTP-Triggered Functions

Next, require a valid Azure AD token with the correct scope.

Step 1: Register an App in Azure AD

  • Create an App Registration named payment-validator-api

  • Expose an API scope: api://<APP_ID>/validate.payment

  • Grant partner applications API permissions to this scope

Step 2: Enable Easy Auth (Authentication) on the Function App

In the Azure Portal:

  • Go to Authentication → Add identity provider

  • Choose Microsoft

  • Set Action to take when request is not authenticated → HTTP 401 Unauthorized

  • Under Token store, enable it

  • Map the required scope in Token validation

Alternatively, via ARM or Bicep—but the portal is fastest for validation.

With Easy Auth enabled, Azure validates the JWT token before your function executes. Invalid or missing tokens return 401 instantly.

Complete Secure Implementation (Python)

Even with platform-level auth, validate claims in code for defense in depth:

requirements.txt

azure-functions>=1.18.0

__init__.py

import logging
import azure.functions as func

def main(req: func.HttpRequest) -> func.HttpResponse:
    # Platform already validated token and IP—now verify claims
    try:
        # Extract claims from Easy Auth injected headers
        auth_header = req.headers.get('X-MS-TOKEN-AAD-ID-TOKEN')
        if not auth_header:
            return func.HttpResponse("Unauthorized", status_code=401)

        # Optional: Validate audience or scope in code (extra safety)
        # In production, parse JWT and check 'aud' and 'scp'
        # For brevity, we trust Easy Auth—but you can add PyJWT validation

        transaction_id = req.params.get('txnId')
        if not transaction_id:
            return func.HttpResponse("Missing txnId", status_code=400)

        # Business logic: validate payment risk
        risk_score = calculate_risk_score(transaction_id)
        
        return func.HttpResponse(
            f'{{"txnId": "{transaction_id}", "riskScore": {risk_score}}}',
            mimetype="application/json",
            status_code=200
        )

    except Exception as e:
        logging.error(f"Validation error: {e}")
        return func.HttpResponse("Internal error", status_code=500)

def calculate_risk_score(txn_id: str) -> float:
    # Simulated risk engine
    return 0.15  # In reality, call fraud detection ML model

No authentication logic in code. Azure handles it. Your function only runs if both IP and token are valid.

1

Operational Best Practices

  • Never disable IP restrictions “for testing”—use Azure’s “Ignore rules for Azure portal” toggle instead

  • Rotate partner IPs via Infrastructure-as-Code (Bicep/Terraform), not manual CLI

  • Monitor access logs in Azure Monitor: AppServiceIPRestrictionLog and AppServiceAuthLog

  • Use Managed Identity for the function to call downstream services—never store secrets

  • Test with curl:

curl -H "Authorization: Bearer <VALID_TOKEN>" https://your-function.azurewebsites.net/api/validate?txnId=123

Conclusion

In high-assurance environments, security isn’t a feature—it’s the foundation. By combining IP-based network filtering and Azure AD token validation, you create a zero-trust perimeter around your Azure Functions without writing a single line of auth code. This pattern is battle-tested in finance, healthcare, and government workloads. It scales, it’s auditable, and it shifts security left—into the platform, not the application. As a senior architect, I mandate this for every HTTP-triggered function that touches sensitive data. If your function can be called from anywhere by anyone, it’s not production-ready. Period.