-
Notifications
You must be signed in to change notification settings - Fork 0
feat: tf ephemeral value and encrypted state examples #1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
WalkthroughThis update introduces two new Terraform/OpenTofu example projects: one demonstrating encrypted state with AWS KMS, and another showcasing ephemeral resources and variables for secrets management. Both projects include provider configurations, version constraints, and resources for generating and storing secrets in AWS Secrets Manager, with appropriate dependency lock files to ensure reproducibility. Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant Terraform
participant AWS KMS
participant AWS SecretsManager
participant RandomProvider
User->>Terraform: Apply configuration
Terraform->>AWS KMS: Create KMS key (for encrypted state)
Terraform->>RandomProvider: Generate random password
Terraform->>AWS SecretsManager: Create secret
Terraform->>AWS SecretsManager: Store password as secret version
sequenceDiagram
participant User
participant Terraform
participant AWS SecretsManager
User->>Terraform: Apply configuration (ephemeral example)
Terraform->>AWS SecretsManager: Create sensitive secret
Terraform->>AWS SecretsManager: Create ephemeral secret
Note right of Terraform: Ephemeral variable is not stored in state
Poem
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 6
🧹 Nitpick comments (9)
tf-ephemeral/providers.tf (1)
1-3
: Parameterise the AWS region instead of hard-coding itHard-coding
us-east-1
limits re-use of this example in other regions and forces consumers to edit code instead of supplying a variable. Expose the region as an input with a sane default.-variable "aws_region" { - type = string - default = "us-east-1" -} - provider "aws" { - region = "us-east-1" + region = var.aws_region }tf-ephemeral/main.tf (1)
5-11
: Optional: add encryption key or tags for better hygieneThe secrets use default KMS keys and have no tags, which is fine for a demo but not for production. Consider exposing
kms_key_id
and common tags via variables so the example doubles as a best-practice template.tf-ephemeral/ephemeral-variables.tf (1)
12-15
: Sensitive output still risks accidental disclosureMarking the output as
sensitive = true
only hides the value from a normalterraform output
, but the secret is still in the state file and can be revealed with-json
. Consider omitting the output entirely or replacing it with a hash / confirmation message.terraform-encrypted-state/providers.tofu (1)
1-3
: Parameterise AWS region for better portabilityHard-coding the region ties the example to
us-east-1
. A simple variable (defaulting tous-east-1
) would let users run the sample in any region without editing the file.-provider "aws" { - region = "us-east-1" -} +variable "aws_region" { + type = string + default = "us-east-1" +} + +provider "aws" { + region = var.aws_region +}terraform-encrypted-state/kms.tf (1)
5-8
: Mark KMS key ID output assensitive
Key IDs aren’t secret, but avoiding plaintext in logs/CI is still a good practice.
output "kms_key_id" { value = aws_kms_key.tf_state.key_id description = "KMS key id" + sensitive = true }
terraform-encrypted-state/main.tf (3)
1-8
: Consider exposing password requirements via variablesThe length and character-set flags are fixed. Making them variables would let consumers tune entropy / compliance without touching the module.
11-14
: Add tags for traceability and cost allocationAWS tagging is virtually free and helps with billing dashboards and auditing.
resource "aws_secretsmanager_secret" "main_password" { name = "main-application-password" description = "Main application password" + tags = { + managed_by = "terraform" + purpose = "example-showcase" + } }
17-20
: Enable automatic secret rotation (optional)For real-world use, attach a rotation schedule or Lambda to keep the secret fresh.
terraform-encrypted-state/versions.tofu (1)
1-37
: General adviceThe
encryption
block is pioneering but still experimental; pinningrequired_version = "~> 1.7.0"
can avoid breaking changes when 1.8 lands.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (11)
terraform-encrypted-state/.terraform.lock.hcl
(1 hunks)terraform-encrypted-state/kms.tf
(1 hunks)terraform-encrypted-state/main.tf
(1 hunks)terraform-encrypted-state/providers.tofu
(1 hunks)terraform-encrypted-state/versions.tofu
(1 hunks)tf-ephemeral/.terraform.lock.hcl
(1 hunks)tf-ephemeral/ephemeral-resources.tf
(1 hunks)tf-ephemeral/ephemeral-variables.tf
(1 hunks)tf-ephemeral/main.tf
(1 hunks)tf-ephemeral/providers.tf
(1 hunks)tf-ephemeral/versions.tf
(1 hunks)
🧰 Additional context used
🪛 Checkov (3.2.334)
terraform-encrypted-state/kms.tf
[MEDIUM] 1-3: Ensure KMS key Policy is defined
(CKV2_AWS_64)
🔇 Additional comments (7)
tf-ephemeral/versions.tf (2)
1-3
: Verify that Terraform ≥ 1.11.0 actually exists
required_version = ">= 1.11.0"
will currently fail because Terraform 1.11 has not been released (latest official is 1.8.x). If you are depending on an unreleased fork or OpenTofu preview, clarify this in the README or pin to a released version to keep the example runnable.- required_version = ">= 1.11.0" + # Change to the latest released version so users can run the demo today. + required_version = ">= 1.6.0"
4-13
: Provider constraints look sensibleVersion constraints for
aws
(>= 6.0.0) andrandom
(>= 3.0.0) are explicit and future-proof.tf-ephemeral/.terraform.lock.hcl (1)
4-7
: Check that provider 6.0.0 is publishedThe lock file pins
hashicorp/aws
to 6.0.0 which, like Terraform 1.11, is not yet on the public registry. Runningterraform init
will error until that version is available. Please verify the provider release timeline or repin to the latest stable 5.x series.tf-ephemeral/ephemeral-resources.tf (1)
1-5
: Confirmephemeral
block support in chosen Terraform distribution
ephemeral
blocks are not yet in mainstream Terraform/OpenTofu releases. Ensure the demo specifically instructs users to install the required experimental build; otherwise, the configuration will be rejected.tf-ephemeral/ephemeral-variables.tf (2)
7-10
: Insecure block already annotated as intentionalThe “Before” example is clearly marked with comments (
# Before – using sensitive (stored in state)
and the ❌ marker onsecret_string
), demonstrating why storing plaintext in state is bad. No further changes needed.
24-28
: secret_string_wo attributes are supported by AWS provider
The AWS provider (≥ 5.x) natively supports the write-only argumentssecret_string_wo
andsecret_string_wo_version
to keep secret values out of the Terraform state. The code intf-ephemeral/ephemeral-variables.tf
is correct as-is—no renaming tosecret_string
is needed.Likely an incorrect or invalid review comment.
terraform-encrypted-state/.terraform.lock.hcl (1)
1-38
: Lock file looks saneProvider versions and hashes match the constraints; nothing to flag.
resource "aws_secretsmanager_secret_version" "random_password_ephemeral_secret_version" { | ||
secret_id = aws_secretsmanager_secret.random_password_ephemeral_secret.id | ||
secret_string_wo = ephemeral.random_password.random_password_ephemeral.result | ||
secret_string_wo_version = 1 | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Invalid attribute names on aws_secretsmanager_secret_version
secret_string_wo
and secret_string_wo_version
do not exist in the AWS provider schema. Use secret_string
(optionally with version_stages
) or the binary_secret
attributes.
-resource "aws_secretsmanager_secret_version" "random_password_ephemeral_secret_version" {
- secret_id = aws_secretsmanager_secret.random_password_ephemeral_secret.id
- secret_string_wo = ephemeral.random_password.random_password_ephemeral.result
- secret_string_wo_version = 1
-}
+resource "aws_secretsmanager_secret_version" "random_password_ephemeral_secret_version" {
+ secret_id = aws_secretsmanager_secret.random_password_ephemeral_secret.id
+ secret_string = jsonencode({
+ password = ephemeral.random_password.random_password_ephemeral.result
+ })
+ version_stages = ["AWSCURRENT"]
+}
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
resource "aws_secretsmanager_secret_version" "random_password_ephemeral_secret_version" { | |
secret_id = aws_secretsmanager_secret.random_password_ephemeral_secret.id | |
secret_string_wo = ephemeral.random_password.random_password_ephemeral.result | |
secret_string_wo_version = 1 | |
} | |
resource "aws_secretsmanager_secret_version" "random_password_ephemeral_secret_version" { | |
secret_id = aws_secretsmanager_secret.random_password_ephemeral_secret.id | |
secret_string = jsonencode({ | |
password = ephemeral.random_password.random_password_ephemeral.result | |
}) | |
version_stages = ["AWSCURRENT"] | |
} |
🤖 Prompt for AI Agents
In tf-ephemeral/ephemeral-resources.tf around lines 11 to 15, the attributes
secret_string_wo and secret_string_wo_version used in the
aws_secretsmanager_secret_version resource are invalid. Replace secret_string_wo
with secret_string and remove secret_string_wo_version or replace it with the
correct attribute version_stages if needed, according to the AWS provider
schema.
variable "api_key_ephemeral" { | ||
ephemeral = true # Never stored! | ||
default = "wJalrXUtnFEMI/K7MDENG/bPxRfiCY-EXAMPLE_SECRET_WONT_BE_STORED" | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ephemeral variable example also leaks secret through VCS
Even though ephemeral = true
prevents the value from reaching state, the literal secret is still baked into the repo. Replace with an empty default or a clearly invalid placeholder to avoid misconceptions.
-variable "api_key_ephemeral" {
- ephemeral = true # Never stored!
- default = "wJalrXUtnFEMI/K7MDENG/bPxRfiCY-EXAMPLE_SECRET_WONT_BE_STORED"
-}
+variable "api_key_ephemeral" {
+ type = string
+ ephemeral = true # Never stored!
+ description = "API key supplied at apply time; never persisted to state."
+}
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
variable "api_key_ephemeral" { | |
ephemeral = true # Never stored! | |
default = "wJalrXUtnFEMI/K7MDENG/bPxRfiCY-EXAMPLE_SECRET_WONT_BE_STORED" | |
} | |
variable "api_key_ephemeral" { | |
type = string | |
ephemeral = true # Never stored! | |
description = "API key supplied at apply time; never persisted to state." | |
} |
🤖 Prompt for AI Agents
In tf-ephemeral/ephemeral-variables.tf around lines 18 to 21, the variable
"api_key_ephemeral" has a default value containing a literal secret, which leaks
sensitive information through version control. Remove the actual secret from the
default value and replace it with an empty string or a clearly invalid
placeholder to prevent accidental exposure while keeping the variable definition
valid.
variable "api_key" { | ||
sensitive = true # Still stored in state! | ||
default = "xK9#mP2$vL@4qR7!nT6&wZ8*bY3^fH5j-EXAMPLE_SECRET_IN_PLAINTEXT" | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hard-coded secret should be removed from VCS
Storing an actual API key in the default
value means the secret is committed to source control, defeating both sensitive
and the later “ephemeral” demo. Ship the example with no default (or a placeholder) and require the user to supply the value via TF_VAR_api_key
/ .tfvars.
-variable "api_key" {
- sensitive = true # Still stored in state!
- default = "xK9#mP2$vL@4qR7!nT6&wZ8*bY3^fH5j-EXAMPLE_SECRET_IN_PLAINTEXT"
-}
+variable "api_key" {
+ type = string
+ sensitive = true # Still stored in state!
+ description = "API key to be provided at apply time (e.g. TF_VAR_api_key)."
+}
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
variable "api_key" { | |
sensitive = true # Still stored in state! | |
default = "xK9#mP2$vL@4qR7!nT6&wZ8*bY3^fH5j-EXAMPLE_SECRET_IN_PLAINTEXT" | |
} | |
variable "api_key" { | |
type = string | |
sensitive = true # Still stored in state! | |
description = "API key to be provided at apply time (e.g. TF_VAR_api_key)." | |
} |
🤖 Prompt for AI Agents
In tf-ephemeral/ephemeral-variables.tf lines 1 to 4, remove the hard-coded API
key from the default value to avoid committing secrets to version control.
Replace the default with no value or a placeholder string, and ensure the
variable is required to be set externally via TF_VAR_api_key or a .tfvars file.
resource "aws_kms_key" "tf_state" { | ||
description = "KMS key for Terraform/OpenTofu state encryption" | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add an explicit key policy – default policy is not recommended
Static analysis (CKV2_AWS_64) flagged the absence of a policy
block. Relying on the implicit default KMS key policy can break least-privilege and cross-account access scenarios.
resource "aws_kms_key" "tf_state" {
description = "KMS key for Terraform/OpenTofu state encryption"
+
+ policy = jsonencode({
+ Version : "2012-10-17",
+ Id : "key-default-1",
+ Statement : [
+ {
+ Sid : "Enable IAM root and principals",
+ Effect : "Allow",
+ Principal : { AWS : "arn:aws:iam::${data.aws_caller_identity.current.account_id}:root" },
+ Action : "kms:*",
+ Resource : "*"
+ }
+ ]
+ })
}
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
resource "aws_kms_key" "tf_state" { | |
description = "KMS key for Terraform/OpenTofu state encryption" | |
} | |
resource "aws_kms_key" "tf_state" { | |
description = "KMS key for Terraform/OpenTofu state encryption" | |
policy = jsonencode({ | |
Version : "2012-10-17", | |
Id : "key-default-1", | |
Statement : [ | |
{ | |
Sid : "Enable IAM root and principals", | |
Effect : "Allow", | |
Principal : { AWS : "arn:aws:iam::${data.aws_caller_identity.current.account_id}:root" }, | |
Action : "kms:*", | |
Resource : "*" | |
} | |
] | |
}) | |
} |
🧰 Tools
🪛 Checkov (3.2.334)
[MEDIUM] 1-3: Ensure KMS key Policy is defined
(CKV2_AWS_64)
🤖 Prompt for AI Agents
In terraform-encrypted-state/kms.tf at lines 1 to 3, the aws_kms_key resource
lacks an explicit key policy block, which is flagged by static analysis for
security reasons. Add a `policy` block to define a custom key policy that
explicitly grants necessary permissions, ensuring least-privilege access and
supporting cross-account scenarios instead of relying on the default implicit
policy.
method "aes_gcm" "kms" { | ||
keys = key_provider.aws_kms.kms_key | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
keys
attribute must be a list
OpenTofu/TF 1.7 expects a list for keys
. Current syntax will error.
- keys = key_provider.aws_kms.kms_key
+ keys = [key_provider.aws_kms.kms_key]
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
method "aes_gcm" "kms" { | |
keys = key_provider.aws_kms.kms_key | |
} | |
method "aes_gcm" "kms" { | |
- keys = key_provider.aws_kms.kms_key | |
+ keys = [key_provider.aws_kms.kms_key] | |
} |
🤖 Prompt for AI Agents
In terraform-encrypted-state/versions.tofu around lines 24 to 26, the keys
attribute is currently assigned a single value but it must be a list according
to OpenTofu/TF 1.7 requirements. To fix this, wrap the existing value of keys in
square brackets to make it a list, ensuring the syntax matches the expected
format and prevents errors.
key_provider "aws_kms" "kms_key" { | ||
kms_key_id = "INSERT_KMS_KEY_ID_HERE" | ||
region = "us-east-1" | ||
key_spec = "AES_256" | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Avoid committing placeholder KMS key IDs
kms_key_id = "INSERT_KMS_KEY_ID_HERE"
will make terraform init
fail. Inject the ID via variable or reference the aws_kms_key.tf_state
resource if this file lives in the same configuration.
- kms_key_id = "INSERT_KMS_KEY_ID_HERE"
+ # If defined in the same workspace:
+ # kms_key_id = aws_kms_key.tf_state.key_id
+ # Otherwise pass it through a variable:
+ # kms_key_id = var.kms_key_id
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
key_provider "aws_kms" "kms_key" { | |
kms_key_id = "INSERT_KMS_KEY_ID_HERE" | |
region = "us-east-1" | |
key_spec = "AES_256" | |
} | |
key_provider "aws_kms" "kms_key" { | |
# If defined in the same workspace: | |
# kms_key_id = aws_kms_key.tf_state.key_id | |
# Otherwise pass it through a variable: | |
# kms_key_id = var.kms_key_id | |
region = "us-east-1" | |
key_spec = "AES_256" | |
} |
🤖 Prompt for AI Agents
In terraform-encrypted-state/versions.tofu around lines 18 to 22, the kms_key_id
is set to a placeholder string which causes terraform init to fail. Replace the
hardcoded placeholder with a variable reference or use a reference to the
aws_kms_key.tf_state resource if it exists in the same configuration, ensuring
the actual KMS key ID is dynamically injected during terraform execution.
For the content short term video. Will update the README within the directory once video gets up
Summary by CodeRabbit
New Features
Chores