├── main.tf ├── .prettierignore ├── .github ├── CODEOWNERS └── workflows │ ├── action-update-lists.yml │ └── deployandbump.yml ├── example ├── frommodule │ ├── provider.tf │ ├── outputs.tf │ ├── module.adblock.tf │ ├── terraform.tf │ └── Makefile └── examplea │ ├── outputs.tf │ ├── module.adblock.tf │ ├── terraform.tf │ └── Makefile ├── data.cloudflare_accounts.tf ├── .terraformignore ├── locals.tf ├── .markdownlintrc ├── terraform.tf ├── .markdownlint.json ├── variables.tf ├── outputs.tf ├── .gitignore ├── cloudflare_teams_rule.block_malware.tf ├── cloudflare_teams_account.tf ├── .pre-commit-config.yaml ├── .gitattributes ├── cloudflare_teams_rule.block_ads.tf ├── README.md └── LICENSE /main.tf: -------------------------------------------------------------------------------- 1 | #not needed 2 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | README.md 2 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @JamesWoolfenden 2 | -------------------------------------------------------------------------------- /example/frommodule/provider.tf: -------------------------------------------------------------------------------- 1 | provider "cloudflare" { 2 | 3 | } -------------------------------------------------------------------------------- /data.cloudflare_accounts.tf: -------------------------------------------------------------------------------- 1 | data "cloudflare_accounts" "woolfenden" { 2 | } 3 | -------------------------------------------------------------------------------- /example/examplea/outputs.tf: -------------------------------------------------------------------------------- 1 | output "adblock" { 2 | value = module.adblock 3 | } 4 | -------------------------------------------------------------------------------- /example/frommodule/outputs.tf: -------------------------------------------------------------------------------- 1 | output "adblock" { 2 | value = module.adblock 3 | } 4 | -------------------------------------------------------------------------------- /.terraformignore: -------------------------------------------------------------------------------- 1 | .terraform/ 2 | *.exe 3 | *.tfstate 4 | *.backup 5 | *.bak 6 | *.info 7 | -------------------------------------------------------------------------------- /locals.tf: -------------------------------------------------------------------------------- 1 | locals { 2 | account_id = data.cloudflare_accounts.woolfenden.accounts[0].id 3 | } 4 | -------------------------------------------------------------------------------- /example/examplea/module.adblock.tf: -------------------------------------------------------------------------------- 1 | module "adblock" { 2 | source = "../../" 3 | team_name = "woolfenden" 4 | } 5 | -------------------------------------------------------------------------------- /.markdownlintrc: -------------------------------------------------------------------------------- 1 | { 2 | "default": true, 3 | "first-header-h1": false, 4 | "first-line-h1": false, 5 | "line_length": false, 6 | "no-multiple-blanks": false 7 | } 8 | -------------------------------------------------------------------------------- /terraform.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_providers { 3 | cloudflare = { 4 | source = "cloudflare/cloudflare" 5 | version = "3.33.1" 6 | } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /example/frommodule/module.adblock.tf: -------------------------------------------------------------------------------- 1 | module "adblock" { 2 | source = "JamesWoolfenden/adblock/cloudflare" 3 | version = "0.0.2" 4 | team_name = "woolfenden" 5 | } 6 | -------------------------------------------------------------------------------- /.markdownlint.json: -------------------------------------------------------------------------------- 1 | { 2 | "MD002": false, 3 | "MD013": false, 4 | "MD024": false, 5 | "MD033": { 6 | "allowed_elements": [ 7 | "br", 8 | "pre", 9 | "a" 10 | ] 11 | }, 12 | "MD034": false, 13 | "MD041": false 14 | } 15 | -------------------------------------------------------------------------------- /variables.tf: -------------------------------------------------------------------------------- 1 | variable "team_name" { 2 | type = string 3 | description = "Your cloudflare team name" 4 | } 5 | 6 | variable "logo_path" { 7 | type = string 8 | default = "https://pbs.twimg.com/profile_images/1408927094315393028/WkL6f1Qf_400x400.jpg" 9 | } 10 | -------------------------------------------------------------------------------- /outputs.tf: -------------------------------------------------------------------------------- 1 | output "team" { 2 | value = cloudflare_teams_account.woolfenden 3 | } 4 | 5 | output "account" { 6 | value = data.cloudflare_accounts.woolfenden 7 | } 8 | 9 | output "accounts" { 10 | value = data.cloudflare_accounts.woolfenden.accounts[0].id 11 | } 12 | 13 | output "malware_rule" { 14 | value = cloudflare_teams_rule.block_malware 15 | } 16 | -------------------------------------------------------------------------------- /example/examplea/terraform.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_providers { 3 | cloudflare = { 4 | source = "cloudflare/cloudflare" 5 | version = "3.33.1" 6 | } 7 | } 8 | backend "s3" { 9 | profile = "personal" 10 | encrypt = true 11 | bucket = "680235478471-terraform-state" 12 | key = "cloudflare/team/terraform.tfstate" 13 | dynamodb_table = "dynamodb-state-lock" 14 | region = "eu-west-2" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /example/frommodule/terraform.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_providers { 3 | cloudflare = { 4 | source = "cloudflare/cloudflare" 5 | version = "3.33.1" 6 | } 7 | } 8 | backend "s3" { 9 | profile = "personal" 10 | encrypt = true 11 | bucket = "680235478471-terraform-state" 12 | key = "cloudflare/team/terraform.tfstate" 13 | dynamodb_table = "dynamodb-state-lock" 14 | region = "eu-west-2" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled files 2 | *.tfstate 3 | *.tfstate.backup 4 | *.zip 5 | .DS_Store 6 | # Module directory 7 | .terraform/ 8 | .terraform 9 | .plugins 10 | __pycache__/ 11 | .vscode/ 12 | .idea 13 | *.iml 14 | *.orig 15 | *.ini 16 | *~HEAD 17 | *backup 18 | tmp 19 | lambda 20 | *~HEAD 21 | *backup 22 | *.bak 23 | .terraform.tfstate.lock.info 24 | .terraform.lock.hcl 25 | tf.json 26 | tf.plan 27 | *.log 28 | output/*.json 29 | secrets.auto.tfvars 30 | checksums.txt 31 | *.tar.gz 32 | original/ 33 | .external_modules 34 | twistcli 35 | -------------------------------------------------------------------------------- /cloudflare_teams_rule.block_malware.tf: -------------------------------------------------------------------------------- 1 | resource "cloudflare_teams_rule" "block_malware" { 2 | account_id = local.account_id 3 | 4 | name = "Block malware" 5 | description = "Block known threats based on Cloudflare’s threat intelligence" 6 | 7 | enabled = true 8 | precedence = 10 9 | 10 | # Block all security risks 11 | filters = ["dns"] 12 | traffic = "any(dns.security_category[*] in {178 80 83 176 175 117 131 134 151 153 68})" 13 | action = "block" 14 | 15 | rule_settings { 16 | block_page_enabled = true 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /cloudflare_teams_account.tf: -------------------------------------------------------------------------------- 1 | resource "cloudflare_teams_account" "woolfenden" { 2 | account_id = local.account_id 3 | block_page { 4 | enabled = true 5 | name = var.team_name 6 | header_text = "This website is blocked by Cloudfare DNS" 7 | footer_text = "Blocked footer" 8 | logo_path = var.logo_path 9 | background_color = "#e8e8e8" 10 | } 11 | 12 | antivirus { 13 | enabled_download_phase = true 14 | enabled_upload_phase = false 15 | fail_closed = false 16 | } 17 | 18 | proxy { 19 | tcp = true 20 | udp = true 21 | } 22 | 23 | logging { 24 | redact_pii = true 25 | settings_by_rule_type { 26 | dns { 27 | log_all = true 28 | log_blocks = false 29 | } 30 | http { 31 | log_all = true 32 | log_blocks = false 33 | } 34 | l4 { 35 | log_all = true 36 | log_blocks = false 37 | } 38 | } 39 | } 40 | 41 | activity_log_enabled = true 42 | tls_decrypt_enabled = false 43 | } 44 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # yamllint disable rule:line-length 3 | repos: 4 | - repo: https://github.com/pre-commit/pre-commit-hooks 5 | rev: v4.3.0 6 | hooks: 7 | - id: check-json 8 | - id: check-merge-conflict 9 | - id: trailing-whitespace 10 | - id: end-of-file-fixer 11 | - id: check-yaml 12 | - id: check-added-large-files 13 | - id: pretty-format-json 14 | args: 15 | - --autofix 16 | - id: detect-aws-credentials 17 | args: 18 | - --allow-missing-credentials 19 | - id: detect-private-key 20 | - repo: https://github.com/Lucas-C/pre-commit-hooks 21 | rev: v1.3.1 22 | hooks: 23 | - id: forbid-tabs 24 | exclude_types: [python, javascript, dtd, markdown, makefile, xml] 25 | exclude: binary|\.bin$ 26 | - repo: https://github.com/jameswoolfenden/pre-commit-shell 27 | rev: 0.0.2 28 | hooks: 29 | - id: shell-lint 30 | exclude: template|\.template$ 31 | - repo: https://github.com/igorshubovych/markdownlint-cli 32 | rev: v0.32.2 33 | hooks: 34 | - id: markdownlint 35 | - repo: https://github.com/jameswoolfenden/pre-commit 36 | rev: v0.1.50 37 | hooks: 38 | - id: terraform-fmt 39 | language_version: python3.11 40 | - id: tf2docs 41 | language_version: python3.11 42 | -------------------------------------------------------------------------------- /.github/workflows/action-update-lists.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: 'Update Domain List' 3 | 4 | on: 5 | workflow_dispatch: 6 | schedule: 7 | - cron: '0 10 15 * *' # At 10:00 on day-of-month 15 8 | 9 | env: 10 | FOLDER: '${{ github.workspace }}/cloudflare/lists' 11 | 12 | permissions: read-all 13 | 14 | jobs: 15 | auto-update: 16 | runs-on: ubuntu-latest 17 | 18 | permissions: 19 | id-token: write 20 | contents: write 21 | pull-requests: write 22 | 23 | steps: 24 | - name: 📂 Checkout Branch 25 | uses: actions/checkout@v3.5.2 26 | 27 | # 28 | # Fetch domain list 29 | # 30 | - name: 🔗 Fetch Domain List 31 | working-directory: ${{ env.FOLDER }} 32 | run: | 33 | LIST_URL="https://adaway.org/hosts.txt" 34 | LIST_FNAME="pihole_domain_list.txt" 35 | 36 | echo "[*] Fetching list: ${LIST_URL} -> ${LIST_FNAME}" 37 | wget --quiet $LIST_URL -O $LIST_FNAME 38 | 39 | echo "[*] Sorting list..." 40 | sort -u -o $LIST_FNAME $LIST_FNAME 41 | 42 | echo "[*] Removing comments..." 43 | grep -o '^[^#]*' $LIST_FNAME > temp.txt 44 | mv temp.txt $LIST_FNAME 45 | 46 | echo "[*] Extracting domains..." 47 | cat $LIST_FNAME | awk '{ print $2 }' > temp.txt 48 | mv temp.txt $LIST_FNAME 49 | 50 | echo "[*] Removing localhost from list..." 51 | sed -i '/localhost/d' $LIST_FNAME 52 | sed -i '/127.0.0.1/d' $LIST_FNAME 53 | 54 | # 55 | # Commit file 56 | # 57 | - name: ↗️ Create Pull Request 58 | uses: peter-evans/create-pull-request@v5.0.0 59 | with: 60 | token: ${{ secrets.GITHUB_TOKEN }} 61 | title: 'Update Domain List' 62 | branch-suffix: timestamp 63 | commit-message: 'Update Domain List' 64 | body: '' 65 | -------------------------------------------------------------------------------- /.github/workflows/deployandbump.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # yamllint disable rule:line-length 3 | name: Deploy and Bump 4 | on: 5 | workflow_dispatch: 6 | push: 7 | branches: 8 | - master 9 | env: 10 | CLOUDFLARE_EMAIL: ${{ secrets.CLOUDFLARE_EMAIL}} 11 | CLOUDFLARE_API_KEY: ${{ secrets.CLOUDFLARE_API_KEY}} 12 | AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID}} 13 | AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY}} 14 | tf_target_dir: example/examplea 15 | 16 | permissions: read-all 17 | 18 | jobs: 19 | terraform: 20 | runs-on: ubuntu-latest 21 | steps: 22 | - uses: hashicorp/setup-terraform@v2.0.3 23 | - name: Checkout 24 | uses: actions/checkout@v3.5.2 25 | with: 26 | ref: master 27 | token: ${{ github.token }} 28 | fetch-depth: '0' 29 | - name: Config Terraform plugin cache 30 | run: | 31 | echo plugin_cache_dir="$HOME/.terraform.d/plugin-cache" >~/.terraformrc 32 | mkdir --parents ~/.terraform.d/plugin-cache 33 | - name: Cache Terraform 34 | uses: actions/cache@v3.3.1 35 | with: 36 | path: | 37 | ~/.terraform.d/plugin-cache 38 | key: ${{ runner.os }}-terraform-${{ hashFiles('**/.terraform.lock.hcl') }} 39 | restore-keys: | 40 | ${{ runner.os }}-terraform- 41 | - name: Terraform Init 42 | id: init 43 | run: terraform init 44 | working-directory: ${{ env.tf_target_dir }} 45 | - name: Terraform Apply 46 | id: apply 47 | run: terraform apply --auto-approve 48 | working-directory: ${{ env.tf_target_dir }} 49 | version: 50 | permissions: write-all 51 | name: versioning 52 | runs-on: ubuntu-latest 53 | steps: 54 | - uses: actions/checkout@v3.5.2 55 | with: 56 | fetch-depth: '0' 57 | - name: Bump version and push tag 58 | uses: anothrNick/github-tag-action@1.61.0 59 | env: 60 | GITHUB_TOKEN: ${{ github.token }} 61 | DEFAULT_BUMP: patch 62 | WITH_V: "true" 63 | needs: [terraform] 64 | -------------------------------------------------------------------------------- /example/examplea/Makefile: -------------------------------------------------------------------------------- 1 | # Makefile 2 | ifdef OS 3 | BLAT = $(powershell -noprofile rm .\.terraform\ -force -recurse) 4 | RM = $(powershell -noprofile rm .\.terraform\ -force -recurse) 5 | else 6 | ifeq ($(shell uname), Linux) 7 | RM = rm .terraform/modules/ -fr 8 | BLAT= rm .terraform/ -fr 9 | endif 10 | endif 11 | 12 | .PHONY: all 13 | 14 | all: init plan build 15 | 16 | init: 17 | $(RM) 18 | terraform init -reconfigure -upgrade 19 | 20 | plan: 21 | terraform plan --out tfplan.binary -refresh=true 22 | 23 | planned: init 24 | terraform plan -out tf.plan 25 | terraform show -json tf.plan > tf.json 26 | checkov -f tf.json 27 | 28 | p: 29 | terraform plan -refresh=true 30 | 31 | apply: build 32 | 33 | build: 34 | terraform apply -auto-approve 35 | 36 | convert: 37 | terraform show -json tfplan.binary > tfplan.json 38 | 39 | check: init 40 | terraform plan -detailed-exitcode 41 | 42 | destroy: init 43 | terraform destroy -force 44 | 45 | docs: 46 | terraform-docs md . > README.md 47 | 48 | valid: 49 | -terraform fmt -recursive 50 | -checkov -d . --external-checks-dir ../../checkov 51 | -tfsec . --tfvars-file examples.auto.tfvars 52 | -terrascan scan 53 | docker pull checkmarx/kics:latest 54 | docker run -v $(CURDIR):/path checkmarx/kics:latest scan --path /path 55 | 56 | compare: 57 | -checkov -d . --external-checks-dir ../../checkov -o json >../../output/checkov.json 58 | -terrascan scan -o json -x json >../../output/terrascan.json 59 | -tfsec . --out ../../output/tfsec.json -f json -s 60 | docker pull checkmarx/kics:latest 61 | docker run -v $(CURDIR):/path -v $(CURDIR)/../../output:/output checkmarx/kics:latest scan --path "/path" -o "/output/kics.json" 62 | 63 | conftest: plan convert 64 | conftest test ./tfplan.json -p ../../policies 65 | 66 | opa: plan convert 67 | opa eval --format pretty --data terraform.rego --input tfplan.json "data.terraform.analysis.authz" 68 | 69 | target: 70 | @read -p "Enter Module to target:" MODULE; 71 | terraform apply -target $$MODULE 72 | 73 | purge: 74 | $(BLAT) 75 | 76 | cost: 77 | infracost breakdown --path . --usage-file infracost-usage.yml --sync-usage-file --show-skipped 78 | -------------------------------------------------------------------------------- /example/frommodule/Makefile: -------------------------------------------------------------------------------- 1 | # Makefile 2 | ifdef OS 3 | BLAT = $(powershell -noprofile rm .\.terraform\ -force -recurse) 4 | RM = $(powershell -noprofile rm .\.terraform\ -force -recurse) 5 | else 6 | ifeq ($(shell uname), Linux) 7 | RM = rm .terraform/modules/ -fr 8 | BLAT= rm .terraform/ -fr 9 | endif 10 | endif 11 | 12 | .PHONY: all 13 | 14 | all: init plan build 15 | 16 | init: 17 | $(RM) 18 | terraform init -reconfigure -upgrade 19 | 20 | plan: 21 | terraform plan --out tfplan.binary -refresh=true 22 | 23 | planned: init 24 | terraform plan -out tf.plan 25 | terraform show -json tf.plan > tf.json 26 | checkov -f tf.json 27 | 28 | p: 29 | terraform plan -refresh=true 30 | 31 | apply: build 32 | 33 | build: 34 | terraform apply -auto-approve 35 | 36 | convert: 37 | terraform show -json tfplan.binary > tfplan.json 38 | 39 | check: init 40 | terraform plan -detailed-exitcode 41 | 42 | destroy: init 43 | terraform destroy -force 44 | 45 | docs: 46 | terraform-docs md . > README.md 47 | 48 | valid: 49 | -terraform fmt -recursive 50 | -checkov -d . --external-checks-dir ../../checkov 51 | -tfsec . --tfvars-file examples.auto.tfvars 52 | -terrascan scan 53 | docker pull checkmarx/kics:latest 54 | docker run -v $(CURDIR):/path checkmarx/kics:latest scan --path /path 55 | 56 | compare: 57 | -checkov -d . --external-checks-dir ../../checkov -o json >../../output/checkov.json 58 | -terrascan scan -o json -x json >../../output/terrascan.json 59 | -tfsec . --out ../../output/tfsec.json -f json -s 60 | docker pull checkmarx/kics:latest 61 | docker run -v $(CURDIR):/path -v $(CURDIR)/../../output:/output checkmarx/kics:latest scan --path "/path" -o "/output/kics.json" 62 | 63 | conftest: plan convert 64 | conftest test ./tfplan.json -p ../../policies 65 | 66 | opa: plan convert 67 | opa eval --format pretty --data terraform.rego --input tfplan.json "data.terraform.analysis.authz" 68 | 69 | target: 70 | @read -p "Enter Module to target:" MODULE; 71 | terraform apply -target $$MODULE 72 | 73 | purge: 74 | $(BLAT) 75 | 76 | cost: 77 | infracost breakdown --path . --usage-file infracost-usage.yml --sync-usage-file --show-skipped 78 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /cloudflare_teams_rule.block_ads.tf: -------------------------------------------------------------------------------- 1 | # ============================================================================== 2 | # POLICY: Block Ads 3 | # ============================================================================== 4 | locals { 5 | # Iterate through each pihole_domain_list resource and extract its ID 6 | pihole_domain_lists = [for k, v in cloudflare_teams_list.pihole_domain_lists : v.id] 7 | 8 | # Format the values: remove dashes and prepend $ 9 | pihole_domain_lists_formatted = [for v in local.pihole_domain_lists : format("$%s", replace(v, "-", ""))] 10 | 11 | # Create filters to use in the policy 12 | pihole_ad_filters = formatlist("any(dns.domains[*] in %s)", local.pihole_domain_lists_formatted) 13 | pihole_ad_filter = join(" or ", local.pihole_ad_filters) 14 | } 15 | 16 | resource "cloudflare_teams_rule" "block_ads" { 17 | account_id = local.account_id 18 | 19 | name = "Block Ads" 20 | description = "Block Ads domains" 21 | 22 | enabled = true 23 | precedence = 11 24 | 25 | # Block domain belonging to lists (defined below) 26 | filters = ["dns"] 27 | action = "block" 28 | traffic = local.pihole_ad_filter 29 | 30 | rule_settings { 31 | block_page_enabled = false 32 | } 33 | } 34 | 35 | 36 | # ============================================================================== 37 | # LISTS: AD Blocking domain list 38 | # 39 | # Remote source: 40 | # - https://firebog.net/ 41 | # - https://adaway.org/hosts.txt 42 | # Local file: 43 | # - ./cloudflare/lists/pihole_domain_list.txt 44 | # - the file can be updated periodically via Github Actions (see README) 45 | # ============================================================================== 46 | locals { 47 | # The full path of the list holding the domain list 48 | pihole_domain_list_file = "${path.module}/cloudflare/lists/pihole_domain_list.txt" 49 | 50 | # Parse the file and create a list, one item per line 51 | pihole_domain_list = split("\n", file(local.pihole_domain_list_file)) 52 | 53 | # Remove empty lines 54 | pihole_domain_list_clean = [for x in local.pihole_domain_list : x if x != ""] 55 | 56 | # Use chunklist to split a list into fixed-size chunks 57 | # It returns a list of lists 58 | pihole_aggregated_lists = chunklist(local.pihole_domain_list_clean, 1000) 59 | 60 | # Get the number of lists (chunks) created 61 | pihole_list_count = length(local.pihole_aggregated_lists) 62 | } 63 | 64 | 65 | resource "cloudflare_teams_list" "pihole_domain_lists" { 66 | account_id = local.account_id 67 | for_each = { 68 | for i in range(0, local.pihole_list_count) : 69 | i => element(local.pihole_aggregated_lists, i) 70 | } 71 | 72 | name = "pihole_domain_list_${each.key}" 73 | type = "DOMAIN" 74 | items = each.value 75 | } 76 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # terraform-cloudflare-adblock 2 | 3 | [![Build Status](https://github.com/JamesWoolfenden/terraform-cloudflare-adblock/workflows/Deploy%20and%20Bump/badge.svg?branch=master)](https://github.com/JamesWoolfenden/terraform-cloudflare-adblock) 4 | [![Latest Release](https://img.shields.io/github/release/JamesWoolfenden/terraform-cloudflare-adblock.svg)](https://github.com/JamesWoolfenden/terraform-cloudflare-adblock/releases/latest) 5 | [![GitHub tag (latest SemVer)](https://img.shields.io/github/tag/JamesWoolfenden/terraform-cloudflare-adblock.svg?label=latest)](https://github.com/JamesWoolfenden/terraform-cloudflare-adblock/releases/latest) 6 | ![Terraform Version](https://img.shields.io/badge/tf-%3E%3D0.14.0-blue.svg) 7 | [![Infrastructure Tests](https://www.bridgecrew.cloud/badges/github/JamesWoolfenden/terraform-cloudflare-adblock/cis_aws)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=JamesWoolfenden%2Fterraform-cloudflare-adblock&benchmark=CIS+AWS+V1.2) 8 | [![pre-commit](https://img.shields.io/badge/pre--commit-enabled-brightgreen?logo=pre-commit&logoColor=white)](https://github.com/pre-commit/pre-commit) 9 | [![checkov](https://img.shields.io/badge/checkov-verified-brightgreen)](https://www.checkov.io/) 10 | [![Infrastructure Tests](https://www.bridgecrew.cloud/badges/github/jameswoolfenden/terraform-cloudflare-adblock/general)](https://www.bridgecrew.cloud/link/badge?vcs=github&fullRepo=JamesWoolfenden%2Fterraform-cloudflare-adblock&benchmark=INFRASTRUCTURE+SECURITY) 11 | 12 | Terraform module - 13 | 14 | This module helps you set up a Cloudflare team for use with the Warp client, enabling Malware protection and Adblocking. 15 | 16 | You need to register for an account first and then install the Cloudflare Warp client on the devices you want to protect. 17 | 18 | 19 | 20 | This module does everything else, sets up the block lists and has 2 GHA that keep the list updated and deploy it. 21 | 22 | --- 23 | 24 | It's 100% Open Source and licensed under the [APACHE2](LICENSE). 25 | 26 | ## Usage 27 | 28 | ```terraform 29 | module "adblock" { 30 | source = "JamesWoolfenden/adblock/cloudflare" 31 | version = "0.0.1" 32 | team_name = "" 33 | } 34 | ``` 35 | 36 | To run a copy of the Github action (Deploy and Bump), you need to add the env vars to your repository secrets: 37 | 38 | CLOUDFLARE_API_KEY 39 | 40 | CLOUDFLARE_EMAIL 41 | 42 | I'm also using an AWS state file, if you use the same then you'll also need to provide adequate AWS creds and env vars. 43 | 44 | Adapted from . 45 | 46 | 47 | ## Requirements 48 | 49 | | Name | Version | 50 | |------|---------| 51 | | [cloudflare](#requirement\_cloudflare) | 3.33.1 | 52 | 53 | ## Providers 54 | 55 | | Name | Version | 56 | |------|---------| 57 | | [cloudflare](#provider\_cloudflare) | 3.33.1 | 58 | 59 | ## Modules 60 | 61 | No modules. 62 | 63 | ## Resources 64 | 65 | | Name | Type | 66 | |------|------| 67 | | [cloudflare_teams_account.woolfenden](https://registry.terraform.io/providers/cloudflare/cloudflare/3.33.1/docs/resources/teams_account) | resource | 68 | | [cloudflare_teams_list.pihole_domain_lists](https://registry.terraform.io/providers/cloudflare/cloudflare/3.33.1/docs/resources/teams_list) | resource | 69 | | [cloudflare_teams_rule.block_ads](https://registry.terraform.io/providers/cloudflare/cloudflare/3.33.1/docs/resources/teams_rule) | resource | 70 | | [cloudflare_teams_rule.block_malware](https://registry.terraform.io/providers/cloudflare/cloudflare/3.33.1/docs/resources/teams_rule) | resource | 71 | | [cloudflare_accounts.woolfenden](https://registry.terraform.io/providers/cloudflare/cloudflare/3.33.1/docs/data-sources/accounts) | data source | 72 | 73 | ## Inputs 74 | 75 | | Name | Description | Type | Default | Required | 76 | |------|-------------|------|---------|:--------:| 77 | | [logo\_path](#input\_logo\_path) | n/a | `string` | `"https://pbs.twimg.com/profile_images/1408927094315393028/WkL6f1Qf_400x400.jpg"` | no | 78 | | [team\_name](#input\_team\_name) | Your cloudflare team name | `string` | n/a | yes | 79 | 80 | ## Outputs 81 | 82 | | Name | Description | 83 | |------|-------------| 84 | | [account](#output\_account) | n/a | 85 | | [accounts](#output\_accounts) | n/a | 86 | | [malware\_rule](#output\_malware\_rule) | n/a | 87 | | [team](#output\_team) | n/a | 88 | 89 | 90 | ## Policy 91 | 92 | This is the policy required to build this project: 93 | 94 | 95 | 96 | and Using 97 | 98 | ## Keeping the domain list up to date 99 | 100 | The `action-update-list.yml` provides a sample 101 | GitHub Actions workflow that periodically (monthly) fetches the list upstream and commits it to the repo if it has changed. 102 | 103 | ![workflow](https://blog.marcolancini.it/images/posts/blog_serverless_adblocking_gh_workflow.png) 104 | 105 | ## Related Projects 106 | 107 | Check out these related projects. 108 | 109 | - [terraform-aws-s3](https://github.com/jameswoolfenden/terraform-aws-s3) - S3 buckets 110 | 111 | ## Help 112 | 113 | **Got a question?** 114 | 115 | File a GitHub [issue](https://github.com/JamesWoolfenden/terraform-cloudflare-adblock/issues). 116 | 117 | ## Contributing 118 | 119 | ### Bug Reports & Feature Requests 120 | 121 | Please use the [issue tracker](https://github.com/JamesWoolfenden/terraform-cloudflare-adblock/issues) to report any bugs or file feature requests. 122 | 123 | ## Copyrights 124 | 125 | Copyright � 2023 James Woolfenden 126 | 127 | ## License 128 | 129 | [![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0) 130 | 131 | See [LICENSE](LICENSE) for full details. 132 | 133 | Licensed to the Apache Software Foundation (ASF) under one 134 | or more contributor license agreements. See the NOTICE file 135 | distributed with this work for additional information 136 | regarding copyright ownership. The ASF licenses this file 137 | to you under the Apache License, Version 2.0 (the 138 | "License"); you may not use this file except in compliance 139 | with the License. You may obtain a copy of the License at 140 | 141 | 142 | 143 | Unless required by applicable law or agreed to in writing, 144 | software distributed under the License is distributed on an 145 | "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 146 | KIND, either express or implied. See the License for the 147 | specific language governing permissions and limitations 148 | under the License. 149 | 150 | ### Contributors 151 | 152 | [![James Woolfenden][jameswoolfenden_avatar]][jameswoolfenden_homepage]
[James Woolfenden][jameswoolfenden_homepage] 153 | 154 | [jameswoolfenden_homepage]: https://github.com/jameswoolfenden 155 | [jameswoolfenden_avatar]: https://github.com/jameswoolfenden.png?size=150 156 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | --------------------------------------------------------------------------------