From 947176e87509025725e5970537083eaa002f0f5e Mon Sep 17 00:00:00 2001 From: Ntwali B Date: Wed, 27 Nov 2024 10:34:31 +0100 Subject: [PATCH 01/36] Make sure to force JSON encoding for the Google analytics credentials file's content. --- roles/ckan/templates/kubernetes/ckan.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/roles/ckan/templates/kubernetes/ckan.yaml b/roles/ckan/templates/kubernetes/ckan.yaml index 6e962f7..adb8a75 100644 --- a/roles/ckan/templates/kubernetes/ckan.yaml +++ b/roles/ckan/templates/kubernetes/ckan.yaml @@ -10,7 +10,7 @@ data: ckan-uwsgi.ini: "{{ lookup('template', 'templates/ckan/ckan-uwsgi.ini') | b64encode }}" wsgi.py: "{{ lookup('template', 'templates/ckan/wsgi.py') | b64encode }}" {% if ckan_googleanalytics_enable %} - google_analytics_credentials.json: "{{ ckan_googleanalytics_credentials | b64encode }}" + google_analytics_credentials.json: "{{ ckan_googleanalytics_credentials | to_json | b64encode }}" {% endif %} type: Opaque From bc86d6172e44abe934ec24e7ed7d75211ab68950 Mon Sep 17 00:00:00 2001 From: Ntwali B Date: Mon, 9 Dec 2024 09:44:15 +0100 Subject: [PATCH 02/36] Add setting for Google analytics api_secret. --- group_vars/all/all.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/group_vars/all/all.yml b/group_vars/all/all.yml index 389a436..9f64885 100644 --- a/group_vars/all/all.yml +++ b/group_vars/all/all.yml @@ -115,6 +115,7 @@ giftless_version: "v0.4.0-fjelltopp" # Google analytics ckan_googleanalytics_enable: false +ckan_googleanalytics_api_secret: "" ckan_googleanalytics_private_key: "" ckan_googleanalytics_credentials: |- { From a4769322e2db3f6dd77bacdc51397290e2f7845d Mon Sep 17 00:00:00 2001 From: Ntwali B Date: Mon, 9 Dec 2024 09:44:52 +0100 Subject: [PATCH 03/36] Add new endpoint in GA cronjob to fetch url visits statistics. --- roles/ckan/templates/kubernetes/ckan_cronjob.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/roles/ckan/templates/kubernetes/ckan_cronjob.yaml b/roles/ckan/templates/kubernetes/ckan_cronjob.yaml index 42e6b8a..f81e08f 100644 --- a/roles/ckan/templates/kubernetes/ckan_cronjob.yaml +++ b/roles/ckan/templates/kubernetes/ckan_cronjob.yaml @@ -37,6 +37,7 @@ spec: command: ['bash', '-c'] args: - "curl -rl -X POST -H 'Content-Type: application/json' -H 'Accept: application/json' -d '{\"credentials_path\": \"/etc/ckan/google_analytics_credentials.json\" }' {{ ckan_site_url }}/api/action/download_package_stats" + - "curl -rl -X POST -H 'Content-Type: application/json' -H 'Accept: application/json' -d '{\"credentials_path\": \"/etc/ckan/google_analytics_credentials.json\" }' {{ ckan_site_url }}/api/action/download_url_stats" restartPolicy: Never {% endif %} From 3e313391ca13f04e0ca2ed4be62f98401884da61 Mon Sep 17 00:00:00 2001 From: Craig Cooper Date: Tue, 10 Dec 2024 13:30:05 +0700 Subject: [PATCH 04/36] fix: add cronjob to Azure --- roles/ckan/tasks/azure-deploy.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/roles/ckan/tasks/azure-deploy.yml b/roles/ckan/tasks/azure-deploy.yml index 847eed0..7e35e9e 100644 --- a/roles/ckan/tasks/azure-deploy.yml +++ b/roles/ckan/tasks/azure-deploy.yml @@ -10,7 +10,7 @@ az aks command invoke --resource-group {{ resource_group_name }} --name {{resource_prefix}}-aks \ --command "kubectl create namespace {{ application_namespace }}" -- set_fact: +- set_fact: storage_class_name: azureblob-nfs-premium # Azure. This can actually be anything as we create a custom StorageClass with this name - name: Get datalake info @@ -78,20 +78,20 @@ - ckan_volumes.yaml - ckan.yaml - ckan_ingress.yaml - # - ckan_cronjob.yaml + - ckan_cronjob.yaml # Look up the files, defaulting to the cloud provider specific version, falling back to a generic version -- name: Templates k8s files # Is there a better way to do this? it would happen automatically if the file _contents_ were piped to the az/kubectl command +- name: Templates k8s files # Is there a better way to do this? it would happen automatically if the file _contents_ were piped to the az/kubectl command template: src: "{{ lookup('first_found', 'templates/kubernetes/aks/{{ item }}', 'templates/kubernetes/{{ item }}') }}" dest: "{{role_path}}/templates/kubernetes/aks/out/{{ item }}" - with_items: "{{ k8s_yaml }}" + with_items: "{{ k8s_yaml }}" # This is nice as it only requires Azure Auth, rather than any network access to the cluster. A private endpoint etc _might_ be better tho? - name: Deploy CKAN command: > az aks command invoke \ - --resource-group {{ resource_group_name }} + --resource-group {{ resource_group_name }} --name {{resource_prefix}}-aks \ --command "kubectl apply -n {{ application_namespace }} -f {{item}}" \ --file "{{ lookup('first_found', 'templates/kubernetes/aks/out/{{ item }}') }}" From 850aa31972086fb2f0c79d050abade06a326638b Mon Sep 17 00:00:00 2001 From: Craig Cooper Date: Tue, 10 Dec 2024 14:35:48 +0700 Subject: [PATCH 05/36] fix: try different secrets --- roles/ckan/templates/kubernetes/ckan.yaml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/roles/ckan/templates/kubernetes/ckan.yaml b/roles/ckan/templates/kubernetes/ckan.yaml index adb8a75..ecc5ae9 100644 --- a/roles/ckan/templates/kubernetes/ckan.yaml +++ b/roles/ckan/templates/kubernetes/ckan.yaml @@ -10,7 +10,9 @@ data: ckan-uwsgi.ini: "{{ lookup('template', 'templates/ckan/ckan-uwsgi.ini') | b64encode }}" wsgi.py: "{{ lookup('template', 'templates/ckan/wsgi.py') | b64encode }}" {% if ckan_googleanalytics_enable %} - google_analytics_credentials.json: "{{ ckan_googleanalytics_credentials | to_json | b64encode }}" + google_analytics_credentials.json: "{{ ckan_googleanalytics_credentials | b64encode }}" + google_analytics_credentials.json2: "{{ ckan_googleanalytics_credentials | to_json | b64encode }}" + google_analytics_credentials.json3: '{{ ckan_googleanalytics_credentials | b64encode }}' {% endif %} type: Opaque From 64e91b9676954fff3c7be229a158db3dc17948a4 Mon Sep 17 00:00:00 2001 From: Craig Cooper Date: Thu, 26 Dec 2024 16:11:22 +0700 Subject: [PATCH 06/36] feat: Azure waf --- group_vars/all/all.yml | 1 - roles/ckan/templates/kubernetes/ckan.yaml | 2 - roles/setup-azure-frontdoor/tasks/main.yml | 112 +++++++++++++++++---- 3 files changed, 95 insertions(+), 20 deletions(-) diff --git a/group_vars/all/all.yml b/group_vars/all/all.yml index 9f64885..389a436 100644 --- a/group_vars/all/all.yml +++ b/group_vars/all/all.yml @@ -115,7 +115,6 @@ giftless_version: "v0.4.0-fjelltopp" # Google analytics ckan_googleanalytics_enable: false -ckan_googleanalytics_api_secret: "" ckan_googleanalytics_private_key: "" ckan_googleanalytics_credentials: |- { diff --git a/roles/ckan/templates/kubernetes/ckan.yaml b/roles/ckan/templates/kubernetes/ckan.yaml index ecc5ae9..6e962f7 100644 --- a/roles/ckan/templates/kubernetes/ckan.yaml +++ b/roles/ckan/templates/kubernetes/ckan.yaml @@ -11,8 +11,6 @@ data: wsgi.py: "{{ lookup('template', 'templates/ckan/wsgi.py') | b64encode }}" {% if ckan_googleanalytics_enable %} google_analytics_credentials.json: "{{ ckan_googleanalytics_credentials | b64encode }}" - google_analytics_credentials.json2: "{{ ckan_googleanalytics_credentials | to_json | b64encode }}" - google_analytics_credentials.json3: '{{ ckan_googleanalytics_credentials | b64encode }}' {% endif %} type: Opaque diff --git a/roles/setup-azure-frontdoor/tasks/main.yml b/roles/setup-azure-frontdoor/tasks/main.yml index 3ddd0ef..a56a7dc 100644 --- a/roles/setup-azure-frontdoor/tasks/main.yml +++ b/roles/setup-azure-frontdoor/tasks/main.yml @@ -1,4 +1,4 @@ - + # No ansible for this, so using CLI mostly # Command group 'afd' is in preview and under development. Reference and support levels: https://aka.ms/CLI_refstatus - name: Get subscription_id for later @@ -31,7 +31,7 @@ --enabled-state Enabled register: giftless_endpoint_output -- set_fact: +- set_fact: ckan_hostname: "https://{{ (ckan_endpoint_output.stdout|from_json).hostName }}" - name: Add a ruleset to set CORS headers for Giftless @@ -81,7 +81,7 @@ # Origin Groups - name: Create Front Door Origin Group (CKAN) - command: > + command: > az afd origin-group create \ --resource-group {{ resource_group_name }} \ --profile-name {{resource_prefix}}-afd \ @@ -96,7 +96,7 @@ # Origin Groups - name: Create Front Door Origin Group (giftless) - command: > + command: > az afd origin-group create \ --resource-group {{ resource_group_name }} \ --profile-name {{resource_prefix}}-afd \ @@ -126,18 +126,18 @@ - name: Create an origin with Private Link to AKS (CKAN) command: > - az afd origin create -g group + az afd origin create -g group --host-name {{ ckan_pls_alias }} \ --origin-host-header {{ ckan_fqdn }} \ --resource-group {{ resource_group_name }} \ --profile-name {{resource_prefix}}-afd \ --origin-group-name {{resource_prefix}}-og-ckan \ - --origin-name ckan-origin \ + --origin-name ckan-origin \ --priority 1 \ --weight 1000 \ --enabled-state Enabled \ --http-port 80 \ - --https-port 80 \ + --https-port 80 \ --enable-private-link true \ --private-link-resource "/subscriptions/{{ subscription_output.subscriptions[0].subscription_id }}/resourceGroups/{{ node_group_name }}/providers/Microsoft.Network/privateLinkServices/{{ ckan_pls_name }}" \ --private-link-request-message 'Please approve this request' \ @@ -156,19 +156,19 @@ - name: Create an origin with Private Link to AKS (Giftless) command: > - az afd origin create -g group + az afd origin create -g group --host-name {{ giftless_pls_alias }} \ --origin-host-header {{ giftless_pls_alias }} \ --resource-group {{ resource_group_name }} \ --profile-name {{resource_prefix}}-afd \ --origin-group-name {{resource_prefix}}-og-giftless \ - --origin-name ckan-origin \ + --origin-name ckan-origin \ --priority 1 \ --weight 1000 \ --enabled-state Enabled \ --enable-private-link true \ --http-port 5001 \ - --https-port 5001 \ + --https-port 5001 \ --private-link-resource "/subscriptions/{{ subscription_output.subscriptions[0].subscription_id }}/resourceGroups/{{ node_group_name }}/providers/Microsoft.Network/privateLinkServices/{{ giftless_pls_name }}" \ --private-link-request-message 'Please approve this request' \ --private-link-location {{ azure_region }} @@ -206,34 +206,112 @@ - name: Get PLS details for approval (CKAN) command: > - az network private-endpoint-connection list \ + az network private-endpoint-connection list \ --id /subscriptions/{{ subscription_output.subscriptions[0].subscription_id }}/resourceGroups/{{ node_group_name }}/providers/Microsoft.Network/privateLinkServices/{{ ckan_pls_name }} \ -o json register: ckan_pls_pending_output - name: Get PLS details for approval (giftless) command: > - az network private-endpoint-connection list \ + az network private-endpoint-connection list \ --id /subscriptions/{{ subscription_output.subscriptions[0].subscription_id }}/resourceGroups/{{ node_group_name }}/providers/Microsoft.Network/privateLinkServices/{{ giftless_pls_name }} \ -o json register: giftless_pls_pending_output - name: Approve the Private Link Services (Giftless) command: > - az network private-endpoint-connection approve \ + az network private-endpoint-connection approve \ -g {{ node_group_name }} \ --type Microsoft.Network/privateLinkServices \ - --resource-name {{ giftless_pls_name }} + --resource-name {{ giftless_pls_name }} -n {{ (giftless_pls_pending_output.stdout|from_json)[0].name }} --description "Approved" when: (giftless_pls_pending_output.stdout|from_json)[0].properties.privateLinkServiceConnectionState.status == "Pending" - name: Approve the Private Link Services (CKAN) command: > - az network private-endpoint-connection approve \ + az network private-endpoint-connection approve \ -g {{ node_group_name }} \ --type Microsoft.Network/privateLinkServices \ - --resource-name {{ ckan_pls_name }} + --resource-name {{ ckan_pls_name }} -n {{ (ckan_pls_pending_output.stdout|from_json)[0].name }} --description "Approved" - when: (ckan_pls_pending_output.stdout|from_json)[0].properties.privateLinkServiceConnectionState.status == "Pending" \ No newline at end of file + when: (ckan_pls_pending_output.stdout|from_json)[0].properties.privateLinkServiceConnectionState.status == "Pending" + +- name: Create Policy for WAF + command: > + az network front-door waf-policy create \ + --name {{resource_prefix}}-waf-policy \ + --resource-group {{ resource_group_name }} \ + --mode Prevention # or 'Detection' + +# DRS 2.1 includes 17 rule groups, as shown in the following table. +# Each group contains multiple rules, and you can customize behavior for individual rules, rule groups, or entire rule set. +# DRS 2.1 is baselined off the Open Web Application Security Project (OWASP) Core Rule Set (CRS) 3.3.2 and includes additional proprietary protections rules developed by Microsoft Threat Intelligence team. +# https://learn.microsoft.com/en-us/azure/web-application-firewall/ag/application-gateway-crs-rulegroups-rules?tabs=owasp32#drs-21 +- name: Add managed default ruleset to WAF policy + command: > + az network front-door waf-policy managed-rules add \ + --resource-group {{ resource_group_name }} \ + --policy-name {{resource_prefix}}-waf-policy \ + --type Microsoft_DefaultRuleSet --version 2.1 --action Block + +# The Bot Manager 1.1 rule set is an enhancement to Bot Manager 1.0 rule set. It provides enhanced protection against malicious bots, and increases good bot detection. +# https://learn.microsoft.com/en-us/azure/web-application-firewall/ag/application-gateway-crs-rulegroups-rules?tabs=owasp32#bot-manager-11 +- name: Add bot ruleset to WAF policy + command: > + az network front-door waf-policy managed-rules add \ + --resource-group {{ resource_group_name }} \ + --policy-name {{resource_prefix}}-waf-policy \ + --type Microsoft_BotManagerRuleSet \ + --version 1.1 + +# The following rules are disabled by default as they result in false positives. +# https://learn.microsoft.com/en-us/azure/web-application-firewall/ag/application-gateway-crs-rulegroups-rules?tabs=owasp32#microsoft-threat-intelligence-collection-rules +# We also disable a lot because CKAN will trigger them +- name: Define rules we disable + set_fact: + azure_waf_rule_overrides: + # --type Microsoft_DefaultRuleSet --rule-group-id SQLI --rule-id 942430 + - ["Microsoft_DefaultRuleSet", "SQLI", "942430"] + - ["Microsoft_DefaultRuleSet", "RFI", "931130"] + - ["Microsoft_DefaultRuleSet", "SQLI", "942440"] + - ["Microsoft_DefaultRuleSet", "MS-ThreatIntel-SQLI", "99031002"] + - ["Microsoft_DefaultRuleSet", "SQLI", "942120"] + - ["Microsoft_DefaultRuleSet", "SQLI", "942200"] + - ["Microsoft_DefaultRuleSet", "PHP", "933210"] + - ["Microsoft_DefaultRuleSet", "General", "200003"] + - ["Microsoft_DefaultRuleSet", "General", "200002"] + - ["Microsoft_DefaultRuleSet", "SQLI", "942400"] + - ["Microsoft_DefaultRuleSet", "SQLI", "942210"] + - ["Microsoft_DefaultRuleSet", "SQLI", "942410"] + - ["Microsoft_DefaultRuleSet", "SQLI", "942150"] + - ["Microsoft_DefaultRuleSet", "MS-ThreatIntel-SQLI", "99031003"] + - ["Microsoft_DefaultRuleSet", "SQLI", "942340"] + - ["Microsoft_DefaultRuleSet", "SQLI", "942260"] + - ["Microsoft_DefaultRuleSet", "MS-ThreatIntel-SQLI", "99031004"] + - ["Microsoft_DefaultRuleSet", "SQLI", "942330"] + - ["Microsoft_DefaultRuleSet", "SQLI", "942100"] + - ["Microsoft_DefaultRuleSet", "PHP", "933160"] + - ["Microsoft_DefaultRuleSet", "SQLI", "942370"] + - ["Microsoft_DefaultRuleSet", "PROTOCOL-ATTACK", "921110"] + - ["Microsoft_DefaultRuleSet", "SQLI", "942110"] + - ["Microsoft_DefaultRuleSet", "SQLI", "942140"] + - ["Microsoft_DefaultRuleSet", "MS-ThreatIntel-SQLI", "99031001"] + - ["Microsoft_DefaultRuleSet", "XSS", "941340"] + - ["Microsoft_DefaultRuleSet", "SQLI", "942190"] + - ["Microsoft_DefaultRuleSet", "XSS", "941150"] + - ["Microsoft_DefaultRuleSet", "XSS", "941370"] + - ["Microsoft_DefaultRuleSet", "SQLI", "942390"] + - ["Microsoft_DefaultRuleSet", "SQLI", "942380"] + +- name: Apply WAF Rule Overrides + command: > + az network front-door waf-policy managed-rules override add \ + --disabled \ + --policy-name {{resource_prefix}}-waf-policy \ + --resource-group {{ resource_group_name }} \ + --type {{ item.0 }} \ + --rule-group-id {{ item.1 }} \ + --rule-id {{ item.2 }} + with_items: "{{ azure_waf_rule_overrides + custom_azure_waf_rule_overrides }}" From df4d83a5c476c672db97bb8aeab1e3bfc489fefe Mon Sep 17 00:00:00 2001 From: Craig Cooper Date: Thu, 26 Dec 2024 16:12:21 +0700 Subject: [PATCH 07/36] feat: Azure waf default --- roles/setup-azure-frontdoor/tasks/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/roles/setup-azure-frontdoor/tasks/main.yml b/roles/setup-azure-frontdoor/tasks/main.yml index a56a7dc..9dde2a7 100644 --- a/roles/setup-azure-frontdoor/tasks/main.yml +++ b/roles/setup-azure-frontdoor/tasks/main.yml @@ -314,4 +314,4 @@ --type {{ item.0 }} \ --rule-group-id {{ item.1 }} \ --rule-id {{ item.2 }} - with_items: "{{ azure_waf_rule_overrides + custom_azure_waf_rule_overrides }}" + with_items: "{{ azure_waf_rule_overrides + (custom_azure_waf_rule_overrides | default([])) }}" From b2460deee9399895470c720fa5a8451a95dbe269 Mon Sep 17 00:00:00 2001 From: Craig Cooper Date: Thu, 26 Dec 2024 16:28:10 +0700 Subject: [PATCH 08/36] add waf --- roles/setup-azure-frontdoor/tasks/main.yml | 157 +++++++++++---------- 1 file changed, 79 insertions(+), 78 deletions(-) diff --git a/roles/setup-azure-frontdoor/tasks/main.yml b/roles/setup-azure-frontdoor/tasks/main.yml index 9dde2a7..8b5128d 100644 --- a/roles/setup-azure-frontdoor/tasks/main.yml +++ b/roles/setup-azure-frontdoor/tasks/main.yml @@ -13,6 +13,85 @@ --resource-group {{ resource_group_name }} \ --sku Premium_AzureFrontDoor +- name: Create Policy for WAF + command: > + az network front-door waf-policy create \ + --name {{resource_prefix}}-waf-policy \ + --resource-group {{ resource_group_name }} \ + --mode Prevention + # or 'Detection' + +# DRS 2.1 includes 17 rule groups, as shown in the following table. +# Each group contains multiple rules, and you can customize behavior for individual rules, rule groups, or entire rule set. +# DRS 2.1 is baselined off the Open Web Application Security Project (OWASP) Core Rule Set (CRS) 3.3.2 and includes additional proprietary protections rules developed by Microsoft Threat Intelligence team. +# https://learn.microsoft.com/en-us/azure/web-application-firewall/ag/application-gateway-crs-rulegroups-rules?tabs=owasp32#drs-21 +- name: Add managed default ruleset to WAF policy + command: > + az network front-door waf-policy managed-rules add \ + --resource-group {{ resource_group_name }} \ + --policy-name {{resource_prefix}}-waf-policy \ + --type Microsoft_DefaultRuleSet --version 2.1 --action Block + +# The Bot Manager 1.1 rule set is an enhancement to Bot Manager 1.0 rule set. It provides enhanced protection against malicious bots, and increases good bot detection. +# https://learn.microsoft.com/en-us/azure/web-application-firewall/ag/application-gateway-crs-rulegroups-rules?tabs=owasp32#bot-manager-11 +- name: Add bot ruleset to WAF policy + command: > + az network front-door waf-policy managed-rules add \ + --resource-group {{ resource_group_name }} \ + --policy-name {{resource_prefix}}-waf-policy \ + --type Microsoft_BotManagerRuleSet \ + --version 1.1 + +# The following rules are disabled by default as they result in false positives. +# https://learn.microsoft.com/en-us/azure/web-application-firewall/ag/application-gateway-crs-rulegroups-rules?tabs=owasp32#microsoft-threat-intelligence-collection-rules +# We also disable a lot because CKAN will trigger them +- name: Define rules we disable + set_fact: + azure_waf_rule_overrides: + # --type Microsoft_DefaultRuleSet --rule-group-id SQLI --rule-id 942430 + - ["Microsoft_DefaultRuleSet", "SQLI", "942430"] + - ["Microsoft_DefaultRuleSet", "RFI", "931130"] + - ["Microsoft_DefaultRuleSet", "SQLI", "942440"] + - ["Microsoft_DefaultRuleSet", "MS-ThreatIntel-SQLI", "99031002"] + - ["Microsoft_DefaultRuleSet", "SQLI", "942120"] + - ["Microsoft_DefaultRuleSet", "SQLI", "942200"] + - ["Microsoft_DefaultRuleSet", "PHP", "933210"] + - ["Microsoft_DefaultRuleSet", "General", "200003"] + - ["Microsoft_DefaultRuleSet", "General", "200002"] + - ["Microsoft_DefaultRuleSet", "SQLI", "942400"] + - ["Microsoft_DefaultRuleSet", "SQLI", "942210"] + - ["Microsoft_DefaultRuleSet", "SQLI", "942410"] + - ["Microsoft_DefaultRuleSet", "SQLI", "942150"] + - ["Microsoft_DefaultRuleSet", "MS-ThreatIntel-SQLI", "99031003"] + - ["Microsoft_DefaultRuleSet", "SQLI", "942340"] + - ["Microsoft_DefaultRuleSet", "SQLI", "942260"] + - ["Microsoft_DefaultRuleSet", "MS-ThreatIntel-SQLI", "99031004"] + - ["Microsoft_DefaultRuleSet", "SQLI", "942330"] + - ["Microsoft_DefaultRuleSet", "SQLI", "942100"] + - ["Microsoft_DefaultRuleSet", "PHP", "933160"] + - ["Microsoft_DefaultRuleSet", "SQLI", "942370"] + - ["Microsoft_DefaultRuleSet", "PROTOCOL-ATTACK", "921110"] + - ["Microsoft_DefaultRuleSet", "SQLI", "942110"] + - ["Microsoft_DefaultRuleSet", "SQLI", "942140"] + - ["Microsoft_DefaultRuleSet", "MS-ThreatIntel-SQLI", "99031001"] + - ["Microsoft_DefaultRuleSet", "XSS", "941340"] + - ["Microsoft_DefaultRuleSet", "SQLI", "942190"] + - ["Microsoft_DefaultRuleSet", "XSS", "941150"] + - ["Microsoft_DefaultRuleSet", "XSS", "941370"] + - ["Microsoft_DefaultRuleSet", "SQLI", "942390"] + - ["Microsoft_DefaultRuleSet", "SQLI", "942380"] + +- name: Apply WAF Rule Overrides + command: > + az network front-door waf-policy managed-rules override add \ + --disabled \ + --policy-name {{resource_prefix}}-waf-policy \ + --resource-group {{ resource_group_name }} \ + --type {{ item.0 }} \ + --rule-group-id {{ item.1 }} \ + --rule-id {{ item.2 }} + with_items: "{{ azure_waf_rule_overrides + (custom_azure_waf_rule_overrides | default([])) }}" + - name: Create Front Door Endpoint For Ckan command: > az afd endpoint create \ @@ -237,81 +316,3 @@ -n {{ (ckan_pls_pending_output.stdout|from_json)[0].name }} --description "Approved" when: (ckan_pls_pending_output.stdout|from_json)[0].properties.privateLinkServiceConnectionState.status == "Pending" - -- name: Create Policy for WAF - command: > - az network front-door waf-policy create \ - --name {{resource_prefix}}-waf-policy \ - --resource-group {{ resource_group_name }} \ - --mode Prevention # or 'Detection' - -# DRS 2.1 includes 17 rule groups, as shown in the following table. -# Each group contains multiple rules, and you can customize behavior for individual rules, rule groups, or entire rule set. -# DRS 2.1 is baselined off the Open Web Application Security Project (OWASP) Core Rule Set (CRS) 3.3.2 and includes additional proprietary protections rules developed by Microsoft Threat Intelligence team. -# https://learn.microsoft.com/en-us/azure/web-application-firewall/ag/application-gateway-crs-rulegroups-rules?tabs=owasp32#drs-21 -- name: Add managed default ruleset to WAF policy - command: > - az network front-door waf-policy managed-rules add \ - --resource-group {{ resource_group_name }} \ - --policy-name {{resource_prefix}}-waf-policy \ - --type Microsoft_DefaultRuleSet --version 2.1 --action Block - -# The Bot Manager 1.1 rule set is an enhancement to Bot Manager 1.0 rule set. It provides enhanced protection against malicious bots, and increases good bot detection. -# https://learn.microsoft.com/en-us/azure/web-application-firewall/ag/application-gateway-crs-rulegroups-rules?tabs=owasp32#bot-manager-11 -- name: Add bot ruleset to WAF policy - command: > - az network front-door waf-policy managed-rules add \ - --resource-group {{ resource_group_name }} \ - --policy-name {{resource_prefix}}-waf-policy \ - --type Microsoft_BotManagerRuleSet \ - --version 1.1 - -# The following rules are disabled by default as they result in false positives. -# https://learn.microsoft.com/en-us/azure/web-application-firewall/ag/application-gateway-crs-rulegroups-rules?tabs=owasp32#microsoft-threat-intelligence-collection-rules -# We also disable a lot because CKAN will trigger them -- name: Define rules we disable - set_fact: - azure_waf_rule_overrides: - # --type Microsoft_DefaultRuleSet --rule-group-id SQLI --rule-id 942430 - - ["Microsoft_DefaultRuleSet", "SQLI", "942430"] - - ["Microsoft_DefaultRuleSet", "RFI", "931130"] - - ["Microsoft_DefaultRuleSet", "SQLI", "942440"] - - ["Microsoft_DefaultRuleSet", "MS-ThreatIntel-SQLI", "99031002"] - - ["Microsoft_DefaultRuleSet", "SQLI", "942120"] - - ["Microsoft_DefaultRuleSet", "SQLI", "942200"] - - ["Microsoft_DefaultRuleSet", "PHP", "933210"] - - ["Microsoft_DefaultRuleSet", "General", "200003"] - - ["Microsoft_DefaultRuleSet", "General", "200002"] - - ["Microsoft_DefaultRuleSet", "SQLI", "942400"] - - ["Microsoft_DefaultRuleSet", "SQLI", "942210"] - - ["Microsoft_DefaultRuleSet", "SQLI", "942410"] - - ["Microsoft_DefaultRuleSet", "SQLI", "942150"] - - ["Microsoft_DefaultRuleSet", "MS-ThreatIntel-SQLI", "99031003"] - - ["Microsoft_DefaultRuleSet", "SQLI", "942340"] - - ["Microsoft_DefaultRuleSet", "SQLI", "942260"] - - ["Microsoft_DefaultRuleSet", "MS-ThreatIntel-SQLI", "99031004"] - - ["Microsoft_DefaultRuleSet", "SQLI", "942330"] - - ["Microsoft_DefaultRuleSet", "SQLI", "942100"] - - ["Microsoft_DefaultRuleSet", "PHP", "933160"] - - ["Microsoft_DefaultRuleSet", "SQLI", "942370"] - - ["Microsoft_DefaultRuleSet", "PROTOCOL-ATTACK", "921110"] - - ["Microsoft_DefaultRuleSet", "SQLI", "942110"] - - ["Microsoft_DefaultRuleSet", "SQLI", "942140"] - - ["Microsoft_DefaultRuleSet", "MS-ThreatIntel-SQLI", "99031001"] - - ["Microsoft_DefaultRuleSet", "XSS", "941340"] - - ["Microsoft_DefaultRuleSet", "SQLI", "942190"] - - ["Microsoft_DefaultRuleSet", "XSS", "941150"] - - ["Microsoft_DefaultRuleSet", "XSS", "941370"] - - ["Microsoft_DefaultRuleSet", "SQLI", "942390"] - - ["Microsoft_DefaultRuleSet", "SQLI", "942380"] - -- name: Apply WAF Rule Overrides - command: > - az network front-door waf-policy managed-rules override add \ - --disabled \ - --policy-name {{resource_prefix}}-waf-policy \ - --resource-group {{ resource_group_name }} \ - --type {{ item.0 }} \ - --rule-group-id {{ item.1 }} \ - --rule-id {{ item.2 }} - with_items: "{{ azure_waf_rule_overrides + (custom_azure_waf_rule_overrides | default([])) }}" From 5dbddb464028da0c27e4ef23193ec04353c749bf Mon Sep 17 00:00:00 2001 From: Craig Cooper Date: Fri, 27 Dec 2024 13:33:45 +0700 Subject: [PATCH 09/36] fix: use alphanumeric name for waf policy --- group_vars/all/azure.yml | 11 ++++++----- roles/setup-azure-frontdoor/tasks/main.yml | 11 +++++++---- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/group_vars/all/azure.yml b/group_vars/all/azure.yml index 554d0d7..a06d398 100644 --- a/group_vars/all/azure.yml +++ b/group_vars/all/azure.yml @@ -25,17 +25,18 @@ resource_prefix: "{{application_name}}-{{resource_group_environment}}" resource_group_name: "{{resource_prefix}}-{{resource_group_region}}-RG01" node_group_name: "{{resource_prefix}}-{{resource_group_region}}-RGMC" -acr_name: "{{application_name|lower}}{{resource_group_environment}}acr" -vault_name: "{{application_name|lower}}{{resource_group_environment}}vault" -storage_account_name: "{{application_name|lower}}{{resource_group_environment|lower}}sta" +alphanumeric_resource_name_prefix: "{{application_name|lower}}{{resource_group_environment}}" + +acr_name: "{{alphanumeric_resource_name_prefix}}acr" +vault_name: "{{alphanumeric_resource_name_prefix}}vault" +storage_account_name: "{{alphanumeric_resource_name_prefix|lower}}sta" # Names for the private link services between K8S and Front Door ckan_pls_name: ckan-pls giftless_pls_name: giftless-pls -ckan_superuser_name: "superuser" +ckan_superuser_name: "superuser" ckan_superuser_email: "super@example.com" # This is an azure object ID that will have access to the KeyVault. It should be the object ID of the service principal that is used to run the ansible scripts vault_object_id: 000000-0000-000-0000 - diff --git a/roles/setup-azure-frontdoor/tasks/main.yml b/roles/setup-azure-frontdoor/tasks/main.yml index 8b5128d..51999e4 100644 --- a/roles/setup-azure-frontdoor/tasks/main.yml +++ b/roles/setup-azure-frontdoor/tasks/main.yml @@ -13,10 +13,13 @@ --resource-group {{ resource_group_name }} \ --sku Premium_AzureFrontDoor +- set_fact: + waf_policy_name: "{{ alphanumeric_resource_name_prefix | lower }}wafpolicy" + - name: Create Policy for WAF command: > az network front-door waf-policy create \ - --name {{resource_prefix}}-waf-policy \ + --name {{ waf_policy_name }} \ --resource-group {{ resource_group_name }} \ --mode Prevention # or 'Detection' @@ -29,7 +32,7 @@ command: > az network front-door waf-policy managed-rules add \ --resource-group {{ resource_group_name }} \ - --policy-name {{resource_prefix}}-waf-policy \ + --policy-name {{ waf_policy_name }} \ --type Microsoft_DefaultRuleSet --version 2.1 --action Block # The Bot Manager 1.1 rule set is an enhancement to Bot Manager 1.0 rule set. It provides enhanced protection against malicious bots, and increases good bot detection. @@ -38,7 +41,7 @@ command: > az network front-door waf-policy managed-rules add \ --resource-group {{ resource_group_name }} \ - --policy-name {{resource_prefix}}-waf-policy \ + --policy-name {{ waf_policy_name }} \ --type Microsoft_BotManagerRuleSet \ --version 1.1 @@ -85,7 +88,7 @@ command: > az network front-door waf-policy managed-rules override add \ --disabled \ - --policy-name {{resource_prefix}}-waf-policy \ + --policy-name {{waf_policy_name}} \ --resource-group {{ resource_group_name }} \ --type {{ item.0 }} \ --rule-group-id {{ item.1 }} \ From 454d638eaba2c2fd2ac2cab0263d738e04d34e29 Mon Sep 17 00:00:00 2001 From: Craig Cooper Date: Fri, 27 Dec 2024 14:00:55 +0700 Subject: [PATCH 10/36] fix: loop correctly thro exclusions --- roles/setup-azure-frontdoor/tasks/main.yml | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/roles/setup-azure-frontdoor/tasks/main.yml b/roles/setup-azure-frontdoor/tasks/main.yml index 51999e4..89f03f3 100644 --- a/roles/setup-azure-frontdoor/tasks/main.yml +++ b/roles/setup-azure-frontdoor/tasks/main.yml @@ -86,14 +86,17 @@ - name: Apply WAF Rule Overrides command: > + echo "{{ item }}" + echo "{{ item[0] }}" + az network front-door waf-policy managed-rules override add \ --disabled \ --policy-name {{waf_policy_name}} \ --resource-group {{ resource_group_name }} \ - --type {{ item.0 }} \ - --rule-group-id {{ item.1 }} \ - --rule-id {{ item.2 }} - with_items: "{{ azure_waf_rule_overrides + (custom_azure_waf_rule_overrides | default([])) }}" + --type {{ item[0] }} \ + --rule-group-id {{ item[1] }} \ + --rule-id {{ item[2] }} + loop: "{{ azure_waf_rule_overrides + (custom_azure_waf_rule_overrides | default([])) }}" - name: Create Front Door Endpoint For Ckan command: > From c85aaacf4984b04fb435f038b070766483730212 Mon Sep 17 00:00:00 2001 From: Craig Cooper Date: Fri, 27 Dec 2024 14:08:17 +0700 Subject: [PATCH 11/36] fix: loop correctly thro exclusions --- roles/setup-azure-frontdoor/tasks/main.yml | 3 --- 1 file changed, 3 deletions(-) diff --git a/roles/setup-azure-frontdoor/tasks/main.yml b/roles/setup-azure-frontdoor/tasks/main.yml index 89f03f3..b5beb31 100644 --- a/roles/setup-azure-frontdoor/tasks/main.yml +++ b/roles/setup-azure-frontdoor/tasks/main.yml @@ -86,9 +86,6 @@ - name: Apply WAF Rule Overrides command: > - echo "{{ item }}" - echo "{{ item[0] }}" - az network front-door waf-policy managed-rules override add \ --disabled \ --policy-name {{waf_policy_name}} \ From 01ade56995694b511a997bbd3df5ebb342059434 Mon Sep 17 00:00:00 2001 From: Craig Cooper Date: Fri, 27 Dec 2024 14:10:41 +0700 Subject: [PATCH 12/36] fix: comment --- roles/setup-azure-frontdoor/tasks/main.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/roles/setup-azure-frontdoor/tasks/main.yml b/roles/setup-azure-frontdoor/tasks/main.yml index b5beb31..5282c71 100644 --- a/roles/setup-azure-frontdoor/tasks/main.yml +++ b/roles/setup-azure-frontdoor/tasks/main.yml @@ -47,7 +47,9 @@ # The following rules are disabled by default as they result in false positives. # https://learn.microsoft.com/en-us/azure/web-application-firewall/ag/application-gateway-crs-rulegroups-rules?tabs=owasp32#microsoft-threat-intelligence-collection-rules -# We also disable a lot because CKAN will trigger them + +# We also disable a lot because CKAN will trigger them, these were found by logging the WAF logs and seeing what was being triggered during normal use of CKAN. +# Additional custom rules can be added to the list below, in the format ["rule-set", "rule-group-id", "rule-id"], or defined in the inventory/group_vars etc as a list of lists (like this) under `custom_azure_waf_rule_overrides` - name: Define rules we disable set_fact: azure_waf_rule_overrides: From 77823fe6b732c816f9c80ca5662001bc6c5374db Mon Sep 17 00:00:00 2001 From: Craig Cooper Date: Fri, 27 Dec 2024 15:20:50 +0700 Subject: [PATCH 13/36] fix: handle custom domain in Azure WAF --- roles/setup-azure-frontdoor/tasks/main.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/roles/setup-azure-frontdoor/tasks/main.yml b/roles/setup-azure-frontdoor/tasks/main.yml index 5282c71..fae7582 100644 --- a/roles/setup-azure-frontdoor/tasks/main.yml +++ b/roles/setup-azure-frontdoor/tasks/main.yml @@ -257,6 +257,8 @@ --private-link-request-message 'Please approve this request' \ --private-link-location {{ azure_region }} +# If a custom domain is set, the route is attached to that, if not (ie on first run or without a custom domain) it is attached to the default domain +# The WAf policy is attached to the route later - name: Create route for CKAN command: > az afd route create \ @@ -268,9 +270,9 @@ --origin-group {{resource_prefix}}-og-ckan \ --enabled-state Enabled \ --supported-protocols Https \ - --link-to-default-domain Enabled \ --https-redirect Enabled \ - --forwarding-protocol HttpOnly + --forwarding-protocol HttpOnly \ + {{ custom_afd_domain | ternary('--custom-domains custom_afd_domain, '--link-to-default-domain Enabled') }} - name: Create route for Giftless command: > From 619d4edae0f784c24a3513d7ffe8a251459e71cc Mon Sep 17 00:00:00 2001 From: Craig Cooper Date: Fri, 27 Dec 2024 15:26:14 +0700 Subject: [PATCH 14/36] fix: handle custom domain in Azure WAF --- roles/setup-azure-frontdoor/tasks/main.yml | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/roles/setup-azure-frontdoor/tasks/main.yml b/roles/setup-azure-frontdoor/tasks/main.yml index fae7582..982349b 100644 --- a/roles/setup-azure-frontdoor/tasks/main.yml +++ b/roles/setup-azure-frontdoor/tasks/main.yml @@ -272,7 +272,7 @@ --supported-protocols Https \ --https-redirect Enabled \ --forwarding-protocol HttpOnly \ - {{ custom_afd_domain | ternary('--custom-domains custom_afd_domain, '--link-to-default-domain Enabled') }} + {{ custom_afd_domain | ternary('--custom-domains custom_afd_domain', '--link-to-default-domain Enabled') }} - name: Create route for Giftless command: > @@ -323,3 +323,11 @@ -n {{ (ckan_pls_pending_output.stdout|from_json)[0].name }} --description "Approved" when: (ckan_pls_pending_output.stdout|from_json)[0].properties.privateLinkServiceConnectionState.status == "Pending" + +# - name: Apply the WAF policy to the endpoint +# command: > +# az afd security-policy create \ +# --resource-group {{ resource_group_name }} \ +# --profile-name {{resource_prefix}}-afd \ +# --security-policy-name contososecurity \ +# --domains /subscriptions/mysubscription/resourcegroups/myRGFD/providers/Microsoft.Cdn/profiles/contosoafd/afdEndpoints/contosofrontend --waf-policy /subscriptions/mysubscription/resourcegroups/myRGFD/providers/Microsoft.Network/frontdoorwebapplicationfirewallpolicies/contosoWAF From b389df10e841bf3d1ddc8b733a2eacc4e076ed0b Mon Sep 17 00:00:00 2001 From: Craig Cooper Date: Fri, 27 Dec 2024 15:40:47 +0700 Subject: [PATCH 15/36] fix: handle custom domain in Azure WAF --- roles/setup-azure-frontdoor/tasks/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/roles/setup-azure-frontdoor/tasks/main.yml b/roles/setup-azure-frontdoor/tasks/main.yml index 982349b..d2bddee 100644 --- a/roles/setup-azure-frontdoor/tasks/main.yml +++ b/roles/setup-azure-frontdoor/tasks/main.yml @@ -272,7 +272,7 @@ --supported-protocols Https \ --https-redirect Enabled \ --forwarding-protocol HttpOnly \ - {{ custom_afd_domain | ternary('--custom-domains custom_afd_domain', '--link-to-default-domain Enabled') }} + {{ custom_afd_domain_id | ternary('--custom-domains ' + custom_afd_domain_id, '--link-to-default-domain Enabled') }} - name: Create route for Giftless command: > From 03f2a7554e78981113a77a110c7f426c60f4baf0 Mon Sep 17 00:00:00 2001 From: Craig Cooper Date: Fri, 27 Dec 2024 17:22:42 +0700 Subject: [PATCH 16/36] fix: apply WAF to endpoint --- roles/setup-azure-frontdoor/tasks/main.yml | 27 +++++++++++++--------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/roles/setup-azure-frontdoor/tasks/main.yml b/roles/setup-azure-frontdoor/tasks/main.yml index d2bddee..eb41cbf 100644 --- a/roles/setup-azure-frontdoor/tasks/main.yml +++ b/roles/setup-azure-frontdoor/tasks/main.yml @@ -97,12 +97,16 @@ --rule-id {{ item[2] }} loop: "{{ azure_waf_rule_overrides + (custom_azure_waf_rule_overrides | default([])) }}" +- set_fact: + ckan_endpoint_name: "{{ resource_prefix|lower }}-ckan" + giftless_endpoint_name: "{{ resource_prefix|lower }}-giftless" + - name: Create Front Door Endpoint For Ckan command: > az afd endpoint create \ --resource-group {{ resource_group_name }} \ --profile-name {{resource_prefix}}-afd \ - --endpoint-name {{resource_prefix|lower}}-ckan \ + --endpoint-name {{ ckan_endpoint_name }} \ --enabled-state Enabled register: ckan_endpoint_output @@ -111,7 +115,7 @@ az afd endpoint create \ --resource-group {{ resource_group_name }} \ --profile-name {{resource_prefix}}-afd \ - --endpoint-name {{resource_prefix|lower}}-giftless \ + --endpoint-name {{ giftless_endpoint_name }} \ --enabled-state Enabled register: giftless_endpoint_output @@ -265,7 +269,7 @@ --resource-group {{ resource_group_name }} \ --profile-name {{resource_prefix}}-afd \ --route-name ckan-route \ - --endpoint-name {{resource_prefix|lower}}-ckan \ + --endpoint-name {{ ckan_endpoint_name }} \ --patterns '/*' \ --origin-group {{resource_prefix}}-og-ckan \ --enabled-state Enabled \ @@ -280,7 +284,7 @@ --resource-group {{ resource_group_name }} \ --profile-name {{resource_prefix}}-afd \ --route-name giftless-route \ - --endpoint-name {{resource_prefix|lower}}-giftless \ + --endpoint-name {{ giftless_endpoint_name }} \ --patterns '/*' \ --origin-group {{resource_prefix}}-og-giftless \ --enabled-state Enabled \ @@ -324,10 +328,11 @@ --description "Approved" when: (ckan_pls_pending_output.stdout|from_json)[0].properties.privateLinkServiceConnectionState.status == "Pending" -# - name: Apply the WAF policy to the endpoint -# command: > -# az afd security-policy create \ -# --resource-group {{ resource_group_name }} \ -# --profile-name {{resource_prefix}}-afd \ -# --security-policy-name contososecurity \ -# --domains /subscriptions/mysubscription/resourcegroups/myRGFD/providers/Microsoft.Cdn/profiles/contosoafd/afdEndpoints/contosofrontend --waf-policy /subscriptions/mysubscription/resourcegroups/myRGFD/providers/Microsoft.Network/frontdoorwebapplicationfirewallpolicies/contosoWAF +- name: Apply the WAF policy to the endpoint + command: > + az afd security-policy create \ + --resource-group {{ resource_group_name }} \ + --profile-name {{ resource_prefix }}-afd \ + --security-policy-name "{{ alphanumeric_resource_name_prefix | lower }}secpolicy" \ + --domains {{ custom_afd_domain_id | ternary(custom_afd_domain_id, ckan_endpoint_name) }} \ + --waf-policy {{ waf_policy_name }} From 286d21fdd0fef89c7f3f8b0232b70a5c15dd3fe5 Mon Sep 17 00:00:00 2001 From: Craig Cooper Date: Fri, 27 Dec 2024 17:24:59 +0700 Subject: [PATCH 17/36] fix: add cors for custom domain --- roles/setup-azure-frontdoor/tasks/main.yml | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/roles/setup-azure-frontdoor/tasks/main.yml b/roles/setup-azure-frontdoor/tasks/main.yml index eb41cbf..8ade809 100644 --- a/roles/setup-azure-frontdoor/tasks/main.yml +++ b/roles/setup-azure-frontdoor/tasks/main.yml @@ -145,6 +145,23 @@ --header-name Access-Control-Allow-Origin \ --header-value {{ ckan_hostname }} +- name: CORS Origin header and condition custom domain rule + command: > + az afd rule create \ + --resource-group {{ resource_group_name }} \ + --rule-set-name giftlesscors \ + --profile-name {{resource_prefix}}-afd \ + --rule-name corsheaders \ + --selector Origin \ + --match-variable RequestHeader \ + --operator Equal \ + --match-values {{ ckan_site_url }} \ + --action-name ModifyResponseHeader \ + --header-action Overwrite \ + --header-name Access-Control-Allow-Origin \ + --header-value {{ ckan_site_url }} + when: custom_afd_domain_id is defined + - name: Add CORS Headers header to rule command: > az afd rule action add --resource-group {{ resource_group_name }} \ From 7562c82a13563600dbc6155ae562524f6b35d0fb Mon Sep 17 00:00:00 2001 From: Craig Cooper Date: Fri, 27 Dec 2024 17:49:08 +0700 Subject: [PATCH 18/36] fix: full id required --- roles/setup-azure-frontdoor/tasks/main.yml | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/roles/setup-azure-frontdoor/tasks/main.yml b/roles/setup-azure-frontdoor/tasks/main.yml index 8ade809..aafef03 100644 --- a/roles/setup-azure-frontdoor/tasks/main.yml +++ b/roles/setup-azure-frontdoor/tasks/main.yml @@ -278,8 +278,9 @@ --private-link-request-message 'Please approve this request' \ --private-link-location {{ azure_region }} -# If a custom domain is set, the route is attached to that, if not (ie on first run or without a custom domain) it is attached to the default domain -# The WAf policy is attached to the route later +# If a custom domain is set, the route is attached to that, if not (ie on first run or without a custom domain) it is attached to the default domain. +# We only attach it to one domain at a time, but to debug, you CAN manually add the route to the other domain in the Azure Portal. +# The WAF policy is attached to the route later - name: Create route for CKAN command: > az afd route create \ @@ -345,11 +346,19 @@ --description "Approved" when: (ckan_pls_pending_output.stdout|from_json)[0].properties.privateLinkServiceConnectionState.status == "Pending" +- set_fact: + custom_afd_domain_full_id: "/subscriptions/{{ subscription_output.subscriptions[0].subscription_id }}/resourcegroups/{{ resource_group_name }}/providers/Microsoft.Cdn/profiles/{{ resource_prefix }}-afd/customdomains/{{ custom_afd_domain_id }}" + when: custom_afd_domain_id is defined +- set_fact: +# /subscriptions/ec6de091-2438-4d4e-a60a-e7aff6f2cbcd/resourcegroups/AFDATAHUB-T-EU-RG01/providers/Microsoft.Cdn/profiles/AFDATAHUB-T-afd/afdendpoints/afdatahub-t-ckan + endpoint_full_id: "/subscriptions/{{ subscription_output.subscriptions[0].subscription_id }}/resourcegroups/{{ resource_group_name }}/providers/Microsoft.Cdn/profiles/{{ resource_prefix }}-afd/afdendpoints/{{ ckan_endpoint_name }}" + when: custom_afd_domain_id is not defined + - name: Apply the WAF policy to the endpoint command: > az afd security-policy create \ --resource-group {{ resource_group_name }} \ --profile-name {{ resource_prefix }}-afd \ --security-policy-name "{{ alphanumeric_resource_name_prefix | lower }}secpolicy" \ - --domains {{ custom_afd_domain_id | ternary(custom_afd_domain_id, ckan_endpoint_name) }} \ + --domains {{ custom_afd_domain_id | ternary(custom_afd_domain_full_id, endpoint_full_id) }} \ --waf-policy {{ waf_policy_name }} From 915b45bdd34e23e60ae439cf611ce7d8db24818e Mon Sep 17 00:00:00 2001 From: Craig Cooper Date: Fri, 27 Dec 2024 18:55:09 +0700 Subject: [PATCH 19/36] fix: full id required --- roles/setup-azure-frontdoor/tasks/main.yml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/roles/setup-azure-frontdoor/tasks/main.yml b/roles/setup-azure-frontdoor/tasks/main.yml index aafef03..5806ecb 100644 --- a/roles/setup-azure-frontdoor/tasks/main.yml +++ b/roles/setup-azure-frontdoor/tasks/main.yml @@ -349,11 +349,14 @@ - set_fact: custom_afd_domain_full_id: "/subscriptions/{{ subscription_output.subscriptions[0].subscription_id }}/resourcegroups/{{ resource_group_name }}/providers/Microsoft.Cdn/profiles/{{ resource_prefix }}-afd/customdomains/{{ custom_afd_domain_id }}" when: custom_afd_domain_id is defined + - set_fact: -# /subscriptions/ec6de091-2438-4d4e-a60a-e7aff6f2cbcd/resourcegroups/AFDATAHUB-T-EU-RG01/providers/Microsoft.Cdn/profiles/AFDATAHUB-T-afd/afdendpoints/afdatahub-t-ckan endpoint_full_id: "/subscriptions/{{ subscription_output.subscriptions[0].subscription_id }}/resourcegroups/{{ resource_group_name }}/providers/Microsoft.Cdn/profiles/{{ resource_prefix }}-afd/afdendpoints/{{ ckan_endpoint_name }}" when: custom_afd_domain_id is not defined +- set_fact: + waf_policy_id: "/subscriptions/{{ subscription_output.subscriptions[0].subscription_id }}/resourcegroups/{{ resource_group_name }}/providers/Microsoft.Network/frontDoorWebApplicationFirewallPolicies/{{ waf_policy_name }}" + - name: Apply the WAF policy to the endpoint command: > az afd security-policy create \ @@ -361,4 +364,4 @@ --profile-name {{ resource_prefix }}-afd \ --security-policy-name "{{ alphanumeric_resource_name_prefix | lower }}secpolicy" \ --domains {{ custom_afd_domain_id | ternary(custom_afd_domain_full_id, endpoint_full_id) }} \ - --waf-policy {{ waf_policy_name }} + --waf-policy {{ waf_policy_id }} From 59660412a33ff70a6f8926282e6cef46143d4113 Mon Sep 17 00:00:00 2001 From: Craig Cooper Date: Fri, 27 Dec 2024 19:14:29 +0700 Subject: [PATCH 20/36] fix: apply WAF to giftless too --- roles/setup-azure-frontdoor/tasks/main.yml | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/roles/setup-azure-frontdoor/tasks/main.yml b/roles/setup-azure-frontdoor/tasks/main.yml index 5806ecb..624981f 100644 --- a/roles/setup-azure-frontdoor/tasks/main.yml +++ b/roles/setup-azure-frontdoor/tasks/main.yml @@ -351,17 +351,29 @@ when: custom_afd_domain_id is defined - set_fact: - endpoint_full_id: "/subscriptions/{{ subscription_output.subscriptions[0].subscription_id }}/resourcegroups/{{ resource_group_name }}/providers/Microsoft.Cdn/profiles/{{ resource_prefix }}-afd/afdendpoints/{{ ckan_endpoint_name }}" + ckan_endpoint_full_id: "/subscriptions/{{ subscription_output.subscriptions[0].subscription_id }}/resourcegroups/{{ resource_group_name }}/providers/Microsoft.Cdn/profiles/{{ resource_prefix }}-afd/afdendpoints/{{ ckan_endpoint_name }}" when: custom_afd_domain_id is not defined +- set_fact: + giftless_endpoint_full_id: "/subscriptions/{{ subscription_output.subscriptions[0].subscription_id }}/resourcegroups/{{ resource_group_name }}/providers/Microsoft.Cdn/profiles/{{ resource_prefix }}-afd/afdendpoints/{{ giftless_endpoint_name }}" + - set_fact: waf_policy_id: "/subscriptions/{{ subscription_output.subscriptions[0].subscription_id }}/resourcegroups/{{ resource_group_name }}/providers/Microsoft.Network/frontDoorWebApplicationFirewallPolicies/{{ waf_policy_name }}" -- name: Apply the WAF policy to the endpoint +- name: Apply the WAF policy to the CKAN endpoint + command: > + az afd security-policy create \ + --resource-group {{ resource_group_name }} \ + --profile-name {{ resource_prefix }}-afd \ + --security-policy-name "{{ alphanumeric_resource_name_prefix | lower }}secpolicy" \ + --domains {{ custom_afd_domain_id | ternary(custom_afd_domain_full_id, ckan_endpoint_full_id) }} \ + --waf-policy {{ waf_policy_id }} + +- name: Apply the WAF policy to the Giftless endpoint command: > az afd security-policy create \ --resource-group {{ resource_group_name }} \ --profile-name {{ resource_prefix }}-afd \ --security-policy-name "{{ alphanumeric_resource_name_prefix | lower }}secpolicy" \ - --domains {{ custom_afd_domain_id | ternary(custom_afd_domain_full_id, endpoint_full_id) }} \ + --domains {{ giftless_endpoint_full_id }} \ --waf-policy {{ waf_policy_id }} From 835245e243f459c280e5a4c7fb1c7b2dd501bbc8 Mon Sep 17 00:00:00 2001 From: Craig Cooper Date: Sat, 28 Dec 2024 08:16:35 +0700 Subject: [PATCH 21/36] fix: tidy up waf --- roles/setup-azure-frontdoor/tasks/main.yml | 90 +++------------------- roles/setup-azure-frontdoor/tasks/waf.yml | 85 ++++++++++++++++++++ 2 files changed, 95 insertions(+), 80 deletions(-) create mode 100644 roles/setup-azure-frontdoor/tasks/waf.yml diff --git a/roles/setup-azure-frontdoor/tasks/main.yml b/roles/setup-azure-frontdoor/tasks/main.yml index 624981f..e27988a 100644 --- a/roles/setup-azure-frontdoor/tasks/main.yml +++ b/roles/setup-azure-frontdoor/tasks/main.yml @@ -24,78 +24,8 @@ --mode Prevention # or 'Detection' -# DRS 2.1 includes 17 rule groups, as shown in the following table. -# Each group contains multiple rules, and you can customize behavior for individual rules, rule groups, or entire rule set. -# DRS 2.1 is baselined off the Open Web Application Security Project (OWASP) Core Rule Set (CRS) 3.3.2 and includes additional proprietary protections rules developed by Microsoft Threat Intelligence team. -# https://learn.microsoft.com/en-us/azure/web-application-firewall/ag/application-gateway-crs-rulegroups-rules?tabs=owasp32#drs-21 -- name: Add managed default ruleset to WAF policy - command: > - az network front-door waf-policy managed-rules add \ - --resource-group {{ resource_group_name }} \ - --policy-name {{ waf_policy_name }} \ - --type Microsoft_DefaultRuleSet --version 2.1 --action Block - -# The Bot Manager 1.1 rule set is an enhancement to Bot Manager 1.0 rule set. It provides enhanced protection against malicious bots, and increases good bot detection. -# https://learn.microsoft.com/en-us/azure/web-application-firewall/ag/application-gateway-crs-rulegroups-rules?tabs=owasp32#bot-manager-11 -- name: Add bot ruleset to WAF policy - command: > - az network front-door waf-policy managed-rules add \ - --resource-group {{ resource_group_name }} \ - --policy-name {{ waf_policy_name }} \ - --type Microsoft_BotManagerRuleSet \ - --version 1.1 - -# The following rules are disabled by default as they result in false positives. -# https://learn.microsoft.com/en-us/azure/web-application-firewall/ag/application-gateway-crs-rulegroups-rules?tabs=owasp32#microsoft-threat-intelligence-collection-rules - -# We also disable a lot because CKAN will trigger them, these were found by logging the WAF logs and seeing what was being triggered during normal use of CKAN. -# Additional custom rules can be added to the list below, in the format ["rule-set", "rule-group-id", "rule-id"], or defined in the inventory/group_vars etc as a list of lists (like this) under `custom_azure_waf_rule_overrides` -- name: Define rules we disable - set_fact: - azure_waf_rule_overrides: - # --type Microsoft_DefaultRuleSet --rule-group-id SQLI --rule-id 942430 - - ["Microsoft_DefaultRuleSet", "SQLI", "942430"] - - ["Microsoft_DefaultRuleSet", "RFI", "931130"] - - ["Microsoft_DefaultRuleSet", "SQLI", "942440"] - - ["Microsoft_DefaultRuleSet", "MS-ThreatIntel-SQLI", "99031002"] - - ["Microsoft_DefaultRuleSet", "SQLI", "942120"] - - ["Microsoft_DefaultRuleSet", "SQLI", "942200"] - - ["Microsoft_DefaultRuleSet", "PHP", "933210"] - - ["Microsoft_DefaultRuleSet", "General", "200003"] - - ["Microsoft_DefaultRuleSet", "General", "200002"] - - ["Microsoft_DefaultRuleSet", "SQLI", "942400"] - - ["Microsoft_DefaultRuleSet", "SQLI", "942210"] - - ["Microsoft_DefaultRuleSet", "SQLI", "942410"] - - ["Microsoft_DefaultRuleSet", "SQLI", "942150"] - - ["Microsoft_DefaultRuleSet", "MS-ThreatIntel-SQLI", "99031003"] - - ["Microsoft_DefaultRuleSet", "SQLI", "942340"] - - ["Microsoft_DefaultRuleSet", "SQLI", "942260"] - - ["Microsoft_DefaultRuleSet", "MS-ThreatIntel-SQLI", "99031004"] - - ["Microsoft_DefaultRuleSet", "SQLI", "942330"] - - ["Microsoft_DefaultRuleSet", "SQLI", "942100"] - - ["Microsoft_DefaultRuleSet", "PHP", "933160"] - - ["Microsoft_DefaultRuleSet", "SQLI", "942370"] - - ["Microsoft_DefaultRuleSet", "PROTOCOL-ATTACK", "921110"] - - ["Microsoft_DefaultRuleSet", "SQLI", "942110"] - - ["Microsoft_DefaultRuleSet", "SQLI", "942140"] - - ["Microsoft_DefaultRuleSet", "MS-ThreatIntel-SQLI", "99031001"] - - ["Microsoft_DefaultRuleSet", "XSS", "941340"] - - ["Microsoft_DefaultRuleSet", "SQLI", "942190"] - - ["Microsoft_DefaultRuleSet", "XSS", "941150"] - - ["Microsoft_DefaultRuleSet", "XSS", "941370"] - - ["Microsoft_DefaultRuleSet", "SQLI", "942390"] - - ["Microsoft_DefaultRuleSet", "SQLI", "942380"] - -- name: Apply WAF Rule Overrides - command: > - az network front-door waf-policy managed-rules override add \ - --disabled \ - --policy-name {{waf_policy_name}} \ - --resource-group {{ resource_group_name }} \ - --type {{ item[0] }} \ - --rule-group-id {{ item[1] }} \ - --rule-id {{ item[2] }} - loop: "{{ azure_waf_rule_overrides + (custom_azure_waf_rule_overrides | default([])) }}" +- name: Create WAF Policy + include_tasks: waf.yml - set_fact: ckan_endpoint_name: "{{ resource_prefix|lower }}-ckan" @@ -105,7 +35,7 @@ command: > az afd endpoint create \ --resource-group {{ resource_group_name }} \ - --profile-name {{resource_prefix}}-afd \ + --profile-name {{ resource_prefix }}-afd \ --endpoint-name {{ ckan_endpoint_name }} \ --enabled-state Enabled register: ckan_endpoint_output @@ -114,7 +44,7 @@ command: > az afd endpoint create \ --resource-group {{ resource_group_name }} \ - --profile-name {{resource_prefix}}-afd \ + --profile-name {{ resource_prefix }}-afd \ --endpoint-name {{ giftless_endpoint_name }} \ --enabled-state Enabled register: giftless_endpoint_output @@ -134,7 +64,7 @@ az afd rule create \ --resource-group {{ resource_group_name }} \ --rule-set-name giftlesscors \ - --profile-name {{resource_prefix}}-afd \ + --profile-name {{ resource_prefix }}-afd \ --rule-name corsheaders \ --selector Origin \ --match-variable RequestHeader \ @@ -166,7 +96,7 @@ command: > az afd rule action add --resource-group {{ resource_group_name }} \ --rule-set-name giftlesscors \ - --profile-name {{resource_prefix}}-afd \ + --profile-name {{ resource_prefix }}-afd \ --rule-name corsheaders \ --action-name ModifyResponseHeader \ --header-action Overwrite \ @@ -177,7 +107,7 @@ command: > az afd rule action add --resource-group {{ resource_group_name }} \ --rule-set-name giftlesscors \ - --profile-name {{resource_prefix}}-afd \ + --profile-name {{ resource_prefix }}-afd \ --rule-name corsheaders \ --action-name ModifyResponseHeader \ --header-action Overwrite \ @@ -189,7 +119,7 @@ command: > az afd origin-group create \ --resource-group {{ resource_group_name }} \ - --profile-name {{resource_prefix}}-afd \ + --profile-name {{ resource_prefix }}-afd \ --origin-group-name {{resource_prefix}}-og-ckan \ --probe-request-type GET \ --probe-protocol Http \ @@ -204,7 +134,7 @@ command: > az afd origin-group create \ --resource-group {{ resource_group_name }} \ - --profile-name {{resource_prefix}}-afd \ + --profile-name {{ resource_prefix }}-afd \ --origin-group-name {{resource_prefix}}-og-giftless \ --probe-request-type GET \ --probe-protocol Http \ @@ -235,7 +165,7 @@ --host-name {{ ckan_pls_alias }} \ --origin-host-header {{ ckan_fqdn }} \ --resource-group {{ resource_group_name }} \ - --profile-name {{resource_prefix}}-afd \ + --profile-name {{ resource_prefix }}-afd \ --origin-group-name {{resource_prefix}}-og-ckan \ --origin-name ckan-origin \ --priority 1 \ diff --git a/roles/setup-azure-frontdoor/tasks/waf.yml b/roles/setup-azure-frontdoor/tasks/waf.yml new file mode 100644 index 0000000..8fe891a --- /dev/null +++ b/roles/setup-azure-frontdoor/tasks/waf.yml @@ -0,0 +1,85 @@ + +# DRS 2.1 includes 17 rule groups, as shown in the following table. +# Each group contains multiple rules, and you can customize behavior for individual rules, rule groups, or entire rule set. +# DRS 2.1 is baselined off the Open Web Application Security Project (OWASP) Core Rule Set (CRS) 3.3.2 and includes additional proprietary protections rules developed by Microsoft Threat Intelligence team. +# https://learn.microsoft.com/en-us/azure/web-application-firewall/ag/application-gateway-crs-rulegroups-rules?tabs=owasp32#drs-21 +- name: Add managed default ruleset to WAF policy + command: > + az network front-door waf-policy managed-rules add \ + --resource-group {{ resource_group_name }} \ + --policy-name {{ waf_policy_name }} \ + --type Microsoft_DefaultRuleSet --version 2.1 --action Block + +# The Bot Manager 1.1 rule set is an enhancement to Bot Manager 1.0 rule set. It provides enhanced protection against malicious bots, and increases good bot detection. +# https://learn.microsoft.com/en-us/azure/web-application-firewall/ag/application-gateway-crs-rulegroups-rules?tabs=owasp32#bot-manager-11 +- name: Add bot ruleset to WAF policy + command: > + az network front-door waf-policy managed-rules add \ + --resource-group {{ resource_group_name }} \ + --policy-name {{ waf_policy_name }} \ + --type Microsoft_BotManagerRuleSet \ + --version 1.1 + +# The following rules are disabled by default as they result in false positives. +# https://learn.microsoft.com/en-us/azure/web-application-firewall/ag/application-gateway-crs-rulegroups-rules?tabs=owasp32#microsoft-threat-intelligence-collection-rules + +# We also disable a lot because CKAN will trigger them, these were found by logging the WAF logs and seeing what was being triggered during normal use of CKAN. +# Additional custom rules can be added to the list below, in the format ["rule-set", "rule-group-id", "rule-id"], or defined in the inventory/group_vars etc as a list of lists (like this) under `custom_azure_waf_rule_overrides` +- name: Define rules we disable + set_fact: + azure_waf_rule_overrides: + # --type Microsoft_DefaultRuleSet --rule-group-id SQLI --rule-id 942430 + - ["Microsoft_DefaultRuleSet", "SQLI", "942430"] + - ["Microsoft_DefaultRuleSet", "RFI", "931130"] + - ["Microsoft_DefaultRuleSet", "SQLI", "942440"] + - ["Microsoft_DefaultRuleSet", "MS-ThreatIntel-SQLI", "99031002"] + - ["Microsoft_DefaultRuleSet", "SQLI", "942120"] + - ["Microsoft_DefaultRuleSet", "SQLI", "942200"] + - ["Microsoft_DefaultRuleSet", "PHP", "933210"] + - ["Microsoft_DefaultRuleSet", "General", "200003"] + - ["Microsoft_DefaultRuleSet", "General", "200002"] + - ["Microsoft_DefaultRuleSet", "SQLI", "942400"] + - ["Microsoft_DefaultRuleSet", "SQLI", "942210"] + - ["Microsoft_DefaultRuleSet", "SQLI", "942410"] + - ["Microsoft_DefaultRuleSet", "SQLI", "942150"] + - ["Microsoft_DefaultRuleSet", "MS-ThreatIntel-SQLI", "99031003"] + - ["Microsoft_DefaultRuleSet", "SQLI", "942340"] + - ["Microsoft_DefaultRuleSet", "SQLI", "942260"] + - ["Microsoft_DefaultRuleSet", "MS-ThreatIntel-SQLI", "99031004"] + - ["Microsoft_DefaultRuleSet", "SQLI", "942330"] + - ["Microsoft_DefaultRuleSet", "SQLI", "942100"] + - ["Microsoft_DefaultRuleSet", "PHP", "933160"] + - ["Microsoft_DefaultRuleSet", "SQLI", "942370"] + - ["Microsoft_DefaultRuleSet", "PROTOCOL-ATTACK", "921110"] + - ["Microsoft_DefaultRuleSet", "SQLI", "942110"] + - ["Microsoft_DefaultRuleSet", "SQLI", "942140"] + - ["Microsoft_DefaultRuleSet", "MS-ThreatIntel-SQLI", "99031001"] + - ["Microsoft_DefaultRuleSet", "XSS", "941340"] + - ["Microsoft_DefaultRuleSet", "SQLI", "942190"] + - ["Microsoft_DefaultRuleSet", "XSS", "941150"] + - ["Microsoft_DefaultRuleSet", "XSS", "941370"] + - ["Microsoft_DefaultRuleSet", "SQLI", "942390"] + - ["Microsoft_DefaultRuleSet", "SQLI", "942380"] + +# This can be VERY slow, so we actually check if we need to apply the rule first + +- name: Apply WAF Rule Overrides + command: > + RESULT=$(az network front-door waf-policy managed-rules override list \ + --policy-name {{ waf_policy_name }} \ + --resource-group {{ resource_group_name }} \ + --type {{ item[0] }} \ + --query "[*].rules[][]") + + echo $RESULT + # If result is Disabled, we don't need to apply the rule + if [ "$RESULT" != "Disabled" ]; then + az network front-door waf-policy managed-rules override add \ + --disabled \ + --policy-name {{ waf_policy_name }} \ + --resource-group {{ resource_group_name }} \ + --type {{ item[0] }} \ + --rule-group-id {{ item[1] }} \ + --rule-id {{ item[2] }} + fi + loop: "{{ azure_waf_rule_overrides + (custom_azure_waf_rule_overrides | default([])) }}" From 36452973f03c6641601cecf7b61970502e5406af Mon Sep 17 00:00:00 2001 From: Craig Cooper Date: Sat, 28 Dec 2024 08:18:45 +0700 Subject: [PATCH 22/36] fix: tidy up waf --- roles/setup-azure-frontdoor/tasks/waf.yml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/roles/setup-azure-frontdoor/tasks/waf.yml b/roles/setup-azure-frontdoor/tasks/waf.yml index 8fe891a..3516f7c 100644 --- a/roles/setup-azure-frontdoor/tasks/waf.yml +++ b/roles/setup-azure-frontdoor/tasks/waf.yml @@ -62,14 +62,13 @@ - ["Microsoft_DefaultRuleSet", "SQLI", "942380"] # This can be VERY slow, so we actually check if we need to apply the rule first - - name: Apply WAF Rule Overrides - command: > + shell: | RESULT=$(az network front-door waf-policy managed-rules override list \ --policy-name {{ waf_policy_name }} \ --resource-group {{ resource_group_name }} \ --type {{ item[0] }} \ - --query "[*].rules[][]") + --query "[*].rules[?ruleId=='{{ item[2] }}'][] | [0].enabledState") echo $RESULT # If result is Disabled, we don't need to apply the rule From a96aec27096d4200799382cdc2d279a00867cfbb Mon Sep 17 00:00:00 2001 From: Craig Cooper Date: Sat, 28 Dec 2024 08:30:10 +0700 Subject: [PATCH 23/36] fix: tidy up waf --- roles/setup-azure-frontdoor/tasks/waf.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/roles/setup-azure-frontdoor/tasks/waf.yml b/roles/setup-azure-frontdoor/tasks/waf.yml index 3516f7c..a1d9679 100644 --- a/roles/setup-azure-frontdoor/tasks/waf.yml +++ b/roles/setup-azure-frontdoor/tasks/waf.yml @@ -71,7 +71,9 @@ --query "[*].rules[?ruleId=='{{ item[2] }}'][] | [0].enabledState") echo $RESULT - # If result is Disabled, we don't need to apply the rule + + # If result is Disabled, we dont need to apply the rule + if [ "$RESULT" != "Disabled" ]; then az network front-door waf-policy managed-rules override add \ --disabled \ From 2fd8b16639b6cac3d1fb2285657dba8e0744674b Mon Sep 17 00:00:00 2001 From: Craig Cooper Date: Sat, 28 Dec 2024 08:34:56 +0700 Subject: [PATCH 24/36] fix: revert waf changes --- roles/setup-azure-frontdoor/tasks/main.yml | 74 ++++++++++++++++++- roles/setup-azure-frontdoor/tasks/waf.yml | 86 ---------------------- 2 files changed, 72 insertions(+), 88 deletions(-) delete mode 100644 roles/setup-azure-frontdoor/tasks/waf.yml diff --git a/roles/setup-azure-frontdoor/tasks/main.yml b/roles/setup-azure-frontdoor/tasks/main.yml index e27988a..66f20c7 100644 --- a/roles/setup-azure-frontdoor/tasks/main.yml +++ b/roles/setup-azure-frontdoor/tasks/main.yml @@ -24,8 +24,78 @@ --mode Prevention # or 'Detection' -- name: Create WAF Policy - include_tasks: waf.yml +# DRS 2.1 includes 17 rule groups, as shown in the following table. +# Each group contains multiple rules, and you can customize behavior for individual rules, rule groups, or entire rule set. +# DRS 2.1 is baselined off the Open Web Application Security Project (OWASP) Core Rule Set (CRS) 3.3.2 and includes additional proprietary protections rules developed by Microsoft Threat Intelligence team. +# https://learn.microsoft.com/en-us/azure/web-application-firewall/ag/application-gateway-crs-rulegroups-rules?tabs=owasp32#drs-21 +- name: Add managed default ruleset to WAF policy + command: > + az network front-door waf-policy managed-rules add \ + --resource-group {{ resource_group_name }} \ + --policy-name {{ waf_policy_name }} \ + --type Microsoft_DefaultRuleSet --version 2.1 --action Block + +# The Bot Manager 1.1 rule set is an enhancement to Bot Manager 1.0 rule set. It provides enhanced protection against malicious bots, and increases good bot detection. +# https://learn.microsoft.com/en-us/azure/web-application-firewall/ag/application-gateway-crs-rulegroups-rules?tabs=owasp32#bot-manager-11 +- name: Add bot ruleset to WAF policy + command: > + az network front-door waf-policy managed-rules add \ + --resource-group {{ resource_group_name }} \ + --policy-name {{ waf_policy_name }} \ + --type Microsoft_BotManagerRuleSet \ + --version 1.1 + +# The following rules are disabled by default as they result in false positives. +# https://learn.microsoft.com/en-us/azure/web-application-firewall/ag/application-gateway-crs-rulegroups-rules?tabs=owasp32#microsoft-threat-intelligence-collection-rules + +# We also disable a lot because CKAN will trigger them, these were found by logging the WAF logs and seeing what was being triggered during normal use of CKAN. +# Additional custom rules can be added to the list below, in the format ["rule-set", "rule-group-id", "rule-id"], or defined in the inventory/group_vars etc as a list of lists (like this) under `custom_azure_waf_rule_overrides` +- name: Define rules we disable + set_fact: + azure_waf_rule_overrides: + # --type Microsoft_DefaultRuleSet --rule-group-id SQLI --rule-id 942430 + - ["Microsoft_DefaultRuleSet", "SQLI", "942430"] + - ["Microsoft_DefaultRuleSet", "RFI", "931130"] + - ["Microsoft_DefaultRuleSet", "SQLI", "942440"] + - ["Microsoft_DefaultRuleSet", "MS-ThreatIntel-SQLI", "99031002"] + - ["Microsoft_DefaultRuleSet", "SQLI", "942120"] + - ["Microsoft_DefaultRuleSet", "SQLI", "942200"] + - ["Microsoft_DefaultRuleSet", "PHP", "933210"] + - ["Microsoft_DefaultRuleSet", "General", "200003"] + - ["Microsoft_DefaultRuleSet", "General", "200002"] + - ["Microsoft_DefaultRuleSet", "SQLI", "942400"] + - ["Microsoft_DefaultRuleSet", "SQLI", "942210"] + - ["Microsoft_DefaultRuleSet", "SQLI", "942410"] + - ["Microsoft_DefaultRuleSet", "SQLI", "942150"] + - ["Microsoft_DefaultRuleSet", "MS-ThreatIntel-SQLI", "99031003"] + - ["Microsoft_DefaultRuleSet", "SQLI", "942340"] + - ["Microsoft_DefaultRuleSet", "SQLI", "942260"] + - ["Microsoft_DefaultRuleSet", "MS-ThreatIntel-SQLI", "99031004"] + - ["Microsoft_DefaultRuleSet", "SQLI", "942330"] + - ["Microsoft_DefaultRuleSet", "SQLI", "942100"] + - ["Microsoft_DefaultRuleSet", "PHP", "933160"] + - ["Microsoft_DefaultRuleSet", "SQLI", "942370"] + - ["Microsoft_DefaultRuleSet", "PROTOCOL-ATTACK", "921110"] + - ["Microsoft_DefaultRuleSet", "SQLI", "942110"] + - ["Microsoft_DefaultRuleSet", "SQLI", "942140"] + - ["Microsoft_DefaultRuleSet", "MS-ThreatIntel-SQLI", "99031001"] + - ["Microsoft_DefaultRuleSet", "XSS", "941340"] + - ["Microsoft_DefaultRuleSet", "SQLI", "942190"] + - ["Microsoft_DefaultRuleSet", "XSS", "941150"] + - ["Microsoft_DefaultRuleSet", "XSS", "941370"] + - ["Microsoft_DefaultRuleSet", "SQLI", "942390"] + - ["Microsoft_DefaultRuleSet", "SQLI", "942380"] + +- name: Apply WAF Rule Overrides + command: > + az network front-door waf-policy managed-rules override add \ + --disabled \ + --policy-name {{ waf_policy_name }} \ + --resource-group {{ resource_group_name }} \ + --type {{ item[0] }} \ + --rule-group-id {{ item[1] }} \ + --rule-id {{ item[2] }} + loop: "{{ azure_waf_rule_overrides + (custom_azure_waf_rule_overrides | default([])) }}" - set_fact: ckan_endpoint_name: "{{ resource_prefix|lower }}-ckan" diff --git a/roles/setup-azure-frontdoor/tasks/waf.yml b/roles/setup-azure-frontdoor/tasks/waf.yml deleted file mode 100644 index a1d9679..0000000 --- a/roles/setup-azure-frontdoor/tasks/waf.yml +++ /dev/null @@ -1,86 +0,0 @@ - -# DRS 2.1 includes 17 rule groups, as shown in the following table. -# Each group contains multiple rules, and you can customize behavior for individual rules, rule groups, or entire rule set. -# DRS 2.1 is baselined off the Open Web Application Security Project (OWASP) Core Rule Set (CRS) 3.3.2 and includes additional proprietary protections rules developed by Microsoft Threat Intelligence team. -# https://learn.microsoft.com/en-us/azure/web-application-firewall/ag/application-gateway-crs-rulegroups-rules?tabs=owasp32#drs-21 -- name: Add managed default ruleset to WAF policy - command: > - az network front-door waf-policy managed-rules add \ - --resource-group {{ resource_group_name }} \ - --policy-name {{ waf_policy_name }} \ - --type Microsoft_DefaultRuleSet --version 2.1 --action Block - -# The Bot Manager 1.1 rule set is an enhancement to Bot Manager 1.0 rule set. It provides enhanced protection against malicious bots, and increases good bot detection. -# https://learn.microsoft.com/en-us/azure/web-application-firewall/ag/application-gateway-crs-rulegroups-rules?tabs=owasp32#bot-manager-11 -- name: Add bot ruleset to WAF policy - command: > - az network front-door waf-policy managed-rules add \ - --resource-group {{ resource_group_name }} \ - --policy-name {{ waf_policy_name }} \ - --type Microsoft_BotManagerRuleSet \ - --version 1.1 - -# The following rules are disabled by default as they result in false positives. -# https://learn.microsoft.com/en-us/azure/web-application-firewall/ag/application-gateway-crs-rulegroups-rules?tabs=owasp32#microsoft-threat-intelligence-collection-rules - -# We also disable a lot because CKAN will trigger them, these were found by logging the WAF logs and seeing what was being triggered during normal use of CKAN. -# Additional custom rules can be added to the list below, in the format ["rule-set", "rule-group-id", "rule-id"], or defined in the inventory/group_vars etc as a list of lists (like this) under `custom_azure_waf_rule_overrides` -- name: Define rules we disable - set_fact: - azure_waf_rule_overrides: - # --type Microsoft_DefaultRuleSet --rule-group-id SQLI --rule-id 942430 - - ["Microsoft_DefaultRuleSet", "SQLI", "942430"] - - ["Microsoft_DefaultRuleSet", "RFI", "931130"] - - ["Microsoft_DefaultRuleSet", "SQLI", "942440"] - - ["Microsoft_DefaultRuleSet", "MS-ThreatIntel-SQLI", "99031002"] - - ["Microsoft_DefaultRuleSet", "SQLI", "942120"] - - ["Microsoft_DefaultRuleSet", "SQLI", "942200"] - - ["Microsoft_DefaultRuleSet", "PHP", "933210"] - - ["Microsoft_DefaultRuleSet", "General", "200003"] - - ["Microsoft_DefaultRuleSet", "General", "200002"] - - ["Microsoft_DefaultRuleSet", "SQLI", "942400"] - - ["Microsoft_DefaultRuleSet", "SQLI", "942210"] - - ["Microsoft_DefaultRuleSet", "SQLI", "942410"] - - ["Microsoft_DefaultRuleSet", "SQLI", "942150"] - - ["Microsoft_DefaultRuleSet", "MS-ThreatIntel-SQLI", "99031003"] - - ["Microsoft_DefaultRuleSet", "SQLI", "942340"] - - ["Microsoft_DefaultRuleSet", "SQLI", "942260"] - - ["Microsoft_DefaultRuleSet", "MS-ThreatIntel-SQLI", "99031004"] - - ["Microsoft_DefaultRuleSet", "SQLI", "942330"] - - ["Microsoft_DefaultRuleSet", "SQLI", "942100"] - - ["Microsoft_DefaultRuleSet", "PHP", "933160"] - - ["Microsoft_DefaultRuleSet", "SQLI", "942370"] - - ["Microsoft_DefaultRuleSet", "PROTOCOL-ATTACK", "921110"] - - ["Microsoft_DefaultRuleSet", "SQLI", "942110"] - - ["Microsoft_DefaultRuleSet", "SQLI", "942140"] - - ["Microsoft_DefaultRuleSet", "MS-ThreatIntel-SQLI", "99031001"] - - ["Microsoft_DefaultRuleSet", "XSS", "941340"] - - ["Microsoft_DefaultRuleSet", "SQLI", "942190"] - - ["Microsoft_DefaultRuleSet", "XSS", "941150"] - - ["Microsoft_DefaultRuleSet", "XSS", "941370"] - - ["Microsoft_DefaultRuleSet", "SQLI", "942390"] - - ["Microsoft_DefaultRuleSet", "SQLI", "942380"] - -# This can be VERY slow, so we actually check if we need to apply the rule first -- name: Apply WAF Rule Overrides - shell: | - RESULT=$(az network front-door waf-policy managed-rules override list \ - --policy-name {{ waf_policy_name }} \ - --resource-group {{ resource_group_name }} \ - --type {{ item[0] }} \ - --query "[*].rules[?ruleId=='{{ item[2] }}'][] | [0].enabledState") - - echo $RESULT - - # If result is Disabled, we dont need to apply the rule - - if [ "$RESULT" != "Disabled" ]; then - az network front-door waf-policy managed-rules override add \ - --disabled \ - --policy-name {{ waf_policy_name }} \ - --resource-group {{ resource_group_name }} \ - --type {{ item[0] }} \ - --rule-group-id {{ item[1] }} \ - --rule-id {{ item[2] }} - fi - loop: "{{ azure_waf_rule_overrides + (custom_azure_waf_rule_overrides | default([])) }}" From 245b57717a8a294579802ef8f27b53f3193084b0 Mon Sep 17 00:00:00 2001 From: Craig Cooper Date: Sat, 28 Dec 2024 13:11:38 +0700 Subject: [PATCH 25/36] fix: async waf --- roles/setup-azure-frontdoor/tasks/main.yml | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/roles/setup-azure-frontdoor/tasks/main.yml b/roles/setup-azure-frontdoor/tasks/main.yml index 66f20c7..b6376cc 100644 --- a/roles/setup-azure-frontdoor/tasks/main.yml +++ b/roles/setup-azure-frontdoor/tasks/main.yml @@ -86,6 +86,7 @@ - ["Microsoft_DefaultRuleSet", "SQLI", "942390"] - ["Microsoft_DefaultRuleSet", "SQLI", "942380"] +# This is incredibly slow, so we run it async. We can still use and assign the policy before it's finished. - name: Apply WAF Rule Overrides command: > az network front-door waf-policy managed-rules override add \ @@ -96,6 +97,9 @@ --rule-group-id {{ item[1] }} \ --rule-id {{ item[2] }} loop: "{{ azure_waf_rule_overrides + (custom_azure_waf_rule_overrides | default([])) }}" + async: 360 + poll: 0 + register: async_results - set_fact: ckan_endpoint_name: "{{ resource_prefix|lower }}-ckan" @@ -377,3 +381,11 @@ --security-policy-name "{{ alphanumeric_resource_name_prefix | lower }}secpolicy" \ --domains {{ giftless_endpoint_full_id }} \ --waf-policy {{ waf_policy_id }} + +- name: Check on async WAF + async_status: + jid: "{{ yum_sleeper.ansible_job_id }}" + register: job_result + until: job_result.finished + retries: 100 + delay: 10 From c45cdd5e5f342472fce3e39609c1e0b2c8c08054 Mon Sep 17 00:00:00 2001 From: Craig Cooper Date: Sat, 28 Dec 2024 13:49:43 +0700 Subject: [PATCH 26/36] fix: tidy and fix domain assignment --- roles/setup-azure-frontdoor/tasks/main.yml | 57 ++++++++++------------ 1 file changed, 27 insertions(+), 30 deletions(-) diff --git a/roles/setup-azure-frontdoor/tasks/main.yml b/roles/setup-azure-frontdoor/tasks/main.yml index b6376cc..7418502 100644 --- a/roles/setup-azure-frontdoor/tasks/main.yml +++ b/roles/setup-azure-frontdoor/tasks/main.yml @@ -6,10 +6,14 @@ all: true register: subscription_output +- name: Set FrontDoor Profile Name + set_fact: + afd_profile_name: "{{ resource_prefix }}-afd" + - name: Create Front Door Profile command: > az afd profile create \ - --profile-name {{resource_prefix}}-afd \ + --profile-name afd_profile_name \ --resource-group {{ resource_group_name }} \ --sku Premium_AzureFrontDoor @@ -109,7 +113,7 @@ command: > az afd endpoint create \ --resource-group {{ resource_group_name }} \ - --profile-name {{ resource_prefix }}-afd \ + --profile-name afd_profile_name \ --endpoint-name {{ ckan_endpoint_name }} \ --enabled-state Enabled register: ckan_endpoint_output @@ -118,7 +122,7 @@ command: > az afd endpoint create \ --resource-group {{ resource_group_name }} \ - --profile-name {{ resource_prefix }}-afd \ + --profile-name afd_profile_name \ --endpoint-name {{ giftless_endpoint_name }} \ --enabled-state Enabled register: giftless_endpoint_output @@ -131,14 +135,14 @@ az afd rule-set create \ --resource-group {{ resource_group_name }} \ --name giftlesscors \ - --profile-name {{resource_prefix}}-afd + --profile-name afd_profile_name - name: CORS Origin header and condition base rule command: > az afd rule create \ --resource-group {{ resource_group_name }} \ --rule-set-name giftlesscors \ - --profile-name {{ resource_prefix }}-afd \ + --profile-name afd_profile_name \ --rule-name corsheaders \ --selector Origin \ --match-variable RequestHeader \ @@ -154,7 +158,7 @@ az afd rule create \ --resource-group {{ resource_group_name }} \ --rule-set-name giftlesscors \ - --profile-name {{resource_prefix}}-afd \ + --profile-name afd_profile_name \ --rule-name corsheaders \ --selector Origin \ --match-variable RequestHeader \ @@ -170,7 +174,7 @@ command: > az afd rule action add --resource-group {{ resource_group_name }} \ --rule-set-name giftlesscors \ - --profile-name {{ resource_prefix }}-afd \ + --profile-name afd_profile_name \ --rule-name corsheaders \ --action-name ModifyResponseHeader \ --header-action Overwrite \ @@ -181,7 +185,7 @@ command: > az afd rule action add --resource-group {{ resource_group_name }} \ --rule-set-name giftlesscors \ - --profile-name {{ resource_prefix }}-afd \ + --profile-name afd_profile_name \ --rule-name corsheaders \ --action-name ModifyResponseHeader \ --header-action Overwrite \ @@ -193,7 +197,7 @@ command: > az afd origin-group create \ --resource-group {{ resource_group_name }} \ - --profile-name {{ resource_prefix }}-afd \ + --profile-name afd_profile_name \ --origin-group-name {{resource_prefix}}-og-ckan \ --probe-request-type GET \ --probe-protocol Http \ @@ -208,7 +212,7 @@ command: > az afd origin-group create \ --resource-group {{ resource_group_name }} \ - --profile-name {{ resource_prefix }}-afd \ + --profile-name afd_profile_name \ --origin-group-name {{resource_prefix}}-og-giftless \ --probe-request-type GET \ --probe-protocol Http \ @@ -239,7 +243,7 @@ --host-name {{ ckan_pls_alias }} \ --origin-host-header {{ ckan_fqdn }} \ --resource-group {{ resource_group_name }} \ - --profile-name {{ resource_prefix }}-afd \ + --profile-name afd_profile_name \ --origin-group-name {{resource_prefix}}-og-ckan \ --origin-name ckan-origin \ --priority 1 \ @@ -269,7 +273,7 @@ --host-name {{ giftless_pls_alias }} \ --origin-host-header {{ giftless_pls_alias }} \ --resource-group {{ resource_group_name }} \ - --profile-name {{resource_prefix}}-afd \ + --profile-name afd_profile_name \ --origin-group-name {{resource_prefix}}-og-giftless \ --origin-name ckan-origin \ --priority 1 \ @@ -289,7 +293,7 @@ command: > az afd route create \ --resource-group {{ resource_group_name }} \ - --profile-name {{resource_prefix}}-afd \ + --profile-name afd_profile_name \ --route-name ckan-route \ --endpoint-name {{ ckan_endpoint_name }} \ --patterns '/*' \ @@ -304,7 +308,7 @@ command: > az afd route create \ --resource-group {{ resource_group_name }} \ - --profile-name {{resource_prefix}}-afd \ + --profile-name afd_profile_name \ --route-name giftless-route \ --endpoint-name {{ giftless_endpoint_name }} \ --patterns '/*' \ @@ -350,41 +354,34 @@ --description "Approved" when: (ckan_pls_pending_output.stdout|from_json)[0].properties.privateLinkServiceConnectionState.status == "Pending" + +# Securiy Policy creation requires full ids, so create them first - set_fact: - custom_afd_domain_full_id: "/subscriptions/{{ subscription_output.subscriptions[0].subscription_id }}/resourcegroups/{{ resource_group_name }}/providers/Microsoft.Cdn/profiles/{{ resource_prefix }}-afd/customdomains/{{ custom_afd_domain_id }}" + custom_afd_domain_full_id: "/subscriptions/{{ subscription_output.subscriptions[0].subscription_id }}/resourcegroups/{{ resource_group_name }}/providers/Microsoft.Cdn/profiles/afd_profile_name/customdomains/{{ custom_afd_domain_id }}" when: custom_afd_domain_id is defined - set_fact: - ckan_endpoint_full_id: "/subscriptions/{{ subscription_output.subscriptions[0].subscription_id }}/resourcegroups/{{ resource_group_name }}/providers/Microsoft.Cdn/profiles/{{ resource_prefix }}-afd/afdendpoints/{{ ckan_endpoint_name }}" + ckan_endpoint_full_id: "/subscriptions/{{ subscription_output.subscriptions[0].subscription_id }}/resourcegroups/{{ resource_group_name }}/providers/Microsoft.Cdn/profiles/afd_profile_name/afdendpoints/{{ ckan_endpoint_name }}" when: custom_afd_domain_id is not defined - set_fact: - giftless_endpoint_full_id: "/subscriptions/{{ subscription_output.subscriptions[0].subscription_id }}/resourcegroups/{{ resource_group_name }}/providers/Microsoft.Cdn/profiles/{{ resource_prefix }}-afd/afdendpoints/{{ giftless_endpoint_name }}" + giftless_endpoint_full_id: "/subscriptions/{{ subscription_output.subscriptions[0].subscription_id }}/resourcegroups/{{ resource_group_name }}/providers/Microsoft.Cdn/profiles/afd_profile_name/afdendpoints/{{ giftless_endpoint_name }}" - set_fact: waf_policy_id: "/subscriptions/{{ subscription_output.subscriptions[0].subscription_id }}/resourcegroups/{{ resource_group_name }}/providers/Microsoft.Network/frontDoorWebApplicationFirewallPolicies/{{ waf_policy_name }}" -- name: Apply the WAF policy to the CKAN endpoint - command: > - az afd security-policy create \ - --resource-group {{ resource_group_name }} \ - --profile-name {{ resource_prefix }}-afd \ - --security-policy-name "{{ alphanumeric_resource_name_prefix | lower }}secpolicy" \ - --domains {{ custom_afd_domain_id | ternary(custom_afd_domain_full_id, ckan_endpoint_full_id) }} \ - --waf-policy {{ waf_policy_id }} - -- name: Apply the WAF policy to the Giftless endpoint +- name: Apply the WAF policy to the CKAN endpoint and the Giftless endpoint command: > az afd security-policy create \ --resource-group {{ resource_group_name }} \ - --profile-name {{ resource_prefix }}-afd \ + --profile-name afd_profile_name \ --security-policy-name "{{ alphanumeric_resource_name_prefix | lower }}secpolicy" \ - --domains {{ giftless_endpoint_full_id }} \ + --domains {{ custom_afd_domain_id | ternary(custom_afd_domain_full_id, ckan_endpoint_full_id) }} {{ giftless_endpoint_full_id }} \ --waf-policy {{ waf_policy_id }} - name: Check on async WAF async_status: - jid: "{{ yum_sleeper.ansible_job_id }}" + jid: "{{ async_results.ansible_job_id }}" register: job_result until: job_result.finished retries: 100 From 675bb9d1cfee2441ce7574b99ada6fc3c96efc92 Mon Sep 17 00:00:00 2001 From: Craig Cooper Date: Sat, 28 Dec 2024 13:53:04 +0700 Subject: [PATCH 27/36] fix: tidy and fix domain assignment --- roles/setup-azure-frontdoor/tasks/main.yml | 38 +++++++++++----------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/roles/setup-azure-frontdoor/tasks/main.yml b/roles/setup-azure-frontdoor/tasks/main.yml index 7418502..ec46471 100644 --- a/roles/setup-azure-frontdoor/tasks/main.yml +++ b/roles/setup-azure-frontdoor/tasks/main.yml @@ -13,7 +13,7 @@ - name: Create Front Door Profile command: > az afd profile create \ - --profile-name afd_profile_name \ + --profile-name {{ afd_profile_name }} \ --resource-group {{ resource_group_name }} \ --sku Premium_AzureFrontDoor @@ -113,7 +113,7 @@ command: > az afd endpoint create \ --resource-group {{ resource_group_name }} \ - --profile-name afd_profile_name \ + --profile-name {{ afd_profile_name }} \ --endpoint-name {{ ckan_endpoint_name }} \ --enabled-state Enabled register: ckan_endpoint_output @@ -122,7 +122,7 @@ command: > az afd endpoint create \ --resource-group {{ resource_group_name }} \ - --profile-name afd_profile_name \ + --profile-name {{ afd_profile_name }} \ --endpoint-name {{ giftless_endpoint_name }} \ --enabled-state Enabled register: giftless_endpoint_output @@ -135,14 +135,14 @@ az afd rule-set create \ --resource-group {{ resource_group_name }} \ --name giftlesscors \ - --profile-name afd_profile_name + --profile-name {{ afd_profile_name }} - name: CORS Origin header and condition base rule command: > az afd rule create \ --resource-group {{ resource_group_name }} \ --rule-set-name giftlesscors \ - --profile-name afd_profile_name \ + --profile-name {{ afd_profile_name }} \ --rule-name corsheaders \ --selector Origin \ --match-variable RequestHeader \ @@ -158,7 +158,7 @@ az afd rule create \ --resource-group {{ resource_group_name }} \ --rule-set-name giftlesscors \ - --profile-name afd_profile_name \ + --profile-name {{ afd_profile_name }} \ --rule-name corsheaders \ --selector Origin \ --match-variable RequestHeader \ @@ -174,7 +174,7 @@ command: > az afd rule action add --resource-group {{ resource_group_name }} \ --rule-set-name giftlesscors \ - --profile-name afd_profile_name \ + --profile-name {{ afd_profile_name }} \ --rule-name corsheaders \ --action-name ModifyResponseHeader \ --header-action Overwrite \ @@ -185,7 +185,7 @@ command: > az afd rule action add --resource-group {{ resource_group_name }} \ --rule-set-name giftlesscors \ - --profile-name afd_profile_name \ + --profile-name {{ afd_profile_name }} \ --rule-name corsheaders \ --action-name ModifyResponseHeader \ --header-action Overwrite \ @@ -197,7 +197,7 @@ command: > az afd origin-group create \ --resource-group {{ resource_group_name }} \ - --profile-name afd_profile_name \ + --profile-name {{ afd_profile_name }} \ --origin-group-name {{resource_prefix}}-og-ckan \ --probe-request-type GET \ --probe-protocol Http \ @@ -212,7 +212,7 @@ command: > az afd origin-group create \ --resource-group {{ resource_group_name }} \ - --profile-name afd_profile_name \ + --profile-name {{ afd_profile_name }} \ --origin-group-name {{resource_prefix}}-og-giftless \ --probe-request-type GET \ --probe-protocol Http \ @@ -243,7 +243,7 @@ --host-name {{ ckan_pls_alias }} \ --origin-host-header {{ ckan_fqdn }} \ --resource-group {{ resource_group_name }} \ - --profile-name afd_profile_name \ + --profile-name {{ afd_profile_name }} \ --origin-group-name {{resource_prefix}}-og-ckan \ --origin-name ckan-origin \ --priority 1 \ @@ -273,7 +273,7 @@ --host-name {{ giftless_pls_alias }} \ --origin-host-header {{ giftless_pls_alias }} \ --resource-group {{ resource_group_name }} \ - --profile-name afd_profile_name \ + --profile-name {{ afd_profile_name }} \ --origin-group-name {{resource_prefix}}-og-giftless \ --origin-name ckan-origin \ --priority 1 \ @@ -293,7 +293,7 @@ command: > az afd route create \ --resource-group {{ resource_group_name }} \ - --profile-name afd_profile_name \ + --profile-name {{ afd_profile_name }} \ --route-name ckan-route \ --endpoint-name {{ ckan_endpoint_name }} \ --patterns '/*' \ @@ -308,7 +308,7 @@ command: > az afd route create \ --resource-group {{ resource_group_name }} \ - --profile-name afd_profile_name \ + --profile-name {{ afd_profile_name }} \ --route-name giftless-route \ --endpoint-name {{ giftless_endpoint_name }} \ --patterns '/*' \ @@ -357,15 +357,15 @@ # Securiy Policy creation requires full ids, so create them first - set_fact: - custom_afd_domain_full_id: "/subscriptions/{{ subscription_output.subscriptions[0].subscription_id }}/resourcegroups/{{ resource_group_name }}/providers/Microsoft.Cdn/profiles/afd_profile_name/customdomains/{{ custom_afd_domain_id }}" + custom_afd_domain_full_id: "/subscriptions/{{ subscription_output.subscriptions[0].subscription_id }}/resourcegroups/{{ resource_group_name }}/providers/Microsoft.Cdn/profiles/{{ afd_profile_name }}/customdomains/{{ custom_afd_domain_id }}" when: custom_afd_domain_id is defined - set_fact: - ckan_endpoint_full_id: "/subscriptions/{{ subscription_output.subscriptions[0].subscription_id }}/resourcegroups/{{ resource_group_name }}/providers/Microsoft.Cdn/profiles/afd_profile_name/afdendpoints/{{ ckan_endpoint_name }}" + ckan_endpoint_full_id: "/subscriptions/{{ subscription_output.subscriptions[0].subscription_id }}/resourcegroups/{{ resource_group_name }}/providers/Microsoft.Cdn/profiles/{{ afd_profile_name }}/afdendpoints/{{ ckan_endpoint_name }}" when: custom_afd_domain_id is not defined - set_fact: - giftless_endpoint_full_id: "/subscriptions/{{ subscription_output.subscriptions[0].subscription_id }}/resourcegroups/{{ resource_group_name }}/providers/Microsoft.Cdn/profiles/afd_profile_name/afdendpoints/{{ giftless_endpoint_name }}" + giftless_endpoint_full_id: "/subscriptions/{{ subscription_output.subscriptions[0].subscription_id }}/resourcegroups/{{ resource_group_name }}/providers/Microsoft.Cdn/profiles/{{ afd_profile_name }}/afdendpoints/{{ giftless_endpoint_name }}" - set_fact: waf_policy_id: "/subscriptions/{{ subscription_output.subscriptions[0].subscription_id }}/resourcegroups/{{ resource_group_name }}/providers/Microsoft.Network/frontDoorWebApplicationFirewallPolicies/{{ waf_policy_name }}" @@ -374,12 +374,12 @@ command: > az afd security-policy create \ --resource-group {{ resource_group_name }} \ - --profile-name afd_profile_name \ + --profile-name {{ afd_profile_name }} \ --security-policy-name "{{ alphanumeric_resource_name_prefix | lower }}secpolicy" \ --domains {{ custom_afd_domain_id | ternary(custom_afd_domain_full_id, ckan_endpoint_full_id) }} {{ giftless_endpoint_full_id }} \ --waf-policy {{ waf_policy_id }} -- name: Check on async WAF +- name: Check on async WAF # If you don't do this, we'll never know if the async job failed async_status: jid: "{{ async_results.ansible_job_id }}" register: job_result From 94fe6921211891090887e159644c3ffd52c9cf0f Mon Sep 17 00:00:00 2001 From: Craig Cooper Date: Sat, 28 Dec 2024 14:14:10 +0700 Subject: [PATCH 28/36] fix: correclt handle async loop --- roles/setup-azure-frontdoor/tasks/main.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/roles/setup-azure-frontdoor/tasks/main.yml b/roles/setup-azure-frontdoor/tasks/main.yml index ec46471..0b0738b 100644 --- a/roles/setup-azure-frontdoor/tasks/main.yml +++ b/roles/setup-azure-frontdoor/tasks/main.yml @@ -381,7 +381,10 @@ - name: Check on async WAF # If you don't do this, we'll never know if the async job failed async_status: - jid: "{{ async_results.ansible_job_id }}" + jid: "{{ async_result_item.ansible_job_id }}" + loop: "{{ async_results.results }}" + loop_control: + loop_var: "async_result_item" register: job_result until: job_result.finished retries: 100 From e99c900394c10bd49ffe7aa4aa69ca4ad3622ea5 Mon Sep 17 00:00:00 2001 From: Craig Cooper Date: Sun, 29 Dec 2024 16:10:25 +0700 Subject: [PATCH 29/36] fix: lookup rules before applying --- roles/setup-azure-frontdoor/tasks/main.yml | 35 ++++++++++------------ 1 file changed, 16 insertions(+), 19 deletions(-) diff --git a/roles/setup-azure-frontdoor/tasks/main.yml b/roles/setup-azure-frontdoor/tasks/main.yml index 0b0738b..f5a8e9a 100644 --- a/roles/setup-azure-frontdoor/tasks/main.yml +++ b/roles/setup-azure-frontdoor/tasks/main.yml @@ -10,6 +10,9 @@ set_fact: afd_profile_name: "{{ resource_prefix }}-afd" +- set_fact: + waf_policy_name: "{{ alphanumeric_resource_name_prefix | lower }}wafpolicy" + - name: Create Front Door Profile command: > az afd profile create \ @@ -17,9 +20,6 @@ --resource-group {{ resource_group_name }} \ --sku Premium_AzureFrontDoor -- set_fact: - waf_policy_name: "{{ alphanumeric_resource_name_prefix | lower }}wafpolicy" - - name: Create Policy for WAF command: > az network front-door waf-policy create \ @@ -90,9 +90,19 @@ - ["Microsoft_DefaultRuleSet", "SQLI", "942390"] - ["Microsoft_DefaultRuleSet", "SQLI", "942380"] -# This is incredibly slow, so we run it async. We can still use and assign the policy before it's finished. -- name: Apply WAF Rule Overrides +# Get the rules that are already disabled so we don't try to disable them again +- name: Get rules status command: > + az network front-door waf-policy managed-rules override list \ + --policy-name {{ waf_policy_name }} \ + --resource-group {{ resource_group_name }} \ + --type Microsoft_DefaultRuleSet \ + --query "[*].rules[][].ruleId" + register: waf_rules_output + +# This is incredibly slow, so only run if we HAVE to +- name: Apply WAF Rule Overrides + shell: > az network front-door waf-policy managed-rules override add \ --disabled \ --policy-name {{ waf_policy_name }} \ @@ -101,9 +111,7 @@ --rule-group-id {{ item[1] }} \ --rule-id {{ item[2] }} loop: "{{ azure_waf_rule_overrides + (custom_azure_waf_rule_overrides | default([])) }}" - async: 360 - poll: 0 - register: async_results + when: item[2] not in list_of_rules - set_fact: ckan_endpoint_name: "{{ resource_prefix|lower }}-ckan" @@ -378,14 +386,3 @@ --security-policy-name "{{ alphanumeric_resource_name_prefix | lower }}secpolicy" \ --domains {{ custom_afd_domain_id | ternary(custom_afd_domain_full_id, ckan_endpoint_full_id) }} {{ giftless_endpoint_full_id }} \ --waf-policy {{ waf_policy_id }} - -- name: Check on async WAF # If you don't do this, we'll never know if the async job failed - async_status: - jid: "{{ async_result_item.ansible_job_id }}" - loop: "{{ async_results.results }}" - loop_control: - loop_var: "async_result_item" - register: job_result - until: job_result.finished - retries: 100 - delay: 10 From 541d7d53ce1d69abc613196e8e3269502187c459 Mon Sep 17 00:00:00 2001 From: Craig Cooper Date: Sun, 29 Dec 2024 16:24:01 +0700 Subject: [PATCH 30/36] fix: lookup rules before applying --- roles/setup-azure-frontdoor/tasks/main.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/roles/setup-azure-frontdoor/tasks/main.yml b/roles/setup-azure-frontdoor/tasks/main.yml index f5a8e9a..12a1194 100644 --- a/roles/setup-azure-frontdoor/tasks/main.yml +++ b/roles/setup-azure-frontdoor/tasks/main.yml @@ -100,6 +100,9 @@ --query "[*].rules[][].ruleId" register: waf_rules_output +- set_fact: + list_of_rules: "{{ waf_rules_output.stdout|from_json }}" + # This is incredibly slow, so only run if we HAVE to - name: Apply WAF Rule Overrides shell: > From 578f3db72d0b2310510e2a37b840c843fc541c94 Mon Sep 17 00:00:00 2001 From: Craig Cooper Date: Mon, 30 Dec 2024 14:25:19 +0700 Subject: [PATCH 31/36] fix: use BICEP for waf policy --- roles/setup-azure-frontdoor/tasks/main.yml | 96 +------ roles/setup-azure-frontdoor/wafpolicy.bicep | 284 ++++++++++++++++++++ 2 files changed, 288 insertions(+), 92 deletions(-) create mode 100644 roles/setup-azure-frontdoor/wafpolicy.bicep diff --git a/roles/setup-azure-frontdoor/tasks/main.yml b/roles/setup-azure-frontdoor/tasks/main.yml index 12a1194..d494767 100644 --- a/roles/setup-azure-frontdoor/tasks/main.yml +++ b/roles/setup-azure-frontdoor/tasks/main.yml @@ -22,99 +22,11 @@ - name: Create Policy for WAF command: > - az network front-door waf-policy create \ - --name {{ waf_policy_name }} \ + az deployment group create \ + --name WAFDeployment \ --resource-group {{ resource_group_name }} \ - --mode Prevention - # or 'Detection' - -# DRS 2.1 includes 17 rule groups, as shown in the following table. -# Each group contains multiple rules, and you can customize behavior for individual rules, rule groups, or entire rule set. -# DRS 2.1 is baselined off the Open Web Application Security Project (OWASP) Core Rule Set (CRS) 3.3.2 and includes additional proprietary protections rules developed by Microsoft Threat Intelligence team. -# https://learn.microsoft.com/en-us/azure/web-application-firewall/ag/application-gateway-crs-rulegroups-rules?tabs=owasp32#drs-21 -- name: Add managed default ruleset to WAF policy - command: > - az network front-door waf-policy managed-rules add \ - --resource-group {{ resource_group_name }} \ - --policy-name {{ waf_policy_name }} \ - --type Microsoft_DefaultRuleSet --version 2.1 --action Block - -# The Bot Manager 1.1 rule set is an enhancement to Bot Manager 1.0 rule set. It provides enhanced protection against malicious bots, and increases good bot detection. -# https://learn.microsoft.com/en-us/azure/web-application-firewall/ag/application-gateway-crs-rulegroups-rules?tabs=owasp32#bot-manager-11 -- name: Add bot ruleset to WAF policy - command: > - az network front-door waf-policy managed-rules add \ - --resource-group {{ resource_group_name }} \ - --policy-name {{ waf_policy_name }} \ - --type Microsoft_BotManagerRuleSet \ - --version 1.1 - -# The following rules are disabled by default as they result in false positives. -# https://learn.microsoft.com/en-us/azure/web-application-firewall/ag/application-gateway-crs-rulegroups-rules?tabs=owasp32#microsoft-threat-intelligence-collection-rules - -# We also disable a lot because CKAN will trigger them, these were found by logging the WAF logs and seeing what was being triggered during normal use of CKAN. -# Additional custom rules can be added to the list below, in the format ["rule-set", "rule-group-id", "rule-id"], or defined in the inventory/group_vars etc as a list of lists (like this) under `custom_azure_waf_rule_overrides` -- name: Define rules we disable - set_fact: - azure_waf_rule_overrides: - # --type Microsoft_DefaultRuleSet --rule-group-id SQLI --rule-id 942430 - - ["Microsoft_DefaultRuleSet", "SQLI", "942430"] - - ["Microsoft_DefaultRuleSet", "RFI", "931130"] - - ["Microsoft_DefaultRuleSet", "SQLI", "942440"] - - ["Microsoft_DefaultRuleSet", "MS-ThreatIntel-SQLI", "99031002"] - - ["Microsoft_DefaultRuleSet", "SQLI", "942120"] - - ["Microsoft_DefaultRuleSet", "SQLI", "942200"] - - ["Microsoft_DefaultRuleSet", "PHP", "933210"] - - ["Microsoft_DefaultRuleSet", "General", "200003"] - - ["Microsoft_DefaultRuleSet", "General", "200002"] - - ["Microsoft_DefaultRuleSet", "SQLI", "942400"] - - ["Microsoft_DefaultRuleSet", "SQLI", "942210"] - - ["Microsoft_DefaultRuleSet", "SQLI", "942410"] - - ["Microsoft_DefaultRuleSet", "SQLI", "942150"] - - ["Microsoft_DefaultRuleSet", "MS-ThreatIntel-SQLI", "99031003"] - - ["Microsoft_DefaultRuleSet", "SQLI", "942340"] - - ["Microsoft_DefaultRuleSet", "SQLI", "942260"] - - ["Microsoft_DefaultRuleSet", "MS-ThreatIntel-SQLI", "99031004"] - - ["Microsoft_DefaultRuleSet", "SQLI", "942330"] - - ["Microsoft_DefaultRuleSet", "SQLI", "942100"] - - ["Microsoft_DefaultRuleSet", "PHP", "933160"] - - ["Microsoft_DefaultRuleSet", "SQLI", "942370"] - - ["Microsoft_DefaultRuleSet", "PROTOCOL-ATTACK", "921110"] - - ["Microsoft_DefaultRuleSet", "SQLI", "942110"] - - ["Microsoft_DefaultRuleSet", "SQLI", "942140"] - - ["Microsoft_DefaultRuleSet", "MS-ThreatIntel-SQLI", "99031001"] - - ["Microsoft_DefaultRuleSet", "XSS", "941340"] - - ["Microsoft_DefaultRuleSet", "SQLI", "942190"] - - ["Microsoft_DefaultRuleSet", "XSS", "941150"] - - ["Microsoft_DefaultRuleSet", "XSS", "941370"] - - ["Microsoft_DefaultRuleSet", "SQLI", "942390"] - - ["Microsoft_DefaultRuleSet", "SQLI", "942380"] - -# Get the rules that are already disabled so we don't try to disable them again -- name: Get rules status - command: > - az network front-door waf-policy managed-rules override list \ - --policy-name {{ waf_policy_name }} \ - --resource-group {{ resource_group_name }} \ - --type Microsoft_DefaultRuleSet \ - --query "[*].rules[][].ruleId" - register: waf_rules_output - -- set_fact: - list_of_rules: "{{ waf_rules_output.stdout|from_json }}" - -# This is incredibly slow, so only run if we HAVE to -- name: Apply WAF Rule Overrides - shell: > - az network front-door waf-policy managed-rules override add \ - --disabled \ - --policy-name {{ waf_policy_name }} \ - --resource-group {{ resource_group_name }} \ - --type {{ item[0] }} \ - --rule-group-id {{ item[1] }} \ - --rule-id {{ item[2] }} - loop: "{{ azure_waf_rule_overrides + (custom_azure_waf_rule_overrides | default([])) }}" - when: item[2] not in list_of_rules + --template-file {{ role_path }}/wafpolicy.bicep \ + --parameters frontdoorwebapplicationfirewallpolicies_wafpolicy_name={{ waf_policy_name }} - set_fact: ckan_endpoint_name: "{{ resource_prefix|lower }}-ckan" diff --git a/roles/setup-azure-frontdoor/wafpolicy.bicep b/roles/setup-azure-frontdoor/wafpolicy.bicep new file mode 100644 index 0000000..331ef03 --- /dev/null +++ b/roles/setup-azure-frontdoor/wafpolicy.bicep @@ -0,0 +1,284 @@ +// Create a WAF Policy with managed rules and overrides for ones that do not work well with CKAN. +// Creating and applying a WAF policy is a slow process, so we use this as it's much faster than the Azure CLI. + +// Rulesets: + +// DRS 2.1 includes 17 rule groups, as shown in the following table. +// Each group contains multiple rules, and you can customize behavior for individual rules, rule groups, or entire rule set. +// DRS 2.1 is baselined off the Open Web Application Security Project (OWASP) Core Rule Set (CRS) 3.3.2 and includes additional proprietary protections rules developed by Microsoft Threat Intelligence team. +// https://learn.microsoft.com/en-us/azure/web-application-firewall/ag/application-gateway-crs-rulegroups-rules?tabs=owasp32#drs-21 + +// The Bot Manager 1.1 rule set is an enhancement to Bot Manager 1.0 rule set. It provides enhanced protection against malicious bots, and increases good bot detection. +// https://learn.microsoft.com/en-us/azure/web-application-firewall/ag/application-gateway-crs-rulegroups-rules?tabs=owasp32#bot-manager-11 + +// The following rules are disabled by default as they result in false positives. +// https://learn.microsoft.com/en-us/azure/web-application-firewall/ag/application-gateway-crs-rulegroups-rules?tabs=owasp32#microsoft-threat-intelligence-collection-rules + +// We also disable a lot because CKAN will trigger them, these were found by logging the WAF logs and seeing what was being triggered during normal use of CKAN. +// Additional custom rules and overrides can be added to the list below if required for all Azure deployments. If a rule needs overriding for just one deployment, they can be defined in the inventory/group_vars etc as a list of lists `custom_azure_waf_rule_overrides`, the format being: [["rule-set", "rule-group-id", "rule-id"]]. These will be applied to the WAF policy synchronously after the WAF policy is created, using the CLI. THIS IS VERY SLOW so ideally keep these rules to a minimum and strongly prefer using this template to define the rules. +param frontdoorwebapplicationfirewallpolicies_wafpolicy_name string = 'wafpolicy1' + +resource frontdoorwebapplicationfirewallpolicies_wafpolicy_name_resource 'Microsoft.Network/frontdoorwebapplicationfirewallpolicies@2024-02-01' = { + name: frontdoorwebapplicationfirewallpolicies_wafpolicy_name + location: 'Global' + sku: { + name: 'Premium_AzureFrontDoor' + } + properties: { + policySettings: { + enabledState: 'Enabled' + mode: 'Prevention' + requestBodyCheck: 'Enabled' + javascriptChallengeExpirationInMinutes: 30 + } + customRules: { + rules: [] + } + managedRules: { + managedRuleSets: [ + { + ruleSetType: 'Microsoft_DefaultRuleSet' + ruleSetVersion: '2.1' + ruleSetAction: 'Block' + ruleGroupOverrides: [ + { + ruleGroupName: 'SQLI' + rules: [ + { + ruleId: '942430' + enabledState: 'Disabled' + action: 'AnomalyScoring' + exclusions: [] + } + { + ruleId: '942440' + enabledState: 'Disabled' + action: 'AnomalyScoring' + exclusions: [] + } + { + ruleId: '942120' + enabledState: 'Disabled' + action: 'AnomalyScoring' + exclusions: [] + } + { + ruleId: '942200' + enabledState: 'Disabled' + action: 'AnomalyScoring' + exclusions: [] + } + { + ruleId: '942400' + enabledState: 'Disabled' + action: 'AnomalyScoring' + exclusions: [] + } + { + ruleId: '942210' + enabledState: 'Disabled' + action: 'AnomalyScoring' + exclusions: [] + } + { + ruleId: '942410' + enabledState: 'Disabled' + action: 'AnomalyScoring' + exclusions: [] + } + { + ruleId: '942150' + enabledState: 'Disabled' + action: 'AnomalyScoring' + exclusions: [] + } + { + ruleId: '942340' + enabledState: 'Disabled' + action: 'AnomalyScoring' + exclusions: [] + } + { + ruleId: '942260' + enabledState: 'Disabled' + action: 'AnomalyScoring' + exclusions: [] + } + { + ruleId: '942330' + enabledState: 'Disabled' + action: 'AnomalyScoring' + exclusions: [] + } + { + ruleId: '942100' + enabledState: 'Disabled' + action: 'AnomalyScoring' + exclusions: [] + } + { + ruleId: '942370' + enabledState: 'Disabled' + action: 'AnomalyScoring' + exclusions: [] + } + { + ruleId: '942110' + enabledState: 'Disabled' + action: 'AnomalyScoring' + exclusions: [] + } + { + ruleId: '942140' + enabledState: 'Disabled' + action: 'AnomalyScoring' + exclusions: [] + } + { + ruleId: '942190' + enabledState: 'Disabled' + action: 'AnomalyScoring' + exclusions: [] + } + { + ruleId: '942390' + enabledState: 'Disabled' + action: 'AnomalyScoring' + exclusions: [] + } + { + ruleId: '942380' + enabledState: 'Disabled' + action: 'AnomalyScoring' + exclusions: [] + } + ] + exclusions: [] + } + { + ruleGroupName: 'RFI' + rules: [ + { + ruleId: '931130' + enabledState: 'Disabled' + action: 'AnomalyScoring' + exclusions: [] + } + ] + exclusions: [] + } + { + ruleGroupName: 'MS-ThreatIntel-SQLI' + rules: [ + { + ruleId: '99031002' + enabledState: 'Disabled' + action: 'AnomalyScoring' + exclusions: [] + } + { + ruleId: '99031003' + enabledState: 'Disabled' + action: 'AnomalyScoring' + exclusions: [] + } + { + ruleId: '99031004' + enabledState: 'Disabled' + action: 'AnomalyScoring' + exclusions: [] + } + { + ruleId: '99031001' + enabledState: 'Disabled' + action: 'AnomalyScoring' + exclusions: [] + } + ] + exclusions: [] + } + { + ruleGroupName: 'PHP' + rules: [ + { + ruleId: '933210' + enabledState: 'Disabled' + action: 'AnomalyScoring' + exclusions: [] + } + { + ruleId: '933160' + enabledState: 'Disabled' + action: 'AnomalyScoring' + exclusions: [] + } + ] + exclusions: [] + } + { + ruleGroupName: 'General' + rules: [ + { + ruleId: '200003' + enabledState: 'Disabled' + action: 'AnomalyScoring' + exclusions: [] + } + { + ruleId: '200002' + enabledState: 'Disabled' + action: 'AnomalyScoring' + exclusions: [] + } + ] + exclusions: [] + } + { + ruleGroupName: 'PROTOCOL-ATTACK' + rules: [ + { + ruleId: '921110' + enabledState: 'Disabled' + action: 'AnomalyScoring' + exclusions: [] + } + ] + exclusions: [] + } + { + ruleGroupName: 'XSS' + rules: [ + { + ruleId: '941340' + enabledState: 'Disabled' + action: 'AnomalyScoring' + exclusions: [] + } + { + ruleId: '941150' + enabledState: 'Disabled' + action: 'AnomalyScoring' + exclusions: [] + } + { + ruleId: '941370' + enabledState: 'Disabled' + action: 'AnomalyScoring' + exclusions: [] + } + ] + exclusions: [] + } + ] + exclusions: [] + } + { + ruleSetType: 'Microsoft_BotManagerRuleSet' + ruleSetVersion: '1.1' + ruleGroupOverrides: [] + exclusions: [] + } + ] + } + } +} From 28ba85480a4b77361955c24a69a381bcfdcd3f38 Mon Sep 17 00:00:00 2001 From: Craig Cooper Date: Mon, 30 Dec 2024 20:41:05 +0700 Subject: [PATCH 32/36] fix: add new rule exclusion --- roles/setup-azure-frontdoor/wafpolicy.bicep | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/roles/setup-azure-frontdoor/wafpolicy.bicep b/roles/setup-azure-frontdoor/wafpolicy.bicep index 331ef03..6076ba5 100644 --- a/roles/setup-azure-frontdoor/wafpolicy.bicep +++ b/roles/setup-azure-frontdoor/wafpolicy.bicep @@ -152,6 +152,12 @@ resource frontdoorwebapplicationfirewallpolicies_wafpolicy_name_resource 'Micros action: 'AnomalyScoring' exclusions: [] } + { + ruleId: '920120' + enabledState: 'Disabled' + action: 'AnomalyScoring' + exclusions: [] + } ] exclusions: [] } From 0d5bb963c511dd52eb5f239c40b5d8d855b011e0 Mon Sep 17 00:00:00 2001 From: Craig Cooper Date: Tue, 31 Dec 2024 12:22:27 +0700 Subject: [PATCH 33/36] fix: put new override WAF rule in the correct group --- roles/setup-azure-frontdoor/wafpolicy.bicep | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/roles/setup-azure-frontdoor/wafpolicy.bicep b/roles/setup-azure-frontdoor/wafpolicy.bicep index 6076ba5..0659e13 100644 --- a/roles/setup-azure-frontdoor/wafpolicy.bicep +++ b/roles/setup-azure-frontdoor/wafpolicy.bicep @@ -41,6 +41,17 @@ resource frontdoorwebapplicationfirewallpolicies_wafpolicy_name_resource 'Micros ruleSetVersion: '2.1' ruleSetAction: 'Block' ruleGroupOverrides: [ + { + ruleGroupName: 'PROTOCOL-ENFORCEMENT' + rules: [ + { + ruleId: '920120' + enabledState: 'Disabled' + action: 'AnomalyScoring' + exclusions: [] + } + ] + } { ruleGroupName: 'SQLI' rules: [ @@ -152,12 +163,6 @@ resource frontdoorwebapplicationfirewallpolicies_wafpolicy_name_resource 'Micros action: 'AnomalyScoring' exclusions: [] } - { - ruleId: '920120' - enabledState: 'Disabled' - action: 'AnomalyScoring' - exclusions: [] - } ] exclusions: [] } From 7b7d9a7a18c4e8955dacfbde0ed69d3f841ff804 Mon Sep 17 00:00:00 2001 From: Craig Cooper Date: Tue, 31 Dec 2024 12:23:35 +0700 Subject: [PATCH 34/36] feat: add static asset caching for Azure deploys --- roles/setup-azure-frontdoor/tasks/main.yml | 26 ++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/roles/setup-azure-frontdoor/tasks/main.yml b/roles/setup-azure-frontdoor/tasks/main.yml index d494767..b407a62 100644 --- a/roles/setup-azure-frontdoor/tasks/main.yml +++ b/roles/setup-azure-frontdoor/tasks/main.yml @@ -53,6 +53,31 @@ - set_fact: ckan_hostname: "https://{{ (ckan_endpoint_output.stdout|from_json).hostName }}" +- name: Create Ruleset for caching resources in the browswer + command: > + az afd rule-set create \ + --resource-group {{ resource_group_name }} \ + --profile-name {{ afd_profile_name }} \ + --name BrowserStaticAssetCaching + +- set_fact: + asset_extensions: ['js', 'css', 'woff', 'svg', 'jpg', 'woff2'] + +- name: Create Rule for caching resources in the browser + command: > + az afd rule create \ + --resource-group {{ resource_group_name }} \ + --rule-set-name BrowserStaticAssetCaching \ + --profile-name {{ afd_profile_name }} \ + --rule-name staticassets \ + --match-variable UrlFileExtension \ + --operator Equal \ + --match-values {{ asset_extensions | join(' ') }} \ + --action-name ModifyResponseHeader \ + --header-action Overwrite \ + --header-name Cache-Control \ + --header-value 'public, max-age=604800' + - name: Add a ruleset to set CORS headers for Giftless command: > az afd rule-set create \ @@ -225,6 +250,7 @@ --supported-protocols Https \ --https-redirect Enabled \ --forwarding-protocol HttpOnly \ + --rule-sets BrowserStaticAssetCaching \ {{ custom_afd_domain_id | ternary('--custom-domains ' + custom_afd_domain_id, '--link-to-default-domain Enabled') }} - name: Create route for Giftless From 6b5e882c4bf4a292b4809384f5f3f5ebc038cf09 Mon Sep 17 00:00:00 2001 From: Craig Cooper Date: Tue, 31 Dec 2024 12:46:05 +0700 Subject: [PATCH 35/36] feat: more extensions --- roles/setup-azure-frontdoor/tasks/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/roles/setup-azure-frontdoor/tasks/main.yml b/roles/setup-azure-frontdoor/tasks/main.yml index b407a62..f497314 100644 --- a/roles/setup-azure-frontdoor/tasks/main.yml +++ b/roles/setup-azure-frontdoor/tasks/main.yml @@ -61,7 +61,7 @@ --name BrowserStaticAssetCaching - set_fact: - asset_extensions: ['js', 'css', 'woff', 'svg', 'jpg', 'woff2'] + asset_extensions: ['js', 'css', 'woff', 'svg', 'jpg', 'woff2', 'jpeg', 'png'] - name: Create Rule for caching resources in the browser command: > From 2e69fe5c301fb48d0b09651f78c4a345f9b5b38d Mon Sep 17 00:00:00 2001 From: Craig Cooper Date: Wed, 1 Jan 2025 11:02:15 +0700 Subject: [PATCH 36/36] fix: enable compression and caching --- roles/setup-azure-frontdoor/tasks/main.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/roles/setup-azure-frontdoor/tasks/main.yml b/roles/setup-azure-frontdoor/tasks/main.yml index f497314..ae00f06 100644 --- a/roles/setup-azure-frontdoor/tasks/main.yml +++ b/roles/setup-azure-frontdoor/tasks/main.yml @@ -249,6 +249,8 @@ --enabled-state Enabled \ --supported-protocols Https \ --https-redirect Enabled \ + --enable-caching \ + --enable-compression \ --forwarding-protocol HttpOnly \ --rule-sets BrowserStaticAssetCaching \ {{ custom_afd_domain_id | ternary('--custom-domains ' + custom_afd_domain_id, '--link-to-default-domain Enabled') }} @@ -266,6 +268,8 @@ --supported-protocols Https \ --link-to-default-domain Enabled \ --https-redirect Enabled \ + --enable-caching \ + --enable-compression \ --forwarding-protocol HttpOnly \ --rule-sets giftlesscors