terraform-plugin-sdk
terraform-plugin-sdk copied to clipboard
Schema validation fails when RequiredWith attributes are combined with DefaultFunc
SDK version
v2.16.0
I know this isn't the latest version, but it's the version specified in the go.mod file of github.com/hashicorp/terraform-provider-vault v3.10.0 (latest) and the relevant pieces of code do not appear to have changed since this version.
Relevant provider source code
The Vault provider's auth_login_aws
attribute has attributes aws_access_key_id
and aws_secret_access_key
and uses RequiredWith
to assert that they must be set together. Schemata for these fields are defined in internal/provider/auth_aws.go:
// static credential fields
consts.FieldAWSAccessKeyID: {
Type: schema.TypeString,
Optional: true,
Description: `The AWS access key ID.`,
DefaultFunc: schema.EnvDefaultFunc("AWS_ACCESS_KEY_ID", nil),
},
consts.FieldAWSSecretAccessKey: {
Type: schema.TypeString,
Optional: true,
Description: `The AWS secret access key.`,
DefaultFunc: schema.EnvDefaultFunc("AWS_SECRET_ACCESS_KEY", nil),
RequiredWith: []string{fmt.Sprintf("%s.0.%s", authField, consts.FieldAWSAccessKeyID)},
},
The validator in play is validateRequiredWithAttribute()
in helper/schema/schema.go:
func validateRequiredWithAttribute(
k string,
schema *Schema,
c *terraform.ResourceConfig) error {
if len(schema.RequiredWith) == 0 {
return nil
}
allKeys := removeDuplicates(append(schema.RequiredWith, k))
sort.Strings(allKeys)
for _, key := range allKeys {
if _, ok := c.Get(key); !ok {
return fmt.Errorf("%q: all of `%s` must be specified", k, strings.Join(allKeys, ","))
}
}
return nil
}
(*ResourceConfig).Get()
calls (*ResourceConfig).get()
which I won't reproduce here.
Terraform Configuration Files
provider "vault" {
address = "http://my.vault.host:8200"
skip_tls_verify = true
auth_login_aws {
role = "my-role"
header_value = local.aws_auth_header
}
}
Debug Output
I've encrypted the output of TF_LOG=trace terraform validate
with Hashicorp's PGP key 72D7468F
and uploaded the result as a Gist here.
Expected Behavior
provider "vault" {
address = "http://my.vault.host:8200"
skip_tls_verify = true
auth_login_aws {
role = "my-role"
header_value = local.aws_auth_header
}
}
When the environment variables AWS_ACCESS_KEY_ID
and AWS_SECRET_ACCESS_KEY
are set, the provider configuration above is valid and well-formed. Validation of the auth_login_aws
attribute should succeed even though its aws_access_key_id
and aws_secret_access_key
attributes are not set.
As far as I can tell, this happens because validateRequiredWithAttribute()
does not take the default values for these attributes as provided by their DefaultFunc
s into account.
Actual Behavior
Validation of the auth_login_aws
attribute fails:
╷
│ Error: Missing required argument
│
│ with provider["registry.terraform.io/hashicorp/vault"],
│ on providers.tf line 13, in provider "vault":
│ 13: auth_login_aws {
│
│ "auth_login_aws.0.aws_secret_access_key": all of `auth_login_aws.0.aws_access_key_id,auth_login_aws.0.aws_secret_access_key` must be specified
╵
Steps to Reproduce
- Create a Terraform environment that includes the Vault provider as configured above.
- Set values (doesn't matter what) for environment variables
AWS_ACCESS_KEY_ID
andAWS_SECRET_ACCESS_KEY
. - Run any Terraform command that validates the configuration, e.g.
terraform validate
,terraform plan
, orterraform apply
. - Observe failure.
References
- https://github.com/hashicorp/terraform-plugin-sdk/pull/342
https://support.hashicorp.com/hc/en-us/articles/4547786359571-Reading-and-using-environment-variables-in-Terraform-runs
This page has a work around
https://support.hashicorp.com/hc/en-us/articles/4547786359571-Reading-and-using-environment-variables-in-Terraform-runs
This page has a work around
Unfortunately, the above-mentioned article does not work as a workaround in this case because it ends up putting sensitive AWS credentials in the statefile that otherwise would not be there.