Hi @schiermi,
The depends_on
argument in Terraform only affects the order of operations Terraform would’ve performed anyway, and so it can never cause Terraform to perform an additional operation that wasn’t required for other reasons.
In your case, it seems like the problem here is that nothing in the configuration of tls_private_key.this
changes in response to the time_rotating
resource’s timestamp and so Terraform can see that if it were changing both of those resources at once then it should work on time_rotating.this
first, but there’s never any situation where it’s necessary to update or replace tls_private_key.this
after it’s initially created because its configuration is constant.
This is a pretty tricky situation because tls_private_key
doesn’t include any arguments that explicitly relate to time, and so there’s no natural way to write out that a private key has a limited timespan… that tends to come from the certificates created from the key.
However, it could work to exploit some details of how time_rotating
works to still get the effect you wanted. Specifically, I believe (though I’ve not verified) that time_rotating
works by making the existing object “vanish” and thus need recreating once the time interval expires, at which point all of its exported time-related attributes will return to being (known after apply)
for that plan, because the time it finally records will come from the apply step instead.
This means that we can potentially cheat a little bit by tricking Terraform into thinking there’s some possibility that the algorithm
argument will change even though it will actually always still stabilize back to ECDSA again:
resource "tls_private_key" "this" {
algorithm = time_rotating.this.id != "" ? "ECDSA" : "invalid"
ecdsa_curve = "P384"
}
The final value of id
should always be a valid timestamp and thus never an empty string, so in practice that conditional can only ever return true
, but Terraform itself doesn’t know what that id
value represents and so it will see that it has an unknown value and thus conservatively conclude that it doesn’t know yet whether it’ll be empty or not, and thus algorithm
itself will become (known after apply)
, which should then prompt the hashicorp/tls
provider to plan to replace that object.
There are two main drawbacks to this approach:
-
Firstly, the configuration I shared about is not intuitive and is only understandable if you know some details of how Terraform works internally. Therefore if I were to employ this trick I’d be sure to write a detailed comment alongside that argument explaining what’s going on, so that future maintainers can understand what it’s doing and not remove the conditional thinking that it’s redundant.
-
Secondly, it does mean that on initial creation and on each rotation the Terraform plan will show algorithm = (known after apply)
, thus obscuring which algorithm this key will use and making the plan less useful.
For someone who already knows how tls_private_key
works it’s possible to infer from context that ecdsa_curve
wouldn’t be valid if algorithm
were "RSA"
, but I think it’s fair to say that the less uncertainty the better when it comes to security-sensitive things like private keys.
With that said, I don’t have a better suggestion to meet your use case within the Terraform language itself. My only other suggestion would be to handle this rotation with some automation outside of Terraform, by arranging for something to run terraform plan -replace=tls_private_key.this
every 90 days and then apply that plan to proactively cycle the key. Of course, along with the additional overhead of having some other process in place to do this, there’s the risk that the system will stop working and not be noticed and thus leave the stale key active longer than it ought to have been.