{"id":1810,"date":"2025-03-10T21:16:02","date_gmt":"2025-03-10T21:16:02","guid":{"rendered":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/2025\/03\/10\/ephemeral-values-in-terraform\/"},"modified":"2025-03-10T21:16:02","modified_gmt":"2025-03-10T21:16:02","slug":"ephemeral-values-in-terraform","status":"publish","type":"post","link":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/2025\/03\/10\/ephemeral-values-in-terraform\/","title":{"rendered":"Ephemeral values in Terraform"},"content":{"rendered":"<p>Before Terraform 1.11, working with sensitive values was a challenge \u2014 sensitive values were always persisted to the Terraform plan artifact and state. As a result, we advised (and <a href=\"https:\/\/developer.hashicorp.com\/terraform\/language\/state\/sensitive-data\">still advise<\/a>) treating your state as sensitive data. This advice applies equally to us as it does to you. To address this, we introduced the concept of ephemerality in Terraform, allowing you to work with sensitive data like passwords and tokens securely, without leaving a trace.<\/p>\n<h2>Ephemerality<\/h2>\n<p>Ephemerality in computing refers to the ability to create something that is short-lived or temporary \u2014 a piece of data that exists only for a brief period and is discarded once its purpose is fulfilled. In Terraform, this concept was introduced to manage sensitive data or open a connection in a way that ensures it doesn\u2019t persist beyond its immediate use. We\u2019ve implemented new language constructs that track values only at runtime, making them transient and, therefore, ephemeral by design. These are part of what we call ephemeral values, a term that covers both ephemeral resources, ephemeral input variables, and write-only arguments.<\/p>\n<h2>Ephemeral resources<\/h2>\n<p><a href=\"https:\/\/developer.hashicorp.com\/terraform\/plugin\/framework\/ephemeral-resources\">Ephemeral resources<\/a> are Terraform resources that are essentially temporary. They are responsible for reading data from a source such as a <a href=\"https:\/\/www.vaultproject.io\/use-cases\/secrets-management\">secrets manager<\/a>, or opening a connection, and their attributes can be referenced in other places without persisting anything to the Terraform plan artifact or state file.<\/p>\n<p>It\u2019s important to note that ephemeral resources require all their dependencies to exist because they always run during both the plan and apply stages. If an ephemeral resource attempts to read a secret from a secrets manager that doesn\u2019t exist, it will result in an error. However, Terraform can defer the execution of an ephemeral resource to the apply stage if one of its input arguments references a value that is not yet known at the plan stage but will be determined during apply.<\/p>\n<p>Here\u2019s an example of an ephemeral password resource with no dependencies, executed during both plan and apply:<\/p>\n<p>ephemeral &#8220;random_password&#8221; &#8220;db_password&#8221; {<br \/>\n  length = 16<br \/>\n}<\/p>\n<p>This generates an ephemeral password string using a cryptographic random number generator. The generated string can then be used as input for a write-only attribute on a managed or ephemeral resource.<\/p>\n<h2>Write-only arguments<\/h2>\n<p><a href=\"https:\/\/developer.hashicorp.com\/terraform\/plugin\/framework\/resources\/write-only-arguments\">Write-only arguments<\/a> are managed resource attributes that are configured by users but are not persisted to the Terraform plan artifact or state file. Terraform providers implement write-only arguments on managed resources to handle sensitive values, such as passwords, tokens, and other secrets, securely. <\/p>\n<p>An example of a write-only argument is the secret_string_wo argument on the aws_secretsmanager_secret_version resource:<\/p>\n<p>resource &#8220;aws_secretsmanager_secret_version&#8221; &#8220;db_password&#8221; {<br \/>\n  secret_id                = aws_secretsmanager_secret.db_password.id<br \/>\n  secret_string_wo         = ephemeral.random_password.db_password.result<br \/>\n  secret_string_wo_version = 1<br \/>\n}<\/p>\n<p>It\u2019s common for write-only arguments to be assigned an ephemeral resource attribute, as shown in the example above. This enables end-to-end ephemerality in Terraform, ensuring that sensitive values are not persisted in either the Terraform plan artifact or the state file.<\/p>\n<p>Earlier, we mentioned that ephemeral resources are executed during every plan and apply. This means that a new ephemeral random password is generated, or a new value is fetched from a secrets manager, with each plan and each apply. To prevent a write-only argument from being updated on every run after creation, you set the write-only version argument. Terraform stores this version in state and uses it to track changes. When the version is incremented, Terraform allows the resource to accept the new value for the write-only argument, which is then sent to the provider to update it accordingly.<\/p>\n<h3>Write-only version arguments<\/h3>\n<p>Terraform doesn\u2019t store write-only arguments in the plan or state file, meaning it can\u2019t track changes to their values. As a result, write-only arguments are sent to the provider during every operation. However, providers typically include write-only version arguments (e.g. password_wo_version) alongside write-only value arguments (e.g. password_wo), where the version arguments are stored in the state file and can be tracked for changes.<\/p>\n<p>These write-only version arguments enable users to update a write-only value by incrementing the version number. When the write-only version argument is updated, Terraform detects this change in the plan and notifies the provider. The provider then uses the updated write-only value to update the resource accordingly.<\/p>\n<p>If a resource depends on multiple write-only arguments in the dependency graph, it\u2019s a good idea to keep their version arguments in sync. This way, all the related write-only values are updated together, avoiding inconsistencies and ensuring the provider uses the correct values during each operation. In the next section, we\u2019ll cover deferring ephemeral resources, and the example code will demonstrate how to synchronize versioning for write-only arguments.<\/p>\n<h2>Deferring ephemeral resources<\/h2>\n<p>If an input argument of an ephemeral resource references a value that is not yet known but will be during or after the plan, Terraform defers the resource\u2019s execution to the apply stage instead of running it during the plan. This behavior allows Terraform to evaluate the ephemeral resource at the correct time and ensures that the resource is not executed prematurely.<\/p>\n<p>Similarly, ephemeral resources form nodes in Terraform\u2019s dependency graph. When a managed resource or data source depends on an attribute of an ephemeral resource, Terraform automatically provisions the ephemeral resource first.<\/p>\n<p>As we concluded earlier, ephemeral resources are executed during every plan and apply. It\u2019s important to model your Terraform configuration in such a way that the dependency graph of all of the managed resources and ephemeral resources ensures correct execution order and prevents unintended behavior. <\/p>\n<p>By using the ephemeral random password and AWS Secrets Manager secret we created earlier, we can take advantage of ephemerality and its deferring logic to securely provision an AWS RDS instance.<\/p>\n<p>ephemeral &#8220;random_password&#8221; &#8220;db_password&#8221; {<br \/>\n  length           = 16<br \/>\n  override_special = &#8220;!#$%&amp;*()-_=+[]{}&lt;&gt;:?&#8221;<br \/>\n}<\/p>\n<p>resource &#8220;aws_secretsmanager_secret&#8221; &#8220;db_password&#8221; {<br \/>\n  name = &#8220;db-password&#8221;<br \/>\n}<\/p>\n<p>resource &#8220;aws_secretsmanager_secret_version&#8221; &#8220;db_password&#8221; {<br \/>\n  secret_id                = aws_secretsmanager_secret.db_password.id<br \/>\n  secret_string_wo         = ephemeral.random_password.db_password.result<br \/>\n  secret_string_wo_version = 1<br \/>\n}<\/p>\n<p>ephemeral &#8220;aws_secretsmanager_secret_version&#8221; &#8220;db_password&#8221; {<br \/>\n  secret_id = aws_secretsmanager_secret_version.db_password.secret_id<br \/>\n}<\/p>\n<p>resource &#8220;aws_db_instance&#8221; &#8220;example&#8221; {<br \/>\n  instance_class      = &#8220;db.t3.micro&#8221;<br \/>\n  allocated_storage   = &#8220;5&#8221;<br \/>\n  engine              = &#8220;postgres&#8221;<br \/>\n  username            = &#8220;example&#8221;<br \/>\n  skip_final_snapshot = true<br \/>\n  password_wo         = ephemeral.aws_secretsmanager_secret_version.db_password.secret_string<br \/>\n  password_wo_version = aws_secretsmanager_secret_version.db_password.secret_string_wo_version<br \/>\n}<\/p>\n<p>In the above example, the ephemeral resource aws_secretsmanager_secret_version depends on an argument that Terraform doesn\u2019t initially know. Terraform defers executing this ephemeral resource until the apply stage, ensuring it runs only after the necessary information becomes available.<\/p>\n<p>During the apply stage Terraform first creates the secret in AWS Secrets Manager using the ephemeral random_password, then Terraform retrieves the secret using the ephemeral aws_secretsmanager_secret_version resource. The last thing Terraform does is write the password to the write-only password_wo argument of the aws_db_instance resource.<\/p>\n<h2>Lifecycle of an ephemeral resource<\/h2>\n<p>Ephemeral resources have a lifecycle that differs from other resources and data sources. The lifecycle has three steps: <\/p>\n<p><strong>Opening<\/strong>: When Terraform needs the result of an ephemeral resource, it opens it \u2014 much like reading a secret from a secrets manager.<br \/>\n<strong>Renewing<\/strong>: If Terraform needs access to the ephemeral resource for longer than the remote system\u2019s enforced expiration time, Terraform asks the provider to periodically renew it.<br \/>\n<strong>Closing<\/strong>: Once Terraform no longer needs an ephemeral resource, it closes it. This happens after the providers that depend on an ephemeral resource complete all of their work for the current Terraform run phase.<\/p>\n<p>All ephemeral resources implement a form of opening logic, but not all implement closing or renewing logic. Whether they do depends on the ephemeral nature of the resource \u2014 handling tunnel connections, for instance, may require periodic renewal and proper closure of the connection. Leasing a temporary set of credentials from Vault would similarly imply renewal and revocation of those credentials when they&#8217;re no longer needed.<\/p>\n<h2>Persisting ephemeral secrets<\/h2>\n<p>Ephemerality in Terraform prevents introspection of the value itself, which is the expected and intended behavior. However, this could lead to a potential issue. When using the ephemeral random password, you\u2019re generating a new secret that hasn\u2019t been persisted to a secrets manager yet, so it\u2019s important to store it to ensure it remains accessible. This is why, in the third code snippet above, we write the ephemeral random password to a secrets manager first and then fetch it from there during the apply stage using another ephemeral resource, effectively persisting an ephemeral secret to a secrets manager.<\/p>\n<p>However, if you\u2019re reading existing secrets from a secrets manager that\u2019s managed outside of the Terraform module you\u2019re working in, there\u2019s no need to persist them again.<\/p>\n<h2>Learn more about ephemeral values<\/h2>\n<p>For more information on working with ephemeral values, resources, and write-only arguments, check out the <a href=\"https:\/\/developer.hashicorp.com\/terraform\/language\/resources\/ephemeral\">ephemerality in resources<\/a> documentation. You can find detailed information on ephemeral resources in the <a href=\"https:\/\/developer.hashicorp.com\/terraform\/language\/resources\/ephemeral\/reference\">ephemeral resource block<\/a> documentation, or learn more about write-only arguments in the <a href=\"https:\/\/developer.hashicorp.com\/terraform\/language\/resources\/ephemeral\/write-only\">write-only arguments<\/a> documentation.<\/p>","protected":false},"excerpt":{"rendered":"<p>Before Terraform 1.11, working with sensitive values was a challenge \u2014 sensitive values were always persisted to the Terraform plan [&hellip;]<\/p>\n","protected":false},"author":0,"featured_media":0,"comment_status":"","ping_status":"","sticky":false,"template":"","format":"standard","meta":{"site-sidebar-layout":"default","site-content-layout":"","ast-site-content-layout":"default","site-content-style":"default","site-sidebar-style":"default","ast-global-header-display":"","ast-banner-title-visibility":"","ast-main-header-display":"","ast-hfb-above-header-display":"","ast-hfb-below-header-display":"","ast-hfb-mobile-header-display":"","site-post-title":"","ast-breadcrumbs-content":"","ast-featured-img":"","footer-sml-layout":"","ast-disable-related-posts":"","theme-transparent-header-meta":"","adv-header-id-meta":"","stick-header-meta":"","header-above-stick-meta":"","header-main-stick-meta":"","header-below-stick-meta":"","astra-migrate-meta-layouts":"default","ast-page-background-enabled":"default","ast-page-background-meta":{"desktop":{"background-color":"var(--ast-global-color-4)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"ast-content-background-meta":{"desktop":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"footnotes":""},"categories":[6],"tags":[],"class_list":["post-1810","post","type-post","status-publish","format-standard","hentry","category-terraform"],"_links":{"self":[{"href":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/wp-json\/wp\/v2\/posts\/1810","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/wp-json\/wp\/v2\/types\/post"}],"replies":[{"embeddable":true,"href":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/wp-json\/wp\/v2\/comments?post=1810"}],"version-history":[{"count":0,"href":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/wp-json\/wp\/v2\/posts\/1810\/revisions"}],"wp:attachment":[{"href":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/wp-json\/wp\/v2\/media?parent=1810"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/wp-json\/wp\/v2\/categories?post=1810"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/wp-json\/wp\/v2\/tags?post=1810"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}