Skip to content

terraform-yc-modules/terraform-yc-sws

Repository files navigation

Smart Web Security (SWS) Terraform module for Yandex.Cloud

Features

  • Create WAF and ARL profiles
  • Create security profile
  • You can use your own Captcha ID, or default one from Yandex Cloud will be used
  • See different examples
  • For settings descriptions see Yandex Cloud SWS documentation

Condition block structure (used in smart_protection, waf, and rule_condition, advanced_rate_limiter_rules, waf_exclusion_rules) source link:

  • authority block (optional):

    • authorities (list of objects with attribute)
  • http_method block (optional):

    • http_methods (list of objects with attribute)
  • request_uri block (optional):

    • path block (optional)

    • queries (optional, list):

      • key (string, required): Query string key.
      • value block (optional)
  • headers (optional, list):

    • name (string, required): HTTP header name.
    • value block (optional)
  • source_ip block (optional):

    • ip_ranges_match block (optional):
      • ip_ranges (list of strings, optional): IP ranges to match.
    • ip_ranges_not_match block (optional):
      • ip_ranges (list of strings, optional): IP ranges to exclude.
    • geo_ip_match block (optional):
      • locations (list of strings, optional): ISO country codes to match.
    • geo_ip_not_match block (optional):
      • locations (list of strings, optional): ISO country codes to exclude.

How to get and set WAF rules id from core rule set

GET Enter into the terraform console data.yandex_sws_waf_rule_set_descriptor.rule_set. example

data "yandex_sws_waf_rule_set_descriptor" "rule_set" {
  name    = "OWASP Core Ruleset"
  version = "4.0.0"
}

SET

waf_rules = [{
    is_blocking = false
    is_enabled  = false
    rule_id     = "owasp-crs-v4.0.0-id944152-attack-java" # Rule ID
  }]

How to Configure Terraform for Yandex.Cloud

  • Install YC CLI
  • Add environment variables for terraform authentication in Yandex.Cloud
export YC_TOKEN=$(yc iam create-token)
export YC_CLOUD_ID=$(yc config get cloud-id)
export YC_FOLDER_ID=$(yc config get folder-id)

Requirements

Name Version
terraform >= 1.0.0
yandex >= 0.101.0

Providers

Name Version
yandex 0.139.0

Modules

No modules.

Resources

Name Type
yandex_sws_advanced_rate_limiter_profile.this resource
yandex_sws_security_profile.this resource
yandex_sws_waf_profile.this resource
yandex_client_config.client data source
yandex_sws_waf_rule_set_descriptor.rule_set data source

Inputs

Name Description Type Default Required
advanced_rate_limiter_rules List of ARL rules with quotas and conditions.
list(object({
name = string
priority = number
description = optional(string)
dry_run = optional(bool)

static_quota = optional(object({
action = string
limit = number
period = number
condition = optional(object({
authority = optional(object({
authorities = list(object({
exact_match = optional(string)
exact_not_match = optional(string)
prefix_match = optional(string)
prefix_not_match = optional(string)
pire_regex_match = optional(string)
pire_regex_not_match = optional(string)
}))
}))
http_method = optional(object({
http_methods = list(object({
exact_match = optional(string)
exact_not_match = optional(string)
prefix_match = optional(string)
prefix_not_match = optional(string)
pire_regex_match = optional(string)
pire_regex_not_match = optional(string)
}))
}))
request_uri = optional(object({
path = optional(object({
exact_match = optional(string)
exact_not_match = optional(string)
prefix_match = optional(string)
prefix_not_match = optional(string)
pire_regex_match = optional(string)
pire_regex_not_match = optional(string)
}))
queries = optional(list(object({
key = string
value = optional(object({
exact_match = optional(string)
exact_not_match = optional(string)
prefix_match = optional(string)
prefix_not_match = optional(string)
pire_regex_match = optional(string)
pire_regex_not_match = optional(string)
}))
})))
}))
headers = optional(list(object({
name = string
value = optional(object({
exact_match = optional(string)
exact_not_match = optional(string)
prefix_match = optional(string)
prefix_not_match = optional(string)
pire_regex_match = optional(string)
pire_regex_not_match = optional(string)
}))
})))
source_ip = optional(object({
ip_ranges_match = optional(object({
ip_ranges = list(string)
}))
ip_ranges_not_match = optional(object({
ip_ranges = list(string)
}))
geo_ip_match = optional(object({
locations = list(string)
}))
geo_ip_not_match = optional(object({
locations = list(string)
}))
}))
}))
}))

dynamic_quota = optional(object({
action = string
limit = number
period = number
condition = optional(object({
authority = optional(object({
authorities = list(object({
exact_match = optional(string)
exact_not_match = optional(string)
prefix_match = optional(string)
prefix_not_match = optional(string)
pire_regex_match = optional(string)
pire_regex_not_match = optional(string)
}))
}))
http_method = optional(object({
http_methods = list(object({
exact_match = optional(string)
exact_not_match = optional(string)
prefix_match = optional(string)
prefix_not_match = optional(string)
pire_regex_match = optional(string)
pire_regex_not_match = optional(string)
}))
}))
request_uri = optional(object({
path = optional(object({
exact_match = optional(string)
exact_not_match = optional(string)
prefix_match = optional(string)
prefix_not_match = optional(string)
pire_regex_match = optional(string)
pire_regex_not_match = optional(string)
}))
queries = optional(list(object({
key = string
value = optional(object({
exact_match = optional(string)
exact_not_match = optional(string)
prefix_match = optional(string)
prefix_not_match = optional(string)
pire_regex_match = optional(string)
pire_regex_not_match = optional(string)
}))
})))
}))
headers = optional(list(object({
name = string
value = optional(object({
exact_match = optional(string)
exact_not_match = optional(string)
prefix_match = optional(string)
prefix_not_match = optional(string)
pire_regex_match = optional(string)
pire_regex_not_match = optional(string)
}))
})))
source_ip = optional(object({
ip_ranges_match = optional(object({
ip_ranges = list(string)
}))
ip_ranges_not_match = optional(object({
ip_ranges = list(string)
}))
geo_ip_match = optional(object({
locations = list(string)
}))
geo_ip_not_match = optional(object({
locations = list(string)
}))
}))
}))
characteristic = list(object({
case_insensitive = optional(bool)
simple_characteristic = optional(object({
type = string
}))
key_characteristic = optional(object({
type = string
value = string
}))
}))
}))
}))
[] no
arl_enabled Advanced Rate Limiter enabled flag. bool false no
captcha_id Captcha ID (optional). Set empty to use default. string null no
default_action Default action (ALLOW or DENY). string "DENY" no
description Description for SWS resources. string null no
folder_id Folder for SWS resources. string null no
labels Labels for resources. map(string)
{
"created_by": "terraform-yc-module"
}
no
name Name for resources. string n/a yes
security_rules List of security rules for the Security Profile resource.

Each rule object supports:

- name (string, required): Name of the security rule.
- priority (number, required): Priority of the rule. The smaller the value, the higher is the rule priority.

Exactly one of the following blocks may be specified per rule:

1. smart_protection block (optional):
- mode (string, required): Protection mode. Possible values: "FULL", "API".
- condition block (optional): Conditions when this protection is applied (see detailed structure below).

2. waf block (optional):
- mode (string, required): WAF mode. Possible values: "FULL", "API".
- condition block (optional): Conditions when WAF rules are applied (see detailed structure below).

3. rule_condition block (optional):
- action (string, required): Action to perform if condition matches. Possible values: "ALLOW", "DENY".
- condition block (optional): Conditions when this action is applied (see detailed structure below).

Condition block structure (used in smart_protection, waf, and rule_condition):

- authority block (optional):
- authorities (list of objects with attribute)

- http_method block (optional):
- http_methods (list of objects with attribute)

- request_uri block (optional):
- path block (optional)

- queries (optional, list):
- key (string, required): Query string key.
- value block (optional)

- headers (optional, list):
- name (string, required): HTTP header name.
- value block (optional)

- source_ip block (optional):
- ip_ranges_match block (optional):
- ip_ranges (list of strings, optional): IP ranges to match.
- ip_ranges_not_match block (optional):
- ip_ranges (list of strings, optional): IP ranges to exclude.
- geo_ip_match block (optional):
- locations (list of strings, optional): ISO country codes to match.
- geo_ip_not_match block (optional):
- locations (list of strings, optional): ISO country codes to exclude.
list(object({
name = string
priority = number
dry_run = optional(bool)

smart_protection = optional(object({
mode = string
condition = optional(object({
authority = optional(object({
authorities = list(object({
exact_match = optional(string)
exact_not_match = optional(string)
prefix_match = optional(string)
prefix_not_match = optional(string)
pire_regex_match = optional(string)
pire_regex_not_match = optional(string)
}))
}))
http_method = optional(object({
http_methods = list(object({
exact_match = optional(string)
exact_not_match = optional(string)
prefix_match = optional(string)
prefix_not_match = optional(string)
pire_regex_match = optional(string)
pire_regex_not_match = optional(string)
}))
}))
request_uri = optional(object({
path = optional(object({
exact_match = optional(string)
exact_not_match = optional(string)
prefix_match = optional(string)
prefix_not_match = optional(string)
pire_regex_match = optional(string)
pire_regex_not_match = optional(string)
}))
queries = optional(list(object({
key = string
value = optional(object({
exact_match = optional(string)
exact_not_match = optional(string)
prefix_match = optional(string)
prefix_not_match = optional(string)
pire_regex_match = optional(string)
pire_regex_not_match = optional(string)
}))
})))
}))
headers = optional(list(object({
name = string
value = optional(object({
exact_match = optional(string)
exact_not_match = optional(string)
prefix_match = optional(string)
prefix_not_match = optional(string)
pire_regex_match = optional(string)
pire_regex_not_match = optional(string)
}))
})))
source_ip = optional(object({
ip_ranges_match = optional(object({
ip_ranges = list(string)
}))
ip_ranges_not_match = optional(object({
ip_ranges = list(string)
}))
geo_ip_match = optional(object({
locations = list(string)
}))
geo_ip_not_match = optional(object({
locations = list(string)
}))
}))
}))
}), null)

waf = optional(object({
mode = string
condition = optional(object({
authority = optional(object({
authorities = list(object({
exact_match = optional(string)
exact_not_match = optional(string)
prefix_match = optional(string)
prefix_not_match = optional(string)
pire_regex_match = optional(string)
pire_regex_not_match = optional(string)
}))
}))
http_method = optional(object({
http_methods = list(object({
exact_match = optional(string)
exact_not_match = optional(string)
prefix_match = optional(string)
prefix_not_match = optional(string)
pire_regex_match = optional(string)
pire_regex_not_match = optional(string)
}))
}))
request_uri = optional(object({
path = optional(object({
exact_match = optional(string)
exact_not_match = optional(string)
prefix_match = optional(string)
prefix_not_match = optional(string)
pire_regex_match = optional(string)
pire_regex_not_match = optional(string)
}))
queries = optional(list(object({
key = string
value = optional(object({
exact_match = optional(string)
exact_not_match = optional(string)
prefix_match = optional(string)
prefix_not_match = optional(string)
pire_regex_match = optional(string)
pire_regex_not_match = optional(string)
}))
})))
}))
headers = optional(list(object({
name = string
value = optional(object({
exact_match = optional(string)
exact_not_match = optional(string)
prefix_match = optional(string)
prefix_not_match = optional(string)
pire_regex_match = optional(string)
pire_regex_not_match = optional(string)
}))
})))
source_ip = optional(object({
ip_ranges_match = optional(object({
ip_ranges = list(string)
}))
ip_ranges_not_match = optional(object({
ip_ranges = list(string)
}))
geo_ip_match = optional(object({
locations = list(string)
}))
geo_ip_not_match = optional(object({
locations = list(string)
}))
}))
}))
}), null)

rule_condition = optional(object({
action = string
condition = optional(object({
authority = optional(object({
authorities = list(object({
exact_match = optional(string)
exact_not_match = optional(string)
prefix_match = optional(string)
prefix_not_match = optional(string)
pire_regex_match = optional(string)
pire_regex_not_match = optional(string)
}))
}))
http_method = optional(object({
http_methods = list(object({
exact_match = optional(string)
exact_not_match = optional(string)
prefix_match = optional(string)
prefix_not_match = optional(string)
pire_regex_match = optional(string)
pire_regex_not_match = optional(string)
}))
}))
request_uri = optional(object({
path = optional(object({
exact_match = optional(string)
exact_not_match = optional(string)
prefix_match = optional(string)
prefix_not_match = optional(string)
pire_regex_match = optional(string)
pire_regex_not_match = optional(string)
}))
queries = optional(list(object({
key = string
value = optional(object({
exact_match = optional(string)
exact_not_match = optional(string)
prefix_match = optional(string)
prefix_not_match = optional(string)
pire_regex_match = optional(string)
pire_regex_not_match = optional(string)
}))
})))
}))
headers = optional(list(object({
name = string
value = optional(object({
exact_match = optional(string)
exact_not_match = optional(string)
prefix_match = optional(string)
prefix_not_match = optional(string)
pire_regex_match = optional(string)
pire_regex_not_match = optional(string)
}))
})))
source_ip = optional(object({
ip_ranges_match = optional(object({
ip_ranges = list(string)
}))
ip_ranges_not_match = optional(object({
ip_ranges = list(string)
}))
geo_ip_match = optional(object({
locations = list(string)
}))
geo_ip_not_match = optional(object({
locations = list(string)
}))
}))
}))
}), null)
}))
n/a yes
waf_analyze_request_body Analyze request body settings.
object({
is_enabled = bool
size_limit = optional(number)
size_limit_action = optional(string)
})
{
"is_enabled": false
}
no
waf_core_rule_set Basic rule set settings.
object({
inbound_anomaly_score = number
paranoia_level = number
rule_set_name = string
rule_set_version = string
is_enabled = bool
is_blocking = bool
})
{
"inbound_anomaly_score": 25,
"is_blocking": false,
"is_enabled": true,
"paranoia_level": 1,
"rule_set_name": "OWASP Core Ruleset",
"rule_set_version": "4.0.0"
}
no
waf_exclusion_rules List of exclusion rules.
list(object({
name = string
description = optional(string)
log_excluded = optional(bool)
condition = optional(object({
authority = optional(object({
authorities = list(object({
exact_match = optional(string)
exact_not_match = optional(string)
prefix_match = optional(string)
prefix_not_match = optional(string)
pire_regex_match = optional(string)
pire_regex_not_match = optional(string)
}))
}))
http_method = optional(object({
http_methods = list(object({
exact_match = optional(string)
exact_not_match = optional(string)
prefix_match = optional(string)
prefix_not_match = optional(string)
pire_regex_match = optional(string)
pire_regex_not_match = optional(string)
}))
}))
request_uri = optional(object({
path = optional(object({
exact_match = optional(string)
exact_not_match = optional(string)
prefix_match = optional(string)
prefix_not_match = optional(string)
pire_regex_match = optional(string)
pire_regex_not_match = optional(string)
}))
queries = optional(list(object({
key = string
value = optional(object({
exact_match = optional(string)
exact_not_match = optional(string)
prefix_match = optional(string)
prefix_not_match = optional(string)
pire_regex_match = optional(string)
pire_regex_not_match = optional(string)
}))
})))
}))
headers = optional(list(object({
name = string
value = optional(object({
exact_match = optional(string)
exact_not_match = optional(string)
prefix_match = optional(string)
prefix_not_match = optional(string)
pire_regex_match = optional(string)
pire_regex_not_match = optional(string)
}))
})))
source_ip = optional(object({
ip_ranges_match = optional(object({
ip_ranges = list(string)
}))
ip_ranges_not_match = optional(object({
ip_ranges = list(string)
}))
geo_ip_match = optional(object({
locations = list(string)
}))
geo_ip_not_match = optional(object({
locations = list(string)
}))
}))
}))
exclude_rules = optional(object({
exclude_all = optional(bool)
rule_ids = optional(list(string))
}))
}))
[] no
waf_rules Additional rules for WAF profile.
list(object({
rule_id = string
is_enabled = bool
is_blocking = bool
}))
[] no

Outputs

Name Description
arl_profile_id The ID of the created ARL profile.
security_profile_id The ID of the created security profile.
waf_profile_id ID созданного WAF профиля.

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages