Skip to content

Instantly share code, notes, and snippets.

@jimbo8098
Last active July 12, 2023 12:02
Show Gist options
  • Save jimbo8098/970daa0bd924289ec43846caa5dccfc8 to your computer and use it in GitHub Desktop.
Save jimbo8098/970daa0bd924289ec43846caa5dccfc8 to your computer and use it in GitHub Desktop.
Complex variable validations in Terraform 1.5.x
output "variable" {
value = var.extra_secrets_maps
}
output "variable_secrets" {
value = [for m in var.extra_secrets_maps: m.secrets]
}
output "variable_serviceaccounts" {
value = [for m in var.extra_secrets_maps: m.namespace_serviceaccounts]
}
output "variable_serviceaccounts_map" {
value = {for k,m in var.extra_secrets_maps: k => m.namespace_serviceaccounts}
}
# We can see that the key can be generated on the list object - that each object in the array in itself becomes an array map (rather than just outputting the same array contents)
output "variable_serviceaccounts_sa" {
value = {for k,m in var.extra_secrets_maps: k => {for k,n_sa in m.namespace_serviceaccounts : k => n_sa}}
}
output "variable_serviceaccounts_sa_contains" {
value = {for k,m in var.extra_secrets_maps: k => {for k,n_sa in m.namespace_serviceaccounts : k => strcontains(n_sa,":")}}
}
# Ensure all variables have a ":". Comment the "invalid" one to get this to be true. Otherwise the result for it each role will be false.
output "variable_serviceaccounts_sa_contains_summary" {
value = {for k,m in var.extra_secrets_maps: k => alltrue([for k,n_sa in m.namespace_serviceaccounts : strcontains(n_sa,":")])}
}
# Output a true/false value depending on the validity of the namespace_serviceaccounts in each of the role definitions
output "variable_serviceaccounts_valid_summary" {
value = [for k,m in var.extra_secrets_maps: alltrue([for k,n_sa in m.namespace_serviceaccounts : strcontains(n_sa,":")])]
}
# Output a general true/false which indicates a valid namespace_service_account in ALL role definitions
output "variable_serviceaccounts_overall_valid_summary" {
value = alltrue([for k,m in var.extra_secrets_maps: alltrue([for k,n_sa in m.namespace_serviceaccounts : strcontains(n_sa,":")])])
}
# Consider a situation where a list of map of IRSA roles are used to access a list of secrets. This is the case for CSI Secrets Store
# providers for example - the use case of this validation. We output a list of roles, each with their own list of Kubernetes services
# accounts, in the format namespace:service_account. This allows configuration of the OIDC connector's audience to ensure that the
# correctly namespaced service accounts can access given IRSA roles, and therefore secrets.
variable "extra_secrets_maps" {
description = "An extra list of service accounts (on top of the service-specific ones created during each specific application's setup) and the secret ARNs which they should have access to"
type = map(object({
secrets = list(string)
namespace_serviceaccounts = list(string)
policy_name = string
}))
default = null
# uncomment to use validation rule
#validation {
# condition = alltrue([for k,m in var.extra_secrets_maps: alltrue([for k,n_sa in m.namespace_serviceaccounts : strcontains(n_sa,":")])])
# error_message = "Secrets in the secret map should be in the format <namespace>:<service_account>, e.g default:deployment-sa"
#}
}
extra_secrets_maps = {
"correct_role" = {
secrets = ["arn:aws:secretsmanager:eu-west-1:0000000000000:secret:/asecret"]
namespace_serviceaccounts = [
"namespace:serviceaccount",
"namespace:otherserviceaccount",
]
policy_name = "policy_name"
},
"invalid_role" = {
secrets = ["arn:aws:secretsmanager:eu-west-1:0000000000000:secret:/asecret"]
namespace_serviceaccounts = [
"namespace:serviceaccount",
"namespace:otherserviceaccount",
"namespaceinvalidserviceaccount"
]
policy_name = "policy_name"
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment