Will we be able to use non-ephemeral values as input to write-only attributes?

I’m familiar with the idea that the use of attributes from an ephemeral resource is constrained: They can only be used in the config blocks for providers and provisioners, upcoming write-only attributes, maybe a few other places I’ve forgotten.

Are write-only attributes the other side of that coin? Will they only accept ephemeral values, or will we be able to feed 'em any value regardless of that value’s lineage (presence in the state)?

Obviously, using a value that’s already in the state as a secret isn’t great, but it’s not clear to me that the SDK/Framework should attempt to protect users from that footgun, because the write-only attribute didn’t create the secret-in-state problem.

Thanks!

Hey @hQnVyLRx :wave:,

I don’t believe there will be any restrictions on where write-only attributes can be sourced from, so for example, you could assign a managed resource attribute to a write-only attribute:

resource "random_password" "password" {
  length           = 16
  special          = true
  override_special = "!#$%&*()-_=+[]{}<>:?"
}

resource "aws_db_instance" "example" {
  // writeonly_password will not be stored in state, but "random_password.password.result" will
  writeonly_password = random_password.password.result
}

Obviously, using a value that’s already in the state as a secret isn’t great, but it’s not clear to me that the SDK/Framework should attempt to protect users from that footgun, because the write-only attribute didn’t create the secret-in-state problem.

Agreed. I think one way to view write-only attributes is like a termination point, any data can be fed in, but no data can flow out.

Excellent. Thank you, @austin.valle

1 Like

Oh, one more thing, @austin.valle

Will write_only attribute values be suppressed (null) when framework delivers the config to the provider’s Update() method?

Put another way… Does Write Only also imply Write Once for end users?

If there is a write-only value defined in configuration, it will always come through and be available in the (resource.UpdateRequest).Config field, so it isn’t write-once by default. It also will never be available in (resource.UpdateRequest).Plan as it will always be null.

One thing you’ll notice is that since write-only attributes are always null in state and null in plan, they won’t be able to signal user intent on their own, meaning the provider will need to potentially use a different non-write-only attribute to signal what the user’s intent actually is.

My concern is this .tf edit sequence:

User runs terraform apply, creating a thing with this configuration:

resource "thing" "example" {
  name   = "verynice thing"
  wo_val = "wo_whatever"
}

In the future, somebody bumps into the wo_val while slashing away at something else in their editor, leaving this:

resource "thing" "example" {
  name   = "verynice thing"
  wo_val = "wo_:wq!whatever"       <--- lol vim noob
}

The config change sneaks through the approvals process and then goes unnoticed by Terraform, because without state for wo_val, Terraform can’t know that an edit has happened. No plan is generated.

(so far so good?)

Later still, the Proper Capitalization and Whitespace Enforcer has their way with the config, giving us:

resource "thing" "example" {
  name   = "Very Nice Thing"      <--- very mindful, very demure
  wo_val = "wo_:wq!whatever"
}

At this point a plan will be generated. Will the PCaWE’s change to the name attribute have unintended consequences for the wo_val attribute?

It sounds like the behavior is now up to the provider developer? I don’t think I’ve ever referenced the Config element within the resource.UpdateRequest struct, so based on that pattern write_only attributes would be effectively write_once?

Yeah I think your understanding is correct, the behavior will be at the provider developer’s discretion. Write-only attributes are essentially poking an imperative hole in the declarative process of “converging config, state, and the remote system”, so when using a write-only attribute, the provider developer will have to define how exactly that imperative process should behave (like when the process should trigger).

I don’t think I’d ever noticed that resource.UpdateRequest had a Config struct element before this conversation. So, that’s interesting. I’m glad you pointed it out earlier.

Using the value from Config in Update() looks like a footgun to me.

I guess it could be mitigated by:

  • toss a new boolean attribute in there: send_wo_val_on_update
  • implement a wo_val_triggers (map[string]string) attribute
  • hash the wo_val into private state (invites brute-force attacks on secrets and conversations with auditors)

Any idea what the Hashicorp providers will do with their write_only attributes during Update()?

Using the value from Config in Update() looks like a footgun to me.

Yeah, that was what I was trying to convey in some of my earlier messages :sweat_smile:. Using just the write-only config value as an indicator that the user wants the provider to do something with said value won’t be sufficient for most resources. Any of what you described could be options since you will be able to determine intent (user modifies send_wo_val_on_update/wo_val_triggers, so we know they want to use this value). You can accurately determine if send_wo_val_on_update or wo_val_triggers has been updated because you have prior state.

  • hash the wo_val into private state (invites brute-force attacks on secrets and conversations with auditors)

This one is probably less ideal then the others as ephemeral values don’t need to be the same during plan/apply (like generating a random password). But there could be write-only attributes where this is less of a concern.

Any idea what the Hashicorp providers will do with their write_only attributes during Update() ?

Not ATM. I don’t think any of that work has started in the official providers since the actual work in the SDKs is still unreleased:

My team owns the utility providers (http, tls, time, random, etc.) but we don’t have any planned write-only attributes for them.

1 Like

Was here to ask the same thing

In particular, if using a regular random_password resource to feed an attribute like password_wo vs password, is it still important to use password_wo_version?

I’ve been getting Terraform warnings about using the write only attribute, which seems like an Ok change to make, but want to make sure there aren’t any unexpected consequences.

Presumably, since the password still exists in state, there aren’t any real consequences with making that change only (although arguably, not many benefits either)?