I'm trying to dynamically add a map of key/value pairs to the variable namespace so that I can iterate over them, creating etcd keys. I had it in mind to just create a data source which would return the map, and then I could call keys() and lookup() on the map. But the implementation details of the external data source insist that the map which gets returned from the datasource can only contain strings rather than lists or maps. But if they are just strings, then I have no way to access them dynamically from the calling template, since you cannot iterate over the returned attributes of a data source, you can only access them directly, by name. But I don't know the names. And even if I put a comma-delimited string with all of the keys in the map into one well-known output value, I still cannot get the value of each of those keys without being able to dynamically access those outputs. Is there any alternative mechanism for doing this? I already have a custom provider in order to create the etcd keys, so my choices are to put the code which loads the values at run time into that provider as a data source, if data sources implemented in Go are allowed to return maps or lists, or else I can write a resource in that provider that simply takes the source data and parses it and populates etcd all at one step.
What I'm trying to accomplish here is simply loading a bunch of config keys and their values from an S3 bucket, then populate an etcd_key resource with each pair, to write it to etcd. This way, I can have secrets stored encrypted in an S3 bucket which even the person running terraform doesn't have access to. They have access to a role which runs terraform locally in order to set up a command which runs terraform on an EC2 instance, and that EC2 instance has a role which can fetch and decrypt the contents of the file. This way, I can allow people to run certain commands without actually exposing them to decrypted secrets. But I need to have the ability to create arbitrary vars and access them dynamically in order for that to work. I'm happy to hear about other solutions to that problem, but I don't see a good one.
resource "aws_s3_bucket_object" "secret_vars_file" {
bucket = "${aws_s3_bucket.secret_config_bucket.bucket}"
key = "secrets.json"
source = "./secrets.json"
server_side_encryption = "aws:kms"
kms_key_id = "${module.kms_master_key.key_arn}"
}
data "external" "load_secret_vars" {
program = ["python", "load-vars.py"]
query = {
contents = "$[aws_s3_bucket_object.secret_vars_file.body}"
}
}
if the secret_vars_file (which is a json map with string values) contains a key of "my_key" then I can happy access ${data.external.load_secret_vars.my_key} but I cannot do things like ${lookup(data.external.load_secret_vars, element(keys(data.external.load_secret_vars), count.index))} which is what I need to be able to do for this to work.