Skip to content

Commit

Permalink
OPS-5899 Adopt old module for cloudflare firewall rules (#1)
Browse files Browse the repository at this point in the history
  • Loading branch information
snovikov authored Apr 12, 2024
1 parent 8bbebaa commit ff98f4e
Show file tree
Hide file tree
Showing 10 changed files with 171 additions and 28 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,6 @@ override.tf.json

# Vars file
/*.tfvars

#IDEA
.idea
26 changes: 13 additions & 13 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,19 @@ endif

.PHONY: help gen lint test _gen-main _gen-examples _gen-modules _lint-files _lint-fmt _lint-json _pull-tf _pull-tfdocs _pull-fl _pull-jl

CURRENT_DIR = $(dir $(abspath $(lastword $(MAKEFILE_LIST))))
TF_EXAMPLES = $(sort $(dir $(wildcard $(CURRENT_DIR)examples/*/)))
TF_MODULES = $(sort $(dir $(wildcard $(CURRENT_DIR)modules/*/)))
CURRENT_DIR = $(dir $(abspath $(lastword $(MAKEFILE_LIST))))
TF_EXAMPLES = $(sort $(dir $(wildcard $(CURRENT_DIR)examples/*/)))
TF_MODULES = $(sort $(dir $(wildcard $(CURRENT_DIR)modules/*/)))
FL_IGNORE_PATHS = .git/,.github/,.terraform/,.idea/

# -------------------------------------------------------------------------------------------------
# Container versions
# -------------------------------------------------------------------------------------------------
TF_VERSION = 1.3.9
TF_VERSION = 1.5.7
TFDOCS_VERSION = 0.16.0-0.34
FL_VERSION = latest-0.8
JL_VERSION = 1.6.0-0.14


# -------------------------------------------------------------------------------------------------
# Enable linter (file-lint, terraform fmt, jsonlint)
# -------------------------------------------------------------------------------------------------
Expand Down Expand Up @@ -218,12 +218,12 @@ _lint-files: _pull-fl
@echo "################################################################################"
@echo "# File-lint"
@echo "################################################################################"
@docker run $$(tty -s && echo "-it" || echo) --rm -v $(CURRENT_DIR):/data cytopia/file-lint:$(FL_VERSION) file-cr --text --ignore '.git/,.github/,.terraform/' --path .
@docker run $$(tty -s && echo "-it" || echo) --rm -v $(CURRENT_DIR):/data cytopia/file-lint:$(FL_VERSION) file-crlf --text --ignore '.git/,.github/,.terraform/' --path .
@docker run $$(tty -s && echo "-it" || echo) --rm -v $(CURRENT_DIR):/data cytopia/file-lint:$(FL_VERSION) file-trailing-single-newline --text --ignore '.git/,.github/,.terraform/' --path .
@docker run $$(tty -s && echo "-it" || echo) --rm -v $(CURRENT_DIR):/data cytopia/file-lint:$(FL_VERSION) file-trailing-space --text --ignore '.git/,.github/,.terraform/' --path .
@docker run $$(tty -s && echo "-it" || echo) --rm -v $(CURRENT_DIR):/data cytopia/file-lint:$(FL_VERSION) file-utf8 --text --ignore '.git/,.github/,.terraform/' --path .
@docker run $$(tty -s && echo "-it" || echo) --rm -v $(CURRENT_DIR):/data cytopia/file-lint:$(FL_VERSION) file-utf8-bom --text --ignore '.git/,.github/,.terraform/' --path .
@docker run $$(tty -s && echo "-it" || echo) --rm -v $(CURRENT_DIR):/data cytopia/file-lint:$(FL_VERSION) file-cr --text --ignore '$(FL_IGNORE_PATHS)' --path .
@docker run $$(tty -s && echo "-it" || echo) --rm -v $(CURRENT_DIR):/data cytopia/file-lint:$(FL_VERSION) file-crlf --text --ignore '$(FL_IGNORE_PATHS)' --path .
@docker run $$(tty -s && echo "-it" || echo) --rm -v $(CURRENT_DIR):/data cytopia/file-lint:$(FL_VERSION) file-trailing-single-newline --text --ignore '$(FL_IGNORE_PATHS)' --path .
@docker run $$(tty -s && echo "-it" || echo) --rm -v $(CURRENT_DIR):/data cytopia/file-lint:$(FL_VERSION) file-trailing-space --text --ignore '$(FL_IGNORE_PATHS)' --path .
@docker run $$(tty -s && echo "-it" || echo) --rm -v $(CURRENT_DIR):/data cytopia/file-lint:$(FL_VERSION) file-utf8 --text --ignore '$(FL_IGNORE_PATHS)' --path .
@docker run $$(tty -s && echo "-it" || echo) --rm -v $(CURRENT_DIR):/data cytopia/file-lint:$(FL_VERSION) file-utf8-bom --text --ignore '$(FL_IGNORE_PATHS)' --path .

_lint-fmt: _pull-tf
@# Lint all Terraform files
Expand All @@ -235,7 +235,7 @@ _lint-fmt: _pull-tf
@echo "# *.tf files"
@echo "------------------------------------------------------------"
@if docker run $$(tty -s && echo "-it" || echo) --rm -v "$(CURRENT_DIR):/t:ro" --workdir "/t" hashicorp/terraform:$(TF_VERSION) \
fmt -recursive -check=true -diff=true -write=false -list=true .; then \
fmt -recursive -check=true -diff=true -write=true -list=true .; then \
echo "OK"; \
else \
echo "Failed"; \
Expand All @@ -246,7 +246,7 @@ _lint-fmt: _pull-tf
@echo "# *.tfvars files"
@echo "------------------------------------------------------------"
@if docker run $$(tty -s && echo "-it" || echo) --rm --entrypoint=/bin/sh -v "$(CURRENT_DIR):/t:ro" --workdir "/t" hashicorp/terraform:$(TF_VERSION) \
-c "find . -name '*.tfvars' -type f -print0 | xargs -0 -n1 terraform fmt -check=true -write=false -diff=true -list=true"; then \
-c "find . -name '*.tfvars' -type f -print0 | xargs -0 -n1 terraform fmt -check=true -write=true -diff=true -list=true"; then \
echo "OK"; \
else \
echo "Failed"; \
Expand Down
64 changes: 49 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
# terraform-module-template
Template for Terraform modules

<!-- Uncomment and replace with your module name
[![lint](https://github.com/flaconi/<MODULENAME>/workflows/lint/badge.svg)](https://github.com/flaconi/<MODULENAME>/actions?query=workflow%3Alint)
[![test](https://github.com/flaconi/<MODULENAME>/workflows/test/badge.svg)](https://github.com/flaconi/<MODULENAME>/actions?query=workflow%3Atest)
[![Tag](https://img.shields.io/github/tag/flaconi/<MODULENAME>.svg)](https://github.com/flaconi/<MODULENAME>/releases)
-->
[![License](https://img.shields.io/badge/license-MIT-blue.svg)](https://opensource.org/licenses/MIT)
# Terraform module: Cloudflare Rulesets

This Terraform module manages Cloudflare Rulesets.

For requirements regarding module structure: [style-guide-terraform.md](https://github.com/Flaconi/devops-docs/blob/master/doc/conventions/style-guide-terraform.md)
[![lint](https://github.com/flaconi/terraform-cloudflare-rulesets/workflows/lint/badge.svg)](https://github.com/flaconi/terraform-cloudflare-rulesets/actions?query=workflow%3Alint)
[![test](https://github.com/flaconi/terraform-cloudflare-rulesets/workflows/test/badge.svg)](https://github.com/flaconi/terraform-cloudflare-rulesets/actions?query=workflow%3Atest)
[![Tag](https://img.shields.io/github/tag/flaconi/terraform-cloudflare-rulesets.svg)](https://github.com/flaconi/terraform-cloudflare-rulesets/releases)
[![Terraform](https://img.shields.io/badge/Terraform--registry-cloudflare--rulesets-brightgreen.svg)](https://registry.terraform.io/modules/flaconi/rulesets/cloudflare/)
[![License](https://img.shields.io/badge/license-MIT-blue.svg)](https://opensource.org/licenses/MIT)

<!-- TFDOCS_HEADER_START -->

Expand All @@ -18,7 +16,9 @@ For requirements regarding module structure: [style-guide-terraform.md](https://
<!-- TFDOCS_PROVIDER_START -->
## Providers

No providers.
| Name | Version |
|------|---------|
| <a name="provider_cloudflare"></a> [cloudflare](#provider\_cloudflare) | ~> 4.20 |

<!-- TFDOCS_PROVIDER_END -->

Expand All @@ -28,29 +28,63 @@ No providers.
| Name | Version |
|------|---------|
| <a name="requirement_terraform"></a> [terraform](#requirement\_terraform) | ~> 1.3 |
| <a name="requirement_cloudflare"></a> [cloudflare](#requirement\_cloudflare) | ~> 4.20 |

<!-- TFDOCS_REQUIREMENTS_END -->

<!-- TFDOCS_INPUTS_START -->
## Required Inputs

No required inputs.
The following input variables are required:

### <a name="input_api_token"></a> [api\_token](#input\_api\_token)

Description: The Cloudflare API token.

Type: `string`

### <a name="input_domain"></a> [domain](#input\_domain)

Description: Cloudflare domain to apply rules for.

Type: `string`

## Optional Inputs

No optional inputs.
The following input variables are optional (have default values):

### <a name="input_rules"></a> [rules](#input\_rules)

Description: List of Cloudflare firewall rule objects.

Type:

```hcl
list(object({
description = string
enabled = bool
action = string
expression = string
products = list(string)
}))
```

Default: `[]`

<!-- TFDOCS_INPUTS_END -->

<!-- TFDOCS_OUTPUTS_START -->
## Outputs

No outputs.
| Name | Description |
|------|-------------|
| <a name="output_domain"></a> [domain](#output\_domain) | Current zone information. |
| <a name="output_rules"></a> [rules](#output\_rules) | Created Cloudflare rules for the current zone. |

<!-- TFDOCS_OUTPUTS_END -->

## License

**[MIT License](LICENSE)**

Copyright (c) 2023 **[Flaconi GmbH](https://github.com/flaconi)**
Copyright (c) 2024 **[Flaconi GmbH](https://github.com/flaconi)**
5 changes: 5 additions & 0 deletions data.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
data "cloudflare_zones" "domain" {
filter {
name = var.domain
}
}
17 changes: 17 additions & 0 deletions locals.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
locals {
rules = [for rule in var.rules :
{
action = rule.action
action_parameters = rule.action == "skip" ? {
ruleset = length(rule.products) == 0 ? "current" : null
products = length(rule.products) > 0 ? rule.products : null
} : null
description = rule.description
enabled = rule.enabled
expression = rule.expression
logging = rule.action == "skip" ? {
enabled = true
} : null
}
]
}
30 changes: 30 additions & 0 deletions main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
resource "cloudflare_ruleset" "http_request_firewall_custom" {
zone_id = lookup(data.cloudflare_zones.domain.zones[0], "id")
name = "default"
kind = "zone"
phase = "http_request_firewall_custom"

dynamic "rules" {
for_each = local.rules

content {
action = rules.value.action
dynamic "action_parameters" {
for_each = rules.value.action_parameters[*]
content {
ruleset = action_parameters.value.ruleset
products = action_parameters.value.products
}
}
description = rules.value.description
enabled = rules.value.enabled
expression = rules.value.expression
dynamic "logging" {
for_each = rules.value.logging[*]
content {
enabled = logging.value.enabled
}
}
}
}
}
9 changes: 9 additions & 0 deletions outputs.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
output "domain" {
description = "Current zone information."
value = data.cloudflare_zones.domain.zones
}

output "rules" {
description = "Created Cloudflare rules for the current zone."
value = cloudflare_ruleset.http_request_firewall_custom.rules
}
3 changes: 3 additions & 0 deletions providers.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
provider "cloudflare" {
api_token = var.api_token
}
36 changes: 36 additions & 0 deletions variables.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
variable "api_token" {
description = "The Cloudflare API token."
type = string
sensitive = true
}

variable "domain" {
description = "Cloudflare domain to apply rules for."
type = string
}

variable "rules" {
description = "List of Cloudflare firewall rule objects."
type = list(object({
description = string
enabled = bool
action = string
expression = string
products = list(string)
}))
default = []

# Ensure we specify only allows action values
# https://registry.terraform.io/providers/cloudflare/cloudflare/latest/docs/resources/firewall_rule#action
validation {
condition = can([for rule in var.rules : contains(["block", "challenge", "js_challenge", "log", "managed_challenge", "skip"], rule.action)])
error_message = "Only the following action elements are allowed: block, challenge, js_challenge, log, managed_challenge, skip."
}

# Ensure we specify only allowed products values
# https://registry.terraform.io/providers/cloudflare/cloudflare/latest/docs/resources/firewall_rule#products
validation {
condition = can([for rule in var.rules : [for product in rule.products : contains(["bic", "hot", "ratelimit", "securityLevel", "uablock", "waf", "zonelockdown"], product)]])
error_message = "Only the following product elements are allowed: bic, hot, ratelimit, securityLevel, uablock, waf, zonelockdown."
}
}
6 changes: 6 additions & 0 deletions versions.tf
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
terraform {
required_providers {
cloudflare = {
source = "cloudflare/cloudflare"
version = "~> 4.20"
}
}
required_version = "~> 1.3"
}

0 comments on commit ff98f4e

Please sign in to comment.