655 lines
20 KiB
Terraform
655 lines
20 KiB
Terraform
# =============================================================================
|
|
# CLOUDFLARE : Access Controls : Policies : Rule Groups
|
|
# =============================================================================
|
|
|
|
locals {
|
|
# SAML groups from Okta
|
|
saml_groups = {
|
|
contractors = "Contractors"
|
|
infrastructure_admin = "GL_Users_Infrastructure Admin"
|
|
sales_engineering = "GL_Users_Sales Engineering"
|
|
sales = "GL_Users_Sales"
|
|
it_admin = "GL_Users_IT Admin"
|
|
}
|
|
|
|
# Allowed countries
|
|
allowed_countries = ["FR", "DE", "US", "GB"]
|
|
blocked_countries = ["CN", "RU", "AF", "BY", "CD", "CU", "IR", "IQ", "KP", "MM", "SD", "SY", "UA", "ZW"]
|
|
|
|
main_countries = ["FR"]
|
|
europe_countries = ["AL", "AD", "AT", "AX", "BA", "BE", "BG", "BY", "CH", "CY", "CZ", "DE", "DK", "EE", "ES", "FI", "FR", "FO", "GB", "GG", "GI", "GR", "HR", "HU", "IE", "IM", "IS", "IT", "JE", "LI", "LT", "LU", "LV", "MC", "MD", "ME", "MK", "MT", "NL", "NO", "PL", "PT", "RO", "RS", "SE", "SI", "SK", "SM", "UA", "VA"]
|
|
afrique_countries = ["AO", "BF", "BI", "BJ", "BW", "CD", "CF", "CG", "CI", "CM", "CV", "DJ", "DZ", "EG", "EH", "ER", "ET", "GA", "GH", "GM", "GN", "GQ", "GW", "KE", "KM", "LR", "LS", "LY", "MA", "MG", "ML", "MR", "MU", "MW", "MZ", "NA", "NE", "NG", "RE", "RW", "SC", "SD", "SH", "SL", "SN", "SO", "SS", "ST", "SZ", "TD", "TF", "TG", "TN", "TZ", "UG", "YT", "ZA", "ZM", "ZW"]
|
|
america_north_countries = ["CA", "US", "MX", "BM", "PM", "GL", "UM"]
|
|
america_central_countries = ["AG", "AI", "AW", "BB", "BZ", "CR", "CU", "DM", "DO", "GD", "GP", "GT", "HN", "HT", "JM", "KN", "KY", "LC", "MF", "MQ", "MS", "NI", "PA", "PR", "SV", "SX", "TC", "TT", "VC", "VG", "VI"]
|
|
america_south_countries = ["AR", "BO", "BR", "CL", "CO", "EC", "FK", "GF", "GY", "PE", "PY", "SR", "UY", "VE"]
|
|
asie_countries = ["AF", "AM", "AZ", "BD", "BH", "BN", "BT", "CN", "GE", "HK", "ID", "IL", "IN", "IQ", "IR", "JO", "JP", "KG", "KH", "KP", "KR", "KW", "KZ", "LA", "LB", "LK", "MM", "MN", "MO", "MY", "NP", "OM", "PH", "PK", "PS", "QA", "SA", "SG", "SY", "TH", "TJ", "TL", "TM", "TR", "TW", "UZ", "VN", "YE"]
|
|
oceanie_countries = ["AS", "AU", "CK", "FJ", "FM", "GU", "HM", "KI", "MH", "MP", "NC", "NF", "NR", "NU", "NZ", "PF", "PG", "PN", "PW", "SB", "TK", "TO", "TV", "UM", "VU", "WF", "WS"]
|
|
antarctique_countries = ["AQ", "BV"]
|
|
other_countries = ["IO", "GS"]
|
|
|
|
# On fusionne *toutes* les zones dans une seule liste
|
|
all_countries = flatten([
|
|
local.europe_countries,
|
|
local.afrique_countries,
|
|
local.america_north_countries,
|
|
local.america_central_countries,
|
|
local.america_south_countries,
|
|
local.asie_countries,
|
|
local.oceanie_countries,
|
|
local.antarctique_countries,
|
|
local.other_countries,
|
|
])
|
|
|
|
# On retire les pays "main"
|
|
blocked_countries_except_main = compact([
|
|
for code in local.all_countries :
|
|
(contains(local.main_countries, code) ? null : code)
|
|
])
|
|
|
|
# On retire les pays "europe"
|
|
blocked_countries_except_europe = compact([
|
|
for code in local.all_countries :
|
|
(contains(local.europe_countries, code) ? null : code)
|
|
])
|
|
|
|
# On retire les pays "afrique"
|
|
blocked_countries_except_afrique = compact([
|
|
for code in local.all_countries :
|
|
(contains(local.afrique_countries, code) ? null : code)
|
|
])
|
|
|
|
# On retire les pays "america_north"
|
|
blocked_countries_except_america_north = compact([
|
|
for code in local.all_countries :
|
|
(contains(local.america_north_countries, code) ? null : code)
|
|
])
|
|
|
|
# On retire les pays "america_central"
|
|
blocked_countries_except_america_central = compact([
|
|
for code in local.all_countries :
|
|
(contains(local.america_central_countries, code) ? null : code)
|
|
])
|
|
|
|
# On retire les pays "america_south"
|
|
blocked_countries_except_america_south = compact([
|
|
for code in local.all_countries :
|
|
(contains(local.america_south_countries, code) ? null : code)
|
|
])
|
|
|
|
# On retire les pays "asie"
|
|
blocked_countries_except_asie = compact([
|
|
for code in local.all_countries :
|
|
(contains(local.asie_countries, code) ? null : code)
|
|
])
|
|
|
|
# On retire les pays "oceanie"
|
|
blocked_countries_except_oceanie = compact([
|
|
for code in local.all_countries :
|
|
(contains(local.oceanie_countries, code) ? null : code)
|
|
])
|
|
|
|
# On retire les pays "antarctique"
|
|
blocked_countries_except_antarctique = compact([
|
|
for code in local.all_countries :
|
|
(contains(local.antarctique_countries, code) ? null : code)
|
|
])
|
|
|
|
# On retire les pays "other"
|
|
blocked_countries_except_other = compact([
|
|
for code in local.all_countries :
|
|
(contains(local.other_countries, code) ? null : code)
|
|
])
|
|
|
|
# OS posture checks
|
|
os_posture_checks = [
|
|
var.cloudflare_linux_posture_id,
|
|
var.cloudflare_macos_posture_id,
|
|
var.cloudflare_windows_posture_id
|
|
]
|
|
|
|
policy_groups = {
|
|
# Composite groups
|
|
employees = cloudflare_zero_trust_access_group.employees_rule_group.id
|
|
sales_team = cloudflare_zero_trust_access_group.sales_team_rule_group.id
|
|
admins = cloudflare_zero_trust_access_group.admins_rule_group.id
|
|
contractors = cloudflare_zero_trust_access_group.contractors_rule_group.id
|
|
|
|
# Individual SAML groups
|
|
infrastructure_admin = cloudflare_zero_trust_access_group.saml_groups["infrastructure_admin"].id
|
|
sales_engineering = cloudflare_zero_trust_access_group.saml_groups["sales_engineering"].id
|
|
sales = cloudflare_zero_trust_access_group.saml_groups["sales"].id
|
|
it_admin = cloudflare_zero_trust_access_group.saml_groups["it_admin"].id
|
|
}
|
|
|
|
# Common access policy configurations
|
|
access_policies = {
|
|
intranet_web_app = {
|
|
name = "Intranet App Policy"
|
|
include_groups = ["employees", "contractors"]
|
|
require_posture = true
|
|
require_mfa = false
|
|
purpose_justification = false
|
|
}
|
|
competition_web_app = {
|
|
name = "Competition App Policy"
|
|
include_groups = ["sales_team"]
|
|
require_posture = true
|
|
require_mfa = true
|
|
# IMPORTANT: Comment out the next 3 lines if you haven't deployed the "Training Compliance Gateway"
|
|
# Otherwise the Competition App won't work or show up in App Launcher
|
|
# Repository: https://github.com/macharpe/cloudflare-access-training-evaluator
|
|
require_external_evaluation = true
|
|
external_evaluation_url = "https://training-status.macharpe.com"
|
|
external_evaluation_keys_url = "https://training-status.macharpe.com/keys"
|
|
purpose_justification = true
|
|
purpose_justification_prompt = "Access justification required: Please provide your business reason for accessing this sensitive resource."
|
|
lifecycle_create_before_destroy = true
|
|
}
|
|
aws_employees_browser_rendering = {
|
|
name = "Employees AWS Database Policy"
|
|
include_groups = ["infrastructure_admin"]
|
|
require_posture = true
|
|
require_mfa = false
|
|
purpose_justification = true
|
|
purpose_justification_prompt = "Access justification required: Please provide your business reason for accessing this production system."
|
|
require_login_method = true
|
|
}
|
|
aws_contractors_browser_rendering = {
|
|
name = "Contractors AWS Database Policy"
|
|
include_groups = ["contractors"]
|
|
require_posture = true
|
|
require_mfa = false
|
|
require_country = true
|
|
purpose_justification = true
|
|
purpose_justification_prompt = "Access justification required: Please provide your business reason for accessing this production system."
|
|
}
|
|
gcp_employees_browser_rendering = {
|
|
name = "Employees GCP Database Policy"
|
|
include_groups = ["infrastructure_admin"]
|
|
require_posture = true
|
|
require_mfa = false
|
|
purpose_justification = true
|
|
purpose_justification_prompt = "Access justification required: Please provide your business reason for accessing this production system."
|
|
require_login_method = true
|
|
}
|
|
gcp_contractors_browser_rendering = {
|
|
name = "Contractors GCP Database Policy"
|
|
include_groups = ["contractors"]
|
|
require_posture = true
|
|
require_mfa = false
|
|
require_country = true
|
|
purpose_justification = true
|
|
purpose_justification_prompt = "Access justification required: Please provide your business reason for accessing this production system."
|
|
}
|
|
aws = {
|
|
name = "AWS Cloud Policy"
|
|
include_groups = ["sales_engineering"]
|
|
require_posture = true
|
|
require_mfa = true
|
|
}
|
|
gcp = {
|
|
name = "GCP Cloud Policy"
|
|
include_groups = ["sales_engineering"]
|
|
require_posture = true
|
|
require_mfa = true
|
|
}
|
|
okta = {
|
|
name = "Okta Cloud Policy"
|
|
include_groups = ["it_admin"]
|
|
require_posture = true
|
|
require_mfa = true
|
|
}
|
|
meraki = {
|
|
name = "Meraki Cloud Policy"
|
|
include_groups = ["it_admin"]
|
|
require_posture = true
|
|
require_mfa = true
|
|
}
|
|
domain_controller = {
|
|
name = "Domain Controller Policy"
|
|
include_groups = ["it_admin", "contractors"]
|
|
require_posture = true
|
|
require_mfa = true
|
|
require_country = true
|
|
purpose_justification = true
|
|
purpose_justification_prompt = "Access justification required: Please provide your business reason for accessing this sensitive resource."
|
|
}
|
|
}
|
|
}
|
|
|
|
#==================================================
|
|
# Default Rule Groups
|
|
#===================================================
|
|
resource "cloudflare_zero_trust_access_group" "default_groups" {
|
|
account_id = local.cloudflare_account_id
|
|
|
|
name = "default group"
|
|
zone_id = local.cloudflare_zone_id
|
|
is_default = true
|
|
|
|
include = [
|
|
{
|
|
email = {
|
|
email = "[email protected]"
|
|
}
|
|
}
|
|
]
|
|
}
|
|
|
|
# SAML Rule Groups
|
|
resource "cloudflare_zero_trust_access_group" "saml_groups" {
|
|
for_each = local.saml_groups
|
|
account_id = local.cloudflare_account_id
|
|
|
|
name = each.value
|
|
|
|
include = [{
|
|
saml = {
|
|
identity_provider_id = cloudflare_zero_trust_access_identity_provider.authentik_oidc.id
|
|
attribute_name = "groups"
|
|
attribute_value = each.value
|
|
}
|
|
}]
|
|
}
|
|
|
|
#==================================================
|
|
# Composite Rule Groups
|
|
#===================================================
|
|
resource "cloudflare_zero_trust_access_group" "employees_rule_group" {
|
|
account_id = local.cloudflare_account_id
|
|
|
|
name = "Employees"
|
|
|
|
include = [
|
|
for group_key in ["it_admin", "sales", "sales_engineering", "infrastructure_admin"] : {
|
|
group = {
|
|
id = cloudflare_zero_trust_access_group.saml_groups[group_key].id
|
|
}
|
|
}
|
|
]
|
|
}
|
|
|
|
resource "cloudflare_zero_trust_access_group" "sales_team_rule_group" {
|
|
account_id = local.cloudflare_account_id
|
|
|
|
name = "Sales Team"
|
|
include = [
|
|
for group_key in ["sales", "sales_engineering"] : {
|
|
group = {
|
|
id = cloudflare_zero_trust_access_group.saml_groups[group_key].id
|
|
}
|
|
}
|
|
]
|
|
}
|
|
|
|
resource "cloudflare_zero_trust_access_group" "admins_rule_group" {
|
|
account_id = local.cloudflare_account_id
|
|
|
|
name = "Administrators"
|
|
include = [
|
|
for group_key in ["it_admin", "infrastructure_admin"] : {
|
|
group = {
|
|
id = cloudflare_zero_trust_access_group.saml_groups[group_key].id
|
|
}
|
|
}
|
|
]
|
|
}
|
|
|
|
resource "cloudflare_zero_trust_access_group" "contractors_rule_group" {
|
|
account_id = local.cloudflare_account_id
|
|
|
|
name = "Contractors Extended"
|
|
include = [
|
|
{
|
|
group = {
|
|
id = cloudflare_zero_trust_access_group.saml_groups["contractors"].id
|
|
}
|
|
},
|
|
{
|
|
email_domain = {
|
|
domain = var.cloudflare_email_domain
|
|
}
|
|
}
|
|
]
|
|
}
|
|
|
|
# Geographic Rule Groups
|
|
resource "cloudflare_zero_trust_access_group" "country_requirements_rule_group" {
|
|
account_id = local.cloudflare_account_id
|
|
|
|
name = "GRP_Localisation_Country Requirements"
|
|
include = [
|
|
for country in local.allowed_countries : {
|
|
geo = {
|
|
country_code = country
|
|
}
|
|
}
|
|
]
|
|
exclude = [
|
|
for country in local.blocked_countries : {
|
|
geo = {
|
|
country_code = country
|
|
}
|
|
}
|
|
]
|
|
}
|
|
|
|
#
|
|
resource "cloudflare_zero_trust_access_group" "country_requirements_rule_group_main" {
|
|
account_id = local.cloudflare_account_id
|
|
|
|
name = "GRP_Localisation Country Requirements : Main"
|
|
include = [
|
|
for country in local.main_countries : {
|
|
geo = {
|
|
country_code = country
|
|
}
|
|
}
|
|
]
|
|
exclude = [
|
|
for country in local.blocked_countries_except_main : {
|
|
geo = {
|
|
country_code = country
|
|
}
|
|
}
|
|
]
|
|
}
|
|
|
|
#
|
|
resource "cloudflare_zero_trust_access_group" "country_requirements_rule_group_europe" {
|
|
account_id = local.cloudflare_account_id
|
|
|
|
name = "GRP_Localisation Country Requirements : Europe"
|
|
include = [
|
|
for country in local.europe_countries : {
|
|
geo = {
|
|
country_code = country
|
|
}
|
|
}
|
|
]
|
|
exclude = [
|
|
for country in local.blocked_countries_except_europe : {
|
|
geo = {
|
|
country_code = country
|
|
}
|
|
}
|
|
]
|
|
}
|
|
|
|
#
|
|
resource "cloudflare_zero_trust_access_group" "country_requirements_rule_group_afrique" {
|
|
account_id = local.cloudflare_account_id
|
|
|
|
name = "GRP_Localisation Country Requirements : Afrique"
|
|
include = [
|
|
for country in local.afrique_countries : {
|
|
geo = {
|
|
country_code = country
|
|
}
|
|
}
|
|
]
|
|
exclude = [
|
|
for country in local.blocked_countries_except_afrique : {
|
|
geo = {
|
|
country_code = country
|
|
}
|
|
}
|
|
]
|
|
}
|
|
|
|
#
|
|
resource "cloudflare_zero_trust_access_group" "country_requirements_rule_group_america_north" {
|
|
account_id = local.cloudflare_account_id
|
|
|
|
name = "GRP_Localisation Country Requirements : America North"
|
|
include = [
|
|
for country in local.america_north_countries : {
|
|
geo = {
|
|
country_code = country
|
|
}
|
|
}
|
|
]
|
|
exclude = [
|
|
for country in local.blocked_countries_except_america_north : {
|
|
geo = {
|
|
country_code = country
|
|
}
|
|
}
|
|
]
|
|
}
|
|
|
|
#
|
|
resource "cloudflare_zero_trust_access_group" "country_requirements_rule_group_america_central" {
|
|
account_id = local.cloudflare_account_id
|
|
|
|
name = "GRP_Localisation Country Requirements : America Central"
|
|
include = [
|
|
for country in local.america_central_countries : {
|
|
geo = {
|
|
country_code = country
|
|
}
|
|
}
|
|
]
|
|
exclude = [
|
|
for country in local.blocked_countries_except_america_central : {
|
|
geo = {
|
|
country_code = country
|
|
}
|
|
}
|
|
]
|
|
}
|
|
|
|
#
|
|
resource "cloudflare_zero_trust_access_group" "country_requirements_rule_group_america_south" {
|
|
account_id = local.cloudflare_account_id
|
|
|
|
name = "GRP_Localisation Country Requirements : America South"
|
|
include = [
|
|
for country in local.america_south_countries : {
|
|
geo = {
|
|
country_code = country
|
|
}
|
|
}
|
|
]
|
|
exclude = [
|
|
for country in local.blocked_countries_except_america_south : {
|
|
geo = {
|
|
country_code = country
|
|
}
|
|
}
|
|
]
|
|
}
|
|
|
|
#
|
|
resource "cloudflare_zero_trust_access_group" "country_requirements_rule_group_asie" {
|
|
account_id = local.cloudflare_account_id
|
|
|
|
name = "GRP_Localisation Country Requirements : Asie"
|
|
include = [
|
|
for country in local.asie_countries : {
|
|
geo = {
|
|
country_code = country
|
|
}
|
|
}
|
|
]
|
|
exclude = [
|
|
for country in local.blocked_countries_except_asie : {
|
|
geo = {
|
|
country_code = country
|
|
}
|
|
}
|
|
]
|
|
}
|
|
|
|
#
|
|
resource "cloudflare_zero_trust_access_group" "country_requirements_rule_group_oceanie" {
|
|
account_id = local.cloudflare_account_id
|
|
|
|
name = "GRP_Localisation Country Requirements : Oceanie"
|
|
include = [
|
|
for country in local.oceanie_countries : {
|
|
geo = {
|
|
country_code = country
|
|
}
|
|
}
|
|
]
|
|
exclude = [
|
|
for country in local.blocked_countries_except_oceanie : {
|
|
geo = {
|
|
country_code = country
|
|
}
|
|
}
|
|
]
|
|
}
|
|
|
|
#
|
|
resource "cloudflare_zero_trust_access_group" "country_requirements_rule_group_antarctique" {
|
|
account_id = local.cloudflare_account_id
|
|
|
|
name = "GRP_Localisation Country Requirements : Antarctique"
|
|
include = [
|
|
for country in local.antarctique_countries : {
|
|
geo = {
|
|
country_code = country
|
|
}
|
|
}
|
|
]
|
|
exclude = [
|
|
for country in local.blocked_countries_except_antarctique : {
|
|
geo = {
|
|
country_code = country
|
|
}
|
|
}
|
|
]
|
|
}
|
|
|
|
#
|
|
resource "cloudflare_zero_trust_access_group" "country_requirements_rule_group_other" {
|
|
account_id = local.cloudflare_account_id
|
|
|
|
name = "GRP_Localisation Country Requirements : other"
|
|
include = [
|
|
for country in local.other_countries : {
|
|
geo = {
|
|
country_code = country
|
|
}
|
|
}
|
|
]
|
|
exclude = [
|
|
for country in local.blocked_countries_except_other : {
|
|
geo = {
|
|
country_code = country
|
|
}
|
|
}
|
|
]
|
|
}
|
|
|
|
# Device Posture Rule Groups
|
|
resource "cloudflare_zero_trust_access_group" "latest_os_version_requirements_rule_group" {
|
|
account_id = local.cloudflare_account_id
|
|
name = "GL_OS Version Requirements"
|
|
|
|
include = [
|
|
for posture_id in local.os_posture_checks : {
|
|
device_posture = {
|
|
integration_uid = posture_id
|
|
}
|
|
}
|
|
]
|
|
}
|
|
|
|
#==========================================================
|
|
# Access Policies
|
|
#==========================================================
|
|
|
|
resource "cloudflare_zero_trust_access_policy" "policies" {
|
|
for_each = local.access_policies
|
|
|
|
account_id = local.cloudflare_account_id
|
|
|
|
decision = "allow"
|
|
name = each.value.name
|
|
session_duration = "0s"
|
|
|
|
# Purpose justification
|
|
purpose_justification_prompt = try(each.value.purpose_justification_prompt, null)
|
|
purpose_justification_required = try(each.value.purpose_justification, false)
|
|
|
|
# Include groups
|
|
include = concat(
|
|
# Groups (both SAML and composite groups via mapping)
|
|
[
|
|
for group in each.value.include_groups : {
|
|
group = {
|
|
id = local.policy_groups[group]
|
|
}
|
|
}
|
|
],
|
|
# Email domain (for contractors)
|
|
try(each.value.include_email_domain, false) ? [{
|
|
email_domain = {
|
|
domain = var.cloudflare_email_domain
|
|
}
|
|
}] : []
|
|
)
|
|
|
|
# Require conditions
|
|
require = concat(
|
|
# Device posture (always required if specified)
|
|
try(each.value.require_posture, false) ? [{
|
|
device_posture = {
|
|
integration_uid = var.cloudflare_gateway_posture_id
|
|
}
|
|
}] : [],
|
|
# MFA requirement
|
|
try(each.value.require_mfa, false) ? [{
|
|
auth_method = {
|
|
auth_method = "mfa"
|
|
}
|
|
}] : [],
|
|
# Login method (for specific policies)
|
|
try(each.value.require_login_method, false) ? [{
|
|
login_method = {
|
|
id = cloudflare_zero_trust_access_identity_provider.authentik_oidc.id
|
|
}
|
|
}] : [],
|
|
# Country requirements
|
|
try(each.value.require_country, false) ? [{
|
|
group = {
|
|
id = cloudflare_zero_trust_access_group.country_requirements_rule_group.id
|
|
}
|
|
}] : [],
|
|
# OS version requirements
|
|
try(each.value.require_os_version, false) ? [{
|
|
group = {
|
|
id = cloudflare_zero_trust_access_group.latest_os_version_requirements_rule_group.id
|
|
}
|
|
}] : [],
|
|
# External evaluation requirements
|
|
try(each.value.require_external_evaluation, false) ? [{
|
|
external_evaluation = {
|
|
evaluate_url = each.value.external_evaluation_url
|
|
keys_url = each.value.external_evaluation_keys_url
|
|
}
|
|
}] : []
|
|
)
|
|
|
|
# Exclude SMS (for MFA policies)
|
|
exclude = try(each.value.require_mfa, false) ? [{
|
|
auth_method = {
|
|
auth_method = "sms"
|
|
}
|
|
}] : []
|
|
|
|
# Explicit dependencies to ensure proper destruction order:
|
|
# Policies → Composite Groups → Individual SAML Groups
|
|
depends_on = [
|
|
cloudflare_zero_trust_access_group.employees_rule_group,
|
|
cloudflare_zero_trust_access_group.sales_team_rule_group,
|
|
cloudflare_zero_trust_access_group.admins_rule_group,
|
|
cloudflare_zero_trust_access_group.contractors_rule_group,
|
|
cloudflare_zero_trust_access_group.saml_groups
|
|
]
|
|
|
|
# Note: lifecycle blocks cannot be conditional in for_each resources
|
|
} |