Spec-Zone.ru › OpenTofu 1.12

Эфемерность

Эфемерность — это свойство значения быть «эфемерным», то есть не сохраняться в состоянии или плане. Благодаря этой концепции в OpenTofu можно безопасно обрабатывать временную и/или конфиденциальную информацию.

Связанные концепции:

  • Конфиденциальные поля ресурсов, выходные значения и переменные
    • Пометка значений как конфиденциальных гарантирует, что их содержимое будет скрыто в пользовательском интерфейсе.
    • Конфиденциальные значения по-прежнему будут храниться в открытом виде в состоянии и плане.
  • Шифрование состояния
    • Можно настроить шифрование данных состояния и плана, чтобы предотвратить несанкционированный доступ к ним и их изменение.
    • Безопасность этих данных зависит от используемых методов шифрования и доступа к ключам шифрования.

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

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

В рамках этой концепции можно использовать следующие конструкции:

  • Эфемерные ресурсы
  • Эфемерные переменные
  • Эфемерные выходные значения
  • Локальные значения
  • Провайдеры
  • Провижионеры
  • Блоки ресурсов connection
  • Атрибуты ресурсов write-only

Совместимость​

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

Эта концепция вдохновлена аналогичной концепцией «Ephemeral» в Terraform v1.12 и нацелена на совместимость с ней. Если обнаружатся несовместимости, команда OpenTofu рассмотрит возможность внесения обратно несовместимых изменений в последующие версии OpenTofu, чтобы обеспечить совместимость.

Дополнительные темы​

  • Передача значений эфемерным переменным корневого модуля
  • Взаимодействие проверок с эфемерными значениями
  • Очистка значений с помощью ephemeralasnull()
  • Различение plan/apply с помощью tofu.applying
  • Обработка атрибутов только для записи при генерации конфигурации

Пример использования​

Примечание

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

Модуль для работы с различными сценариями использования секретов​

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

Блок кода
terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = ">=6.0.0"
    }
  }
}

variable "secret_map" {
  type        = map(string)
  default     = null # default because in some cases this module can be used only for reading the secret and not storing it
  ephemeral   = true # defines an ephemeral variable since it holds the secrets to be processed
  description = "The map of secrets to be used to create the new secret entry. Omit this when using this module to read the secret"
}

variable "secret_version" {
  # needed to update a write-only attribute
  type        = number
  default     = 0
  description = "The version used to update the secret. You need to bump this from the previous version in order for the secret_map content to be persisted. Omit this when using this module to read the secret"
}

variable "secret_manager_arn" {
  type        = string
  default     = ""
  description = "The map of secrets to be used to create the new secret entry"
  validation {
    condition     = (var.secret_manager_arn == "" && var.secret_map != null) || (var.secret_manager_arn != "" && var.secret_map == null)
    error_message = "var.secret_manager_arn should not be used in the same time with var.secret_map. Use the module only with var.secret_manager_arn to read the secret or use it with var.secret_map and var.secret_version to create a new secret"
  }
}

resource "aws_secretsmanager_secret" "manager" {
  count = var.secret_version > 0 ? 1 : 0 # used when we create a new secret manager
  name  = "testin-secret-manager"
}

resource "aws_secretsmanager_secret_version" "secret_creation" {
  count                    = var.secret_version > 0 ? 1 : 0 # used when we want to create a new secret
  secret_id                = aws_secretsmanager_secret.manager[0].arn
  secret_string_wo         = jsonencode(var.secret_map) # here we pass in the ephemeral variable into a write-only attribute
  secret_string_wo_version = var.secret_version
  # and when we want to update it, we can provide a different value for var.secret_map and an incremented secret_version
}

ephemeral "aws_secretsmanager_secret_version" "secret_retrieval" {
  # used to read the secret from the secret manager after creating it
  count     = var.secret_version > 0 ? 1 : 0
  secret_id = aws_secretsmanager_secret.manager[0].arn
  depends_on = [
    aws_secretsmanager_secret_version.secret_creation # ensure that we want for the secret creation before reading it
  ]
}

ephemeral "aws_secretsmanager_secret_version" "secret_retrieval_direct" {
  # used to read the secret from the secret manager when the module is used only for reading without creating a new secret
  count     = var.secret_version > 0 ? 0 : 1
  secret_id = var.secret_manager_arn
}

output "secrets" {
  value = "${var.secret_version > 0 ?
    jsondecode(ephemeral.aws_secretsmanager_secret_version.secret_retrieval[0].secret_string) :
    jsondecode(ephemeral.aws_secretsmanager_secret_version.secret_retrieval_direct[0].secret_string)}"
  ephemeral = true # marking an output as ephemeral is mandatory when the value points to an ephemeral value
}

output "secret_manager_arn" {
  value = var.secret_version > 0 ? aws_secretsmanager_secret.manager[0].arn : null
  # available only when the module is used to create a secret
}

Использование модуля в конфигурации для хранения секрета​

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

Блок кода
terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "6.0.0-beta1"
    }
  }
}

provider "aws" {
  alias = "secrets-read-write"
}

variable "access_key" {
  type      = string
  ephemeral = true
}

variable "secret_key" {
  type      = string
  ephemeral = true
}

locals {
  secrets = {
    "access_key" : var.access_key,
    "secret_key" : var.secret_key
  }
}

module "secret_management" {
  providers = {
    aws = aws.secrets-read-write
  }
  source         = "../mod"
  secret_map     = local.secrets
  secret_version = 1 # first version of the secret. If want to update the secret inside, bump this version
}

output "secret_manager_arn" {
  value = module.secret_management.secret_manager_arn
}

Использование модуля в конфигурации для получения секрета и настройки провайдера​

Следующая конфигурация использует описанный выше модуль для чтения секрета, настройки провайдера с полученными учетными данными и сохранения тех же учетных данных в атрибуте только для записи value_wo ресурса aws_ssm_parameter. Кроме того, она добавляет два провижионера local-exec. При выполнении первого будет выведено содержимое command, а при выполнении второго — (output suppressed due to ephemeral value in config):

Блок кода
terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "6.0.0-beta1"
    }
  }
}
provider "aws" {
  alias = "read-secrets"
}

variable "secret_manager_arn" {
  type = string
}

module "secret_management" {
  providers = {
    aws = aws.read-secrets
  }
  source             = "../mod"
  secret_manager_arn = var.secret_manager_arn
}

# Provider can be configured with the credentials returned by the ephemeral resource inside the module.
provider "aws" {
  alias      = "dev-access"
  access_key = module.secret_management.secrets["access_key"]
  secret_key = module.secret_management.secrets["secret_key"]
}

resource "aws_ssm_parameter" "store_ephemeral_in_write_only" {
  provider         = aws.dev-access
  name             = "parameter_from_ephemeral_value"
  type             = "SecureString"
  value_wo         = jsonencode(module.secret_management.secrets) # Using the secrets again in a write-only attribute
  value_wo_version = 1 # bump this if `value_wo` needs to be updated

  # Because this provisioner uses only regular attributes, it will print the output of the command
  provisioner "local-exec" {
    when    = create
    command = "echo non-ephemeral value: ${aws_ssm_parameter.store_ephemeral_in_write_only.arn}"
  }

  # Because this provisioner uses ephemeral values, its output will be suppressed
  provisioner "local-exec" {
    when    = create
    command = "echo ephemeral value from module: #${jsonencode(module.secret_management.secrets)}#"
  }
}

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

Spec-Zone.ru

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