Эфемерность
Эфемерность описывает свойство значения быть «эфемерным», то есть не сохраняться в состоянии или плане. Благодаря этой концепции в OpenTofu можно безопасно обрабатывать временную и/или конфиденциальную информацию.
Связанные концепции:
-
Конфиденциальные поля ресурсов, выходные значения и переменные
- Пометка значений как конфиденциальных гарантирует, что их содержимое будет скрыто в пользовательском интерфейсе.
- Конфиденциальные значения по-прежнему будут храниться в виде открытого текста в состоянии и плане.
-
Шифрование состояния
- Можно настроить шифрование данных состояния и плана, чтобы предотвратить несанкционированный доступ к ним и их подмену.
- Безопасность этих данных определяется используемыми методами шифрования и доступом к ключам шифрования.
В отличие от них, эфемерные значения существуют только в течение одного выполнения команды tofu и никогда не сохраняются в данных состояния или плана. Это позволяет представлять временные сущности, такие как временные сетевые туннели или конфиденциальные ключи, которыми управляет внешняя система.
При работе с конфиденциальной информацией рекомендуется учитывать все три концепции. По возможности используйте эфемерные значения/ресурсы, чтобы вообще не сохранять данные. Если конфиденциальные данные необходимо сохранить, убедитесь, что они помечены как конфиденциальные, а шифрование состояния и плана включено и настроено правильно.
В рамках этой концепции можно использовать следующие конструкции:
- Эфемерные ресурсы
- Эфемерные переменные
- Эфемерные выходные значения
- Локальные значения
- Провайдеры
- Провижионеры
- Блоки ресурсов
connection - Атрибуты ресурсов
write-only
Совместимость
Эта концепция вдохновлена соответствующей концепцией «Ephemeral» в Terraform v1.12 и призвана обеспечить совместимость с ней. Если обнаружатся несовместимости, команда OpenTofu рассмотрит возможность внесения несовместимых изменений в последующие версии OpenTofu, чтобы обеспечить совместимость.
Дополнительные темы
- Передача значений эфемерным переменным корневого модуля
- Взаимодействие проверок с эфемерными значениями
- Очистка значений с помощью
ephemeralasnull() - Различия между планированием и применением с помощью
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.11/language/ephemerality/