Skip to content

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

Open
wants to merge 2 commits into
base: main
Choose a base branch
from

Conversation

oycyc
Copy link
Contributor

@oycyc oycyc commented Jul 1, 2025

For the content short term video. Will update the README within the directory once video gets up

Summary by CodeRabbit

  • New Features

    • Introduced secure storage of random passwords in AWS Secrets Manager for both persistent and ephemeral use cases.
    • Added support for encrypted Terraform state using AWS KMS and AES-GCM encryption.
    • Demonstrated handling of sensitive and ephemeral variables to enhance secret management security.
    • Added Terraform provider configurations and version constraints for improved compatibility and reproducibility.
  • Chores

    • Added lock files to ensure consistent provider versions and dependency integrity.

Copy link

coderabbitai bot commented Jul 1, 2025

Walkthrough

This 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

File(s) Change Summary
terraform-encrypted-state/.terraform.lock.hcl, tf-ephemeral/.terraform.lock.hcl Added provider dependency lock files specifying exact provider versions and hashes for reproducibility.
terraform-encrypted-state/kms.tf Added AWS KMS key resource for state encryption and an output for the KMS key ID.
terraform-encrypted-state/main.tf Added resources to generate a random password and store it in AWS Secrets Manager.
terraform-encrypted-state/providers.tofu, tf-ephemeral/providers.tf Added AWS provider configuration with region set to "us-east-1".
terraform-encrypted-state/versions.tofu Added Terraform configuration specifying required versions, providers, and state encryption with AWS KMS.
tf-ephemeral/ephemeral-resources.tf Added resources to generate an ephemeral random password and store it in AWS Secrets Manager.
tf-ephemeral/ephemeral-variables.tf Added variables and resources to illustrate the difference between sensitive and ephemeral secret handling.
tf-ephemeral/main.tf Added AWS Secrets Manager secret resources for sensitive and ephemeral secrets.
tf-ephemeral/versions.tf Added Terraform configuration specifying required versions and providers.

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
Loading
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
Loading

Poem

In burrows deep, the secrets hide,
With KMS locks and state encrypted wide.
Ephemeral carrots, passwords anew,
Stored in the cloud, safe from view.
Providers aligned, the hashes in place—
This bunny hops on, securing your space!
🥕🔐


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.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need 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)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@coderabbitai coderabbitai bot left a 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 it

Hard-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 hygiene

The 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 disclosure

Marking the output as sensitive = true only hides the value from a normal terraform 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 portability

Hard-coding the region ties the example to us-east-1. A simple variable (defaulting to us-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 as sensitive

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 variables

The 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 allocation

AWS 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 advice

The encryption block is pioneering but still experimental; pinning required_version = "~> 1.7.0" can avoid breaking changes when 1.8 lands.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c8d0e3e and 4491d36.

📒 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 sensible

Version constraints for aws (>= 6.0.0) and random (>= 3.0.0) are explicit and future-proof.

tf-ephemeral/.terraform.lock.hcl (1)

4-7: Check that provider 6.0.0 is published

The lock file pins hashicorp/aws to 6.0.0 which, like Terraform 1.11, is not yet on the public registry. Running terraform 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: Confirm ephemeral 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 intentional

The “Before” example is clearly marked with comments (# Before – using sensitive (stored in state) and the ❌ marker on secret_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 arguments secret_string_wo and secret_string_wo_version to keep secret values out of the Terraform state. The code in tf-ephemeral/ephemeral-variables.tf is correct as-is—no renaming to secret_string is needed.

Likely an incorrect or invalid review comment.

terraform-encrypted-state/.terraform.lock.hcl (1)

1-38: Lock file looks sane

Provider versions and hashes match the constraints; nothing to flag.

Comment on lines +11 to +15
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
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

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.

Suggested change
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.

Comment on lines +18 to +21
variable "api_key_ephemeral" {
ephemeral = true # Never stored!
default = "wJalrXUtnFEMI/K7MDENG/bPxRfiCY-EXAMPLE_SECRET_WONT_BE_STORED"
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

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.

Suggested change
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.

Comment on lines +1 to +4
variable "api_key" {
sensitive = true # Still stored in state!
default = "xK9#mP2$vL@4qR7!nT6&wZ8*bY3^fH5j-EXAMPLE_SECRET_IN_PLAINTEXT"
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

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.

Suggested change
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.

Comment on lines +1 to +3
resource "aws_kms_key" "tf_state" {
description = "KMS key for Terraform/OpenTofu state encryption"
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

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.

Suggested change
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.

Comment on lines +24 to +26
method "aes_gcm" "kms" {
keys = key_provider.aws_kms.kms_key
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

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.

Suggested change
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.

Comment on lines +18 to +22
key_provider "aws_kms" "kms_key" {
kms_key_id = "INSERT_KMS_KEY_ID_HERE"
region = "us-east-1"
key_spec = "AES_256"
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

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.

Suggested change
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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant