INTEGRITY Документация

Рекомендации

Хотя каждое развёртывание Terraform уникально, следуйте этим рекомендациям, чтобы добиться успешного результата.

Управление ресурсами через Terraform

Terraform работает наиболее эффективно, когда он управляет всеми изменениями и жизненным циклом ресурса.

После любой операции с конфигурацией Terraform пытается устранить расхождения, синхронизируя удалённое состояние с локальным. Если между локальным и удалённым состоянием есть различия (например, из-за управления ресурсами вне Terraform), может потребоваться удалить и заново создать ресурс в файле состояния (обычно через импорт), поскольку не все ресурсы поддерживают обновление на месте.

Структура каталогов

Cloudflare рекомендует использовать структуру каталогов, основанную на сочетании аккаунтов, зон и продуктов, чтобы изолировать изменения. Такой подход позволяет назначать ответственных с высокой точностью и ограничивать операции Terraform конкретным продуктом в пределах зоны. Кроме того, он точнее соответствует роли по умолчанию, а также дополнительные инструменты, такие как хранилище AWS или GCP, настроив права доступа для отдельных файлов состояния.

Для продуктов с широким набором функций, таких как Rulesets, можно пойти ещё дальше, разделив их на уровне фаз (WAF, правила перенаправления, правила источника).

example-tf/
├── demo_account_a                  # per account segregation of resources
│   ├── users                       # top level directory for account members as they are "zoneless"
│   │   ├── provider.tf             # `provider.tf` is for configuring the providers
│   │   ├── users.tf                # `<subject>.tf` (users.tf) is for managing the individual resources
│   │   └── vars.tf                 # manage all variables for this component
│   ├── zone_a                      # group all zone based features together
│   │   ├── dns                     # individual (or grouped, your choice) of products or features to manage together
│   │   │   ├── dns.tf              # `<subject>.tf` (dns.tf) is for managing the individual resources
│   │   │   ├── provider.tf         # `provider.tf` is for configuring the providers
│   │   │   └── vars.tf             # manage all variables for this component
│   │   └── page_rules              # ... same as above but for Page Rules
│   │       ├── page_rules.tf
│   │       ├── provider.tf
│   │       └── vars.tf
│   ├── zone_b
│   │   ├── dns
│   │   │   ├── dns.tf
│   │   │   ├── provider.tf
│   │   │   └── vars.tf
│   │   └── page_rules
│   │       ├── page_rules.tf
│   │       ├── provider.tf
│   │       └── vars.tf
│   └── zone_c
│       ├── dns
│       │   ├── dns.tf
│       │   ├── provider.tf
│       │   └── vars.tf
│       └── page_rules
│           ├── page_rules.tf
│           ├── provider.tf
│           └── vars.tf
└── demo_account_b
    ├── users
    │   ├── provider.tf
    │   ├── users.tf
    │   └── vars.tf
    ├── zone_a
    │   ├── dns
    │   │   ├── dns.tf
    │   │   ├── provider.tf
    │   │   └── vars.tf
    │   └── page_rules
    │       ├── page_rules.tf
    │       ├── provider.tf
    │       └── vars.tf
    ├── zone_b
    │   ├── dns
    │   │   ├── dns.tf
    │   │   ├── provider.tf
    │   │   └── vars.tf
    │   └── page_rules
    │       ├── page_rules.tf
    │       ├── provider.tf
    │       └── vars.tf
    └── zone_c
        ├── dns
        │   ├── dns.tf
        │   ├── provider.tf
        │   └── vars.tf
        └── page_rules
            ├── page_rules.tf
            ├── provider.tf
            └── vars.tf

Избегайте модулей (или используйте их по минимуму)

Модули Terraform позволяют инкапсулировать несколько ресурсов с логикой в абстрактном интерфейсе. Рассмотрим пример, когда модуль настраивает балансировщик нагрузки по умолчанию с пулом, несколькими записями DNS и, возможно, правилом Page Rules. Конечный пользователь может использовать его следующим образом:

module "example" "an_example_site" {
  domain = "example.com"
  origin_ip = "192.168.0.1"
}

Однако с точки зрения ресурсов Terraform приведённый выше пример будет выглядеть следующим образом:

resource "cloudflare_record" "example_1" {
  zone_id = var.cloudflare_zone_id
  name    = "terraform"
  value   = "198.51.100.11"
  type    = "A"
  ttl     = 3600
}

resource "cloudflare_record" "example_2" {
  zone_id = var.cloudflare_zone_id
  name    = "terraform"
  value   = "198.51.100.12"
  type    = "A"
  ttl     = 3600
}

resource "cloudflare_record" "example_3" {
  zone_id = var.cloudflare_zone_id
  name    = "terraform"
  value   = "198.51.100.13"
  type    = "A"
  ttl     = 3600
}

resource "cloudflare_load_balancer" "bar" {
  zone_id          = var.cloudflare_zone_id
  name             = "example-load-balancer.example.com"
  fallback_pool_id = cloudflare_load_balancer_pool.foo.id
  default_pool_ids = [cloudflare_load_balancer_pool.foo.id]
  description      = "example load balancer using geo-balancing"
  proxied          = true
  steering_policy  = "geo"

  pop_pools {
    pop      = "LAX"
    pool_ids = [cloudflare_load_balancer_pool.foo.id]
  }

  country_pools {
    country  = "US"
    pool_ids = [cloudflare_load_balancer_pool.foo.id]
  }

  region_pools {
    region   = "WNAM"
    pool_ids = [cloudflare_load_balancer_pool.foo.id]
  }

  rules {
    name      = "example rule"
    condition = "http.request.uri.path contains \"testing\""
    fixed_response {
      message_body = "hello"
      status_code  = 200
      content_type = "html"
      location     = "www.example.com"
    }
  }
}

resource "cloudflare_load_balancer_pool" "example_lb_pool" {
  name = "example-lb-pool"
  origins {
    name    = "example-1"
    address = "198.51.100.1"
    enabled = true
  }
}

resource "cloudflare_page_rule" "example_page_rule" {
  zone_id = var.cloudflare_zone_id
  target = "sub.${var.cloudflare_zone}/page"
  priority = 1

  actions {
    ssl = "flexible"
    email_obfuscation = "on"
  }
}

Такая настройка удобна, но может привести к непредвиденным проблемам. Если этот модуль используется совместно и в нём происходят внутренние изменения, ресурсы модуля могут рассинхронизироваться или пересоздаться.

Использование модулей также усложняет отладку и воспроизведение проблем, поскольку приходится учитывать возможные логические ошибки за пределами ядра Terraform и провайдера Cloudflare.

Перенесите ресурсы в Terraform

Cloudflare рекомендует использовать cf-terraforming , чтобы перенести существующие ресурсы в Cloudflare.

Управление частью ресурсов вне Terraform

Вполне допустимо управлять одними ресурсами через Terraform, а другими с помощью иного инструмента, но убедитесь, что вы не выполнение обоих действий для одного и того же ресурса.

Используйте отдельные окружения

Чтобы безопасно управлять отдельными средами (staging, QA, UAT, production), используйте отдельные аккаунты Cloudflare с отдельными доменами (например, example.com и example-staging.com).

Это связано с тем, что некоторые продукты, определённые на уровне аккаунта, являются общими (например, мониторы и пулы Load Balancer), и вы не можете внести изолированное изменение в них, если они находятся в одном аккаунте. Использование отдельных аккаунтов также полезно, если вы планируете тестировать такие функции, как DNSSEC, которые при неправильной настройке могут повлиять на весь домен.

Чтобы свести к минимуму расхождения, используйте Terraform и CI/CD-конвейер, который выполняется для обоих доменов и поддерживает их синхронизацию по мере необходимости.

Храните учётные данные в безопасности

Мы не рекомендуем хранить учётные данные Cloudflare в незашифрованном виде.

Локально можно использовать сторонний инструмент, например cf-vault ↗ для хранения учетных данных Cloudflare.

Для CI-конвейеров используйте внутренний инструмент или хранилище секретов (например, Vault ↗).