I want to do the following
Update the KMS key resource to include lifecycle precondition
If the referenced policy is null, use the constructed local policy
Add a validator for the policy that if not set and the key type is direct, then direct_key_principal should not be empty
resource "aws_kms_key" "direct_key" {
description = var.description
enable_key_rotation = true
deletion_window_in_days = var.deletion_window
policy = var.policy != null ? var.policy : data.aws_iam_policy_document.kms_key_policy_direct[0].json
key_usage = var.key_usage
customer_master_key_spec = var.customer_master_key_spec
lifecycle {
precondition {
condition = var.policy == null && var.key_type == "direct" && length(values(var.direct_key_principal)[0]) > 0
error_message = "When the policy is not set and the key type is direct, all direct_key_principal elements should be non-empty."
}
}
variable "direct_key_principal" {
description = "Principal Information - Type & Identifier required for a 'direct' key"
type = map(list(string))
default = {
AWS = []
}
validation {
condition = alltrue([for principal_type in keys(var.direct_key_principal) : contains(["AWS", "Service"], principal_type)])
error_message = "Valid values for Principal type are AWS and Service."
}
}
I get this error message below
│ 12: condition = var.policy == null && var.key_type == "direct" && length(values(var.direct_key_principal)[0]) > 0
│ ├────────────────
│ │ var.direct_key_principal is map of list of string with 1 element
│ │ var.key_type is "direct"
│ │ var.policy is "{\n \"Version\": \"2012-10-17\",\n \"Statement\": [\n {\n \"Sid\": \"\",\n \"Effect\": \"Allow\",\n \"Action\": \"kms:*\",\n \"Resource\": \"arn:aws:*:*:765862725291:*\",\n \"Principal\": {\n \"AWS\": \"arn:aws:iam::765862725291499556464691:root\"\n }\n },\n {\n \"Sid\": \"sid1\",\n \"Effect\": \"Allow\",\n \"Action\": [\n \"kms:TagResource\",\n \"kms:List*\",\n \"kms:Get*\",\n \"kms:Describe*\",\n \"kms:Decrypt\"\n ],\n \"Resource\": [\n \"arn:aws:*:*:499556464691:*\",\n \"arn:aws:*:*:999999955:*\"\n ],\n \"Principal\": {\n \"AWS\": \"999999955\"\n }\n }\n ]\n}"
│
│ When the policy is not set and the key type is direct, all
│ direct_key_principal elements should be non-empty.
This error message is correct for the condition you wrote because you've required that var.policy
be null
but we can see from the error message that it is not null.
From the error message you wrote I believe what you intended to write as the rule is that this rule is only relevant if var.policy
is null
and var.key_type
is "direct"
.
If so, you'll need to use a conditional expression to test that first and then choose between enforcing your rule or just returning true
to make the rule always pass, like this:
precondition {
condition = (
var.policy == null && var.key_type == "direct" ?
length(values(var.direct_key_principal)[0]) > 0 :
true
)
error_message = "When the policy is not set and the key type is direct, all direct_key_principal elements should be non-empty."
}
If var.policy
is null
and var.key_type
is "direct"
then Terraform will use the result of the first expression that tests whether the length is greater than zero. If either of those pre-conditions is not true then Terraform will use the result of the second expression, which is literally true
and will therefore always pass the check.
Note that your error message says "all direct_key_principal elements should be non-empty", but yet your conditional expression only tests one element of the map -- whichever one sorts first in the result from values
. Making this test apply to all of the elements is possible but beyond the scope of what you asked in this question, so if you'd like to implement that change too and you're not sure how to proceed I'd suggest starting another separate question after you've verified that my answer above works for avoiding the error you asked about.