Tags: azure, ingress, application gateway, front door, web application firewall


Overview

Azure Web Application Firewall (WAF) provides centralized protection of your web applications from common exploits and vulnerabilities. Web applications are increasingly targeted by malicious attacks that exploit commonly known vulnerabilities. SQL injection and cross-site scripting are among the most common attacks.

WAF can be deployed with Azure Application Gateway and Azure Front Door service from Microsoft. WAF has features that are customized for each specific service. 


Kublr provides full customization for integration Azure Front Door with WAF and Kuberntes NGNIX Ingress controller service.


Prerequisites

Ingress controller DNS record and SSL certificate

You will need to create DNS record for Ingress controller and provide a valid SSL certificate for this record. Please refer to Kublr documentation (https://docs.kublr.com/articles/tls-setup/) or Support portal article (https://support.kublr.com/support/solutions/articles/33000257554-let-s-enrypt-dns-solver-with-aws-route53-service)


To determine the health of ingress service for a given Front Door environment, each Front Door environment periodically sends a synthetic HTTP/HTTPS request to Kubernetes ingress controller. If you use HTTPS, your ingress

health probe host must have valid SSL Certificate (https://ccadb-public.secure.force.com/microsoft/IncludedCACertificateReportForMSFT).

You cannot use self-signed certificates when you are forwarding the traffic as HTTPS or HTTPS health probes or filling the cache for from origin for routing rules!


Certificate CN: For HTTPS connections, Front Door expects that your backend presents certificate from a valid CA with subject name(s) matching the backend hostname. You can disabling certificate subject name check for your Front Door.

Certificate CA: Only certificates from valid Certificate Authorities can be used at the backend with Front Door. Certificates from internal CAs or self-signed certificates aren't allowed. The certificate must have a complete certificate chain with leaf and intermediate certificates, and root CA must be part of the Microsoft Trusted CA List.

Ingress Controller LB DNS record: You will need to create A record in DNS for Kubernetes NGINX Ingress controller public LB IP address. 


Workloads services DNS records: For each ingress hostname you will need to create CNAME records linked to Azure Front Door public DNS name (e.g. my-ingress-front-door.azurefd.net).


Azure WAF policy: You will need to create Web Application Firewall policy for FrontDoor in Azure console (https://docs.microsoft.com/en-us/azure/frontdoor/front-door-waf).


Kublr Cluster ARM Template extras

Azure FrontDoor Name: kublr-frontdoor

FrontDoor DNS: kublr-frontdoor-my-ingress-fqdn.azurefd.net

Kubernetes ingress public LB FQDN: ingress.kubernetes-ingress-domain.com

spec:
  locations:
    - name: azure1
      azure:
        armTemplateResourcesExtra:
          - apiVersion: '2020-07-01'
            location: Global
            name: kublr-frontdoor
            type: Microsoft.Network/frontdoors
            properties:
              cName: {kublr-frontdoor-my-ingress-fqdn}.azurefd.net
              backendPoolsSettings:
                enforceCertificateNameCheck: Disabled
              backendPools:
                - name: ingress
                  type: Microsoft.Network/Frontdoors/BackendPools
                  properties:
                    backends:
                      - address: ingress.{kubernetes-ingress-domain.com}
                        backendHostHeader: ''
                        httpPort: 80
                        httpsPort: 443
                        priority: 1
                        weight: 50
                    healthProbeSettings:
                      id: '[concat(''/subscriptions/'', subscription().subscriptionId, ''/resourceGroups/'', resourceGroup().name, ''/providers/Microsoft.Network/Frontdoors/kublr-frontdoor/HealthProbeSettings/ingress'')]'
                    loadBalancingSettings:
                      id: '[concat(''/subscriptions/'', subscription().subscriptionId, ''/resourceGroups/'', resourceGroup().name, ''/providers/Microsoft.Network/Frontdoors/kublr-frontdoor/LoadBalancingSettings/ingress-lb-0'')]'
              frontendEndpoints:
                - name: azurefd-net
                  type: Microsoft.Network/Frontdoors/FrontendEndpoints
                  properties:
                    hostName: {kublr-frontdoor-my-ingress-fqdn}.azurefd.net
                    sessionAffinityEnabledState: Enabled
                    sessionAffinityTtlSeconds: 0
              healthProbeSettings:
                - name: ingress
                  type: Microsoft.Network/Frontdoors/HealthProbeSettings
                  properties:
                    healthProbeMethod: HEAD
                    intervalInSeconds: 60
                    path: /healthz
                    protocol: Https
              loadBalancingSettings:
                - name: ingress-lb-0
                  type: Microsoft.Network/Frontdoors/LoadBalancingSettings
                  properties:
                    additionalLatencyMilliseconds: 0
                    sampleSize: 4
                    successfulSamplesRequired: 2
              routingRules:
                - name: ingress
                  properties:
                    acceptedProtocols:
                      - Https
                      - Http
                    enabledState: Enabled
                    frontendEndpoints:
                      - id: '[concat(''/subscriptions/'', subscription().subscriptionId, ''/resourceGroups/'', resourceGroup().name, ''/providers/Microsoft.Network/Frontdoors/kublr-frontdoor/FrontendEndpoints/azurefd-net'')]'
                    patternsToMatch:
                      - /*
                    routeConfiguration:
                      '@odata.type': '#Microsoft.Azure.FrontDoor.Models.FrontdoorForwardingConfiguration'
                      backendPool:
                        id: '[concat(''/subscriptions/'', subscription().subscriptionId, ''/resourceGroups/'', resourceGroup().name, ''/providers/Microsoft.Network/Frontdoors/kublr-frontdoor/backendPools/ingress'')]'
                      forwardingProtocol: HttpsOnly
                  type: Microsoft.Network/Frontdoors/RoutingRules
            tags:
              KubernetesCluster: Kublr-Cluster-Name

Workload service with WAF policy

Azure FrontDoor Name: kublr-frontdoor

Azure WAF policy for FrontDoor: MyWAFPolicy in waf-policy resource group

FrontDoor DNS: kublr-frontdoor-my-ingress-fqdn.azurefd.net

Workload FQDN: service.kubernetes-ingress-domain.com

You will need to create CNAME DNS record:

service.kubernetes-ingress-domain.com CNAME kublr-frontdoor-my-ingress-fqdn.azurefd.net

spec:
  locations:
    - name: azure1
      azure:
        armTemplateResourcesExtra:
          - apiVersion: '2020-07-01'
            location: Global
            name: kublr-frontdoor
            type: Microsoft.Network/frontdoors
            properties:
            ...
              frontendEndpoints:
              ...
                - name: service
                  type: Microsoft.Network/Frontdoors/FrontendEndpoints
                  properties:
                    hostName: service.kuberntes-ingress-domain.com
                    sessionAffinityEnabledState: Enabled
                    sessionAffinityTtlSeconds: 0
                    webApplicationFirewallPolicyLink:
                      id: '[concat(''/subscriptions/'', subscription().subscriptionId, ''/resourceGroups/'', ''waf-policy'', ''/providers/Microsoft.Network/frontdoorwebapplicationfirewallpolicies/MyWAFPolicy'')]'
              ...
              routingRules:
                - name: ingress
                  properties:
                    acceptedProtocols:
                      - Https
                    enabledState: Enabled
                    frontendEndpoints:
                      ...
                      - id: '[concat(''/subscriptions/'', subscription().subscriptionId, ''/resourceGroups/'', resourceGroup().name, ''/providers/Microsoft.Network/Frontdoors/kublr-frontdoor/FrontendEndpoints/service'')]'

Workload enable SSL termination on FrontDoor

Azure FrontDoor Name: kublr-frontdoor

Workload FQDN: service.kubernetes-ingress-domain.com

spec:
  locations:
    - name: azure1
      azure:
        armTemplateResourcesExtra:
          - apiVersion: '2020-07-01'
            type: Microsoft.Network/frontdoors/frontendEndpoints/customHttpsConfiguration
            name: kublr-frontdoor/{service}/default
            dependsOn:
              - '[resourceId(''Microsoft.Network/frontdoors'', ''kublr-frontdoor'')]'
            properties:
              certificateSource: FrontDoor
              frontDoorCertificateSourceParameters:
                certificateType: Dedicated
              minimumTlsVersion: 1.2
              protocolType: ServerNameIndication
            tags:
              KubernetesCluster: My-Kubernetes-ClusterName

Customize Ingress service firewall rules

This can be done via chart parameters controller.service.annotations etc as shown below in Kublr cluster specification snippet:

spec:
  features:
    ingress:
      values:
        nginx-ingress:
          controller:
            service:
              annotations:
                service.beta.kubernetes.io/azure-allowed-service-tags: 'AzureFrontDoor.Backend'
              enableHttp: false