Spec-Zone.ru › OpenTofu 1.9

Шифрование состояния и плана

OpenTofu поддерживает шифрование файлов состояния и плана при хранении — как локально, так и при использовании бэкенда. Кроме того, шифрование можно использовать с источником данных terraform_remote_state. На этой странице объясняется, как настроить шифрование и какой метод подходит для каждого сценария использования.

Общие рекомендации и возможные проблемы (обязательно прочитайте)​

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

От чего защищает шифрование?​

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

Однако шифрование не защищает от потери данных (повреждения файла состояния) и не защищает от атаки повторного воспроизведения (когда злоумышленник использует более старый файл состояния или плана и обманом заставляет вас запустить его). Кроме того, OpenTofu не защищает и не может защитить конфиденциальные значения в файле состояния от человека, запускающего команду tofu.

Какие меры предосторожности необходимо принять?​

При включении шифрования подумайте, кому нужен непосредственный доступ к файлу состояния. Если доступ нужен более чем небольшому числу людей, рассмотрите возможность запуска рабочих процессов plan и apply для производственной среды из системы непрерывной интеграции, чтобы защитить и ключ шифрования, и конфиденциальные значения в состоянии.

Также необходимо выбрать тип ключа с учётом требований безопасности. Можно использовать статическую парольную фразу или систему управления ключами. Если вы выбрали систему управления ключами, для некоторых методов шифрования крайне важно настроить автоматическую ротацию ключей. Это особенно важно, если выбранный алгоритм шифрования может достичь состояния «насыщения ключа», когда приближается максимальный безопасный предел использования ключа, например AES-GCM. Дополнительную информацию см. в разделе методы шифрования ниже.

Наконец, прежде чем включать шифрование, проверьте план аварийного восстановления и создайте временную резервную копию незашифрованного файла состояния. Также убедитесь, что у вас есть резервные копии ключей. После включения шифрования OpenTofu не сможет прочитать файл состояния без правильного ключа.

Переход с незашифрованного состояния/плана​

Если у вас уже есть файл состояния и вы хотите включить шифрование, одного включения шифрования недостаточно: OpenTofu откажется читать обычный текст. Это защитный механизм, который не позволяет OpenTofu читать изменённые незашифрованные данные. Подробные инструкции по миграции см. в разделе первоначальная настройка ниже.

Гарантия совместимости​

Исследования в области криптографии могут быстро менять современный уровень развития технологий. Мы будем поддерживать все документированные поставщики ключей и методы в течение +1 минорной версии, но в любой минорной версии можем добавлять новые версии тех же поставщиков ключей и методов (например, aes_gcm_v2) или новые поставщики ключей и методы. Если мы объявим поставщика ключей или метод устаревшим, при запуске tofu plan или tofu apply в консоли появится предупреждение. Если вы получили такое предупреждение, выполните переход до обновления до следующей версии.

Конфигурация​

Настроить шифрование в OpenTofu можно, указав конфигурацию в коде OpenTofu или используя переменную окружения TF_ENCRYPTION. Оба варианта равнозначны. Если использовать оба, OpenTofu объединит конфигурации, переопределив все параметры, заданные в коде, значениями из окружения.

Базовая структура конфигурации выглядит следующим образом:

  • Код
  • Окружение (оболочка Linux/UNIX)
  • Окружение (PowerShell)
Блок кода
terraform {
  encryption {
    key_provider "some_key_provider" "some_name" {
      # Key provider options here
    }

    method "some_method" "some_method_name" {
      # Method options here
      keys = key_provider.some_key_provider.some_name
    }

    state {
      # Encryption/decryption for state data
      method = method.some_method.some_method_name
    }

    plan {
      # Encryption/decryption for plan data
      method = method.some_method.some_method_name
    }

    remote_state_data_sources {
      # See below
    }
  }
}
Блок кода
TF_ENCRYPTION=$(cat <<EOF
key_provider "some_key_provider" "some_name" {
  # Key provider options here
}

method "some_method" "some_method_name" {
  # Method options here
  keys = key_provider.some_key_provider.some_name
}

state {
  # Encryption/decryption for state data
  method = method.some_method.some_method_name
}

plan {
  # Encryption/decryption for plan data
  method = method.some_method.some_method_name
}

remote_state_data_sources {
  # See below
}
EOF)
Блок кода
$Env:TF_ENCRYPTION = @"
key_provider "some_key_provider" "some_name" {
  # Key provider options here
}

method "some_method" "some_method_name" {
  # Method options here
  keys = key_provider.some_key_provider.some_name
}

state {
  # Encryption/decryption for state data
  method = method.some_method.some_method_name
}

plan {
  # Encryption/decryption for plan data
  method = method.some_method.some_method_name
}

remote_state_data_sources {
  # See below
}
"@
Предупреждение

После шифрования данных не переименовывайте поставщиков ключей и методы в конфигурации! Зашифрованные данные, хранящиеся в бэкенде, содержат метаданные с их именами. Вместо этого используйте блок резервного варианта для обработки изменений поставщиков ключей. Можно также указать уникальный ключ хранения метаданных в поле encrypted_metadata_alias поставщика ключей — это позволит без проблем изменить имя поставщика ключей.

Примечание

Вместо HCL для конфигурации шифрования можно использовать синтаксис конфигурации JSON.

Примечание

Если вы используете конфигурацию окружения, добавьте следующую конфигурацию кода, чтобы не допустить записи незашифрованных данных при отсутствии переменной окружения:

Блок кода
terraform {
    encryption {
        state {
            enforced = true
        }
        plan {
            enforced = true
        }
    }
}

Смена ключа и метода​

В некоторых случаях может потребоваться изменить конфигурацию шифрования. Это может включать переименование поставщика ключей или метода, изменение парольной фразы поставщика ключей либо переход на другую систему управления ключами. OpenTofu поддерживает автоматическую смену конфигурации шифрования, если указать старую конфигурацию в блоке fallback:

Блок кода
terraform {
  encryption {
    # Methods and key providers here.

    state {
      method = method.some_method.new_method
      fallback {
        method = method.some_method.old_method
      }
    }

    plan {
      method = method.some_method.new_method
      fallback {
        method = method.some_method.old_method
      }
    }
  }
}

Если OpenTofu не удастся прочитать файл состояния или плана с помощью нового метода, он автоматически попробует резервный метод. При сохранении файла состояния или плана OpenTofu всегда будет использовать новый метод, а не резервный.

Первоначальная настройка​

Новый проект​

Если вы настраиваете новый проект и у вас ещё нет файла состояния, начните с этой конфигурации шифрования на основе парольной фразы:

Блок кода
variable "passphrase" {
  # Change passphrase to be at least 16 characters long:
  default = "changeme!"
}

terraform {
  encryption {
    ## Step 1: Add the desired key provider:
    key_provider "pbkdf2" "mykey" {
      passphrase = var.passphrase
    }
    ## Step 2: Set up your encryption method:
    method "aes_gcm" "new_method" {
      keys = key_provider.pbkdf2.mykey
    }

    state {
      ## Step 3: Link the desired encryption method:
      method = method.aes_gcm.new_method

      ## Step 4: Run "tofu apply".

      ## Step 5: Consider adding the "enforced" option:
      # enforced = true
    }

    ## Step 6: Repeat steps 3-5 for plan{} if needed.
  }
}

Существующий проект​

При первой настройке шифрования в существующем проекте файлы состояния и плана не зашифрованы. По умолчанию OpenTofu отказывается читать их, поскольку они могли быть изменены. Чтобы разрешить чтение незашифрованных данных, необходимо указать метод unencrypted:

Блок кода
variable "passphrase" {
  # Change passphrase to be at least 16 characters long:
  default = "changeme!"
}

terraform {
  encryption {
    ## Step 1: Add the unencrypted method:
    method "unencrypted" "migrate" {}

    ## Step 2: Add the desired key provider:
    key_provider "pbkdf2" "mykey" {
      passphrase = var.passphrase
    }

    ## Step 3: Add the desired encryption method:
    method "aes_gcm" "new_method" {
      keys = key_provider.pbkdf2.mykey
    }

    state {
      ## Step 4: Link the desired encryption method:
      method = method.aes_gcm.new_method

      ## Step 5: Add the "fallback" block referencing the
      ## "unencrypted" method.
      fallback {
        method = method.unencrypted.migrate
      }

      ## Step 6: Run "tofu apply".

      ## Step 7: Remove the "fallback" block above and
      ## consider adding the "enforced" option:
      # enforced = true
    }

    ## Step 8: Repeat steps 4-8 for plan{} if needed.
  }
}
Примечание

В конфигурации можно использовать переменные и локальные значения, но они не должны ссылаться на данные состояния или функции, определённые поставщиком. Все значения должны разрешаться во время tofu init, до того как состояние станет доступно.

Отмена шифрования​

Как и при первоначальной настройке выше, перейти к незашифрованным файлам состояния и плана также можно с помощью метода unencrypted:

Блок кода
terraform {
  encryption {
    ## Step 1: Leave the original encryption method unchanged:
    method "some_method" "old_method" {
      ## Parameters for the old method here.
    }

    # Step 2: Add the unencrypted method here:
    method "unencrypted" "migrate" {}

    state {
      ## Step 3: Disable or remove the "enforced" option:
      enforced = false

      ## Step 4: Move the original encryption method into the "fallback" block:
      fallback {
        method = method.some_method.old_method
      }

      ## Step 5: Reference the unencrypted method as your primary "encryption" method.
      method = method.unencrypted.migrate
    }

    ## Step 6: Run "tofu apply".

    ## Step 7: Remove the "state" block once the migration is complete.

    ## Step 8: Repeat steps 3-7 for plan{} if needed.
  }
}
Предупреждение

Не удаляйте и не изменяйте исходный метод шифрования, пока не завершите миграцию.

Источники данных удалённого состояния​

Можно также настроить шифрование для проектов, использующих источник данных terraform_remote_state. Для этого можно использовать ту же конфигурацию шифрования, что и в основной конфигурации, либо определить отдельный набор ключей и методов. Синтаксис конфигурации:

Блок кода
terraform {
  encryption {
    # Key provider and method configuration here

    remote_state_data_sources {
      default {
        method = method.my_method.my_name
      }
      remote_state_data_source "my_state" {
        method = method.my_method.my_other_name
      }
    }
  }
}

data "terraform_remote_state" "my_state" {
  # ...
}

Для отдельных удалённых состояний можно использовать следующий синтаксис:

  • myname для выбора источника данных в основном проекте с указанным именем.
  • mymodule.myname для выбора источника данных в указанном модуле с указанным именем.
  • mymodule.myname[0] для выбора первого источника данных в указанном модуле с указанным именем.

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

Например, вы можете создавать сертификаты в проекте «A» и ссылаться на них в проекте «B». В проекте «A» можно настроить следующее:

Блок кода
terraform {
  encryption {
    key_provider "pbkdf2" "mykey" {
      passphrase               = "OpenTofu has encryption"
      # Note the fixed encrypted_metadata_alias here:
      encrypted_metadata_alias = "certificates"
    }
    method "aes_gcm" "mymethod" {
      keys = key_provider.pbkdf2.mykey
    }
    state {
      method = method.aes_gcm.mymethod
    }
  }
}

resource "tls_private_key" "webserver" {
  algorithm   = "ED25519"
}

resource "tls_self_signed_cert" "webserver" {
  private_key_pem = tls_private_key.webserver.private_key_pem

  subject {
    common_name  = "someserver.opentofu.org"
    organization = "OpenTofu"
  }

  validity_period_hours = 24*365*10

  allowed_uses = [
    "key_encipherment",
    "digital_signature",
    "server_auth",
  ]
}

output "cert_pem" {
  value = tls_self_signed_cert.webserver.cert_pem
}

Затем на него можно сослаться в проекте «B» следующим образом:

Блок кода
terraform {
  encryption {
    # Note that the name of the key here is different:
    key_provider "pbkdf2" "mykeyrenamed" {
      passphrase               = "OpenTofu has encryption"
      # Note the fixed encrypted_metadata_alias here:
      encrypted_metadata_alias = "certificates"
    }
    method "aes_gcm" "mymethod" {
      keys = key_provider.pbkdf2.mykeyrenamed
    }
    remote_state_data_sources {
      default {
        method = method.aes_gcm.mymethod
      }
    }
  }
}


data "terraform_remote_state" "cert" {
  backend = "local"
  config = {
    # Refer to the other project here:
    path = "../a/terraform.tfstate"
  }
}

output "cert" {
  # Use data from the other project by referencing it as follows:
  value = data.terraform_remote_state.cert.outputs.cert_pem
}

Поставщики ключей​

PBKDF2​

Поставщик ключей PBKDF2 позволяет использовать длинную парольную фразу для создания ключа для такого метода шифрования, как AES-GCM. Его можно настроить следующим образом:

Блок кода
terraform {
  encryption {
    key_provider "pbkdf2" "foo" {
      # Specify a long / complex passphrase (min. 16 characters)
      passphrase = "correct-horse-battery-staple"

      # Adjust the key length to the encryption method (default: 32)
      key_length = 32

      # Specify the number of iterations (min. 200.000, default: 600.000)
      iterations = 600000

      # Specify the salt length in bytes (default: 32)
      salt_length = 32

      # Specify the hash function (sha256 or sha512, default: sha512)
      hash_function = "sha512"
    }
  }
}
Параметр Описание Мин. По умолчанию
passphrase (обязательный) Введите длинную и сложную парольную фразу. 16 символов -
key_length Количество байтов для создания ключа. 1 32
iterations Количество итераций. Рекомендации см. в этом документе. 200 000 600 000
salt_length Длина соли для получения ключа. 1 32
hash_function Укажите sha256 или sha512 в качестве хеш-функции. sha1 не поддерживается. Н/Д sha512
encrypted_metadata_alias Необязательный идентификатор, под которым хранятся метаданные в зашифрованных файлах состояния/плана. Укажите его, чтобы разрешить изменение имени поставщика ключей. - производное от имени поставщика ключей

AWS KMS​

Этот поставщик ключей использует службу управления ключами Amazon Web Services для создания ключей. Параметры аутентификации совпадают с параметрами бэкенда S3, за исключением устаревших параметров. Кроме того, укажите следующие параметры:

Параметр Описание Мин. По умолчанию
kms_key_id Идентификатор ключа для AWS KMS. 1 -
key_spec Спецификация ключа для AWS KMS. Выберите её в соответствии с методом шифрования (например, AES_256). 1 -
encrypted_metadata_alias Необязательный идентификатор, под которым хранятся метаданные в зашифрованных файлах состояния/плана. Укажите его, чтобы разрешить изменение имени поставщика ключей. - производное от имени поставщика ключей

В следующем примере показана минимальная конфигурация:

Блок кода
terraform {
  encryption {
    key_provider "aws_kms" "basic" {
      kms_key_id = "a4f791e1-0d46-4c8e-b489-917e0bec05ef"
      region = "us-east-1"
      key_spec = "AES_256"
    }
  }
}

GCP KMS​

Этот поставщик ключей использует службу управления ключами Google Cloud для создания ключей. Параметры аутентификации совпадают с параметрами бэкенда GCS, за исключением устаревших параметров. Кроме того, укажите следующие параметры:

Параметр Описание Мин. По умолчанию
kms_encryption_key (обязательный) Идентификатор ключа для GCP KMS. Н/Д -
key_length (обязательный) Количество байтов для создания ключа. Должно быть в диапазоне от 1 до 1024 байт. 1 -
encrypted_metadata_alias Необязательный идентификатор, под которым хранятся метаданные в зашифрованных файлах состояния/плана. Укажите его, чтобы разрешить изменение имени поставщика ключей. - производное от имени поставщика ключей

В следующем примере показана минимальная конфигурация:

Блок кода
terraform {
  encryption {
    key_provider "gcp_kms" "basic" {
      kms_encryption_key = "projects/local-vehicle-id/locations/global/keyRings/ringid/cryptoKeys/keyid"
      key_length = 32
    }
  }
}

OpenBao (экспериментальная функция)​

Этот поставщик ключей использует модуль секретов OpenBao Transit для создания ключей данных. Его можно настроить следующим образом:

Параметр Описание Мин. По умолчанию
key_name (обязательный) Имя ключа шифрования Transit, используемого для шифрования/расшифровки ключа данных. Предварительно настройте его на сервере OpenBao. Н/Д -
token Токен авторизации, используемый при обращении к API OpenBao. OpenTofu также может считывать его из переменной окружения BAO_TOKEN. Н/Д -
address Адрес сервера OpenBao для доступа к API. OpenTofu также может считывать его из переменной окружения BAO_ADDR. Ваша система должна доверять TLS-сертификату сервера. Н/Д https://127.0.0.1:8200
transit_engine_path Путь, по которому в OpenBao включён модуль секретов Transit. Измените этот параметр, если вы изменили путь к модулю Transit. Н/Д /transit
key_length Количество байтов для создания ключа. Допустимые значения: 16, 32 или 64 байт. 16 32
encrypted_metadata_alias Необязательный идентификатор, под которым хранятся метаданные в зашифрованных файлах состояния/плана. Укажите его, чтобы разрешить изменение имени поставщика ключей. - производное от имени поставщика ключей

В следующем примере показан возможный вариант конфигурации:

Блок кода
terraform {
  encryption {
    key_provider "openbao" "my_bao" {
      
      # Required. Name of the transit encryption key
      # to use to encrypt/decrypt the data key.
      key_name = "test-key"
      
      # Optional. Authorization Token to use when accessing OpenBao API.
      # You can also set this in the BAO_TOKEN environment variable.
      token = "s.Fg8wA4nDrP08TirpjEXkrTmt"

      # Optional. OpenBao server address to access the API on.
      # You can also set this using the BAO_ADDR environment variable.
      address = "http://127.0.0.1:8200"

      # Optional. You can customize this if you mounted the
      # transit engine on a different path. Default: /transit
      transit_engine_path = "/my-org/transit"

      # Optional. Number of bytes to generate as a key. Default: 32
      key_length = 16
    }
  }
}
Предупреждение

Поставщик ключей OpenBao пока является экспериментальным, поскольку на момент выпуска OpenTofu стабильная версия OpenBao отсутствовала.

Примечание

Поставщик ключей OpenBao совместим с последней версией HashiCorp Vault с лицензией MPL (1.14), но не поддерживает последующие версии с лицензией BUSL.

Методы​

AES-GCM​

В настоящее время поддерживается только метод шифрования AES-GCM. Его можно настроить следующим образом:

Блок кода
terraform {
  encryption {
    # Key provider configuration here

    method "aes_gcm" "yourname" {
      keys = key_provider.yourkeyprovider.yourname
    }
  }
}
Примечание

Для метода AES-GCM нужны ключи длиной 16, 24 или 32 байта. Настройте поставщик ключей так, чтобы он предоставлял ключи именно такой длины.

Предупреждение

AES-GCM — это безопасный отраслевой стандарт шифрования, однако он подвержен «насыщению ключа». Для настройки безопасной системы следует использовать либо поставщик ключей, выполняющий выработку ключа (например, PBKDF2) с длинной и сложной парольной фразой, либо систему управления ключами, которая регулярно выполняет автоматическую ротацию ключей. Использование коротких статических ключей снижает надёжность шифрования.

Без шифрования​

Метод unencrypted используется для явного перехода к шифрованию и обратно. Он не требует настройки; пример его использования приведён выше в блоке «Первоначальная настройка».

Copyright (c) The OpenTofu Authors
Copyright (c) 2014 HashiCorp, Inc.
Mozilla Public License, version 2.0
https://opentofu.org/docs/v1.9/language/state/encryption/

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API