hashicorp / terraform-provider-aws

The AWS Provider enables Terraform to manage AWS resources.
https://registry.terraform.io/providers/hashicorp/aws
Mozilla Public License 2.0
9.78k stars 9.13k forks source link

Support StringList for "aws_ssm_association" parameters | AWS-JoinDirectoryServiceDomain #16469

Open ghost opened 3 years ago

ghost commented 3 years ago

This issue was originally opened by @rp42mt as hashicorp/terraform#27047. It was migrated here as a result of the provider split. The original body of the issue is below.


Current Terraform Version

0.13.4

Use-cases

Currently terrform throws an error if more than one IP address is specified for AWS-JoinDirectoryServiceDomain, parameter "dnsIpAddresses" because only String Type is supported: https://github.com/hashicorp/terraform-provider-aws/blob/3b002dfdfaa672c7e2527c1dfd322723b394e624/aws%2Fresource_aws_ssm_association.go#L66

This is working, but only with a single IP specified:

resource "aws_ssm_association" "identifier" {
  name             = "AWS-JoinDirectoryServiceDomain"
  association_name = "JoinDirectoryServiceDomain"

  parameters = {
    directoryId    = "AWS-directory-ID"
    directoryName  = "DirectoryName"
    directoryOU    = "OU-DN"
    dnsIpAddresses = "198.51.100.1"
  }

  targets {
    key    = "InstanceIds"
    values = [aws_instance.<windows-instance>.id]
    }
}

Attempted Solutions

Because of the parameter name "dnsIpAddresses" a StringList should be supported:

dnsIpAddresses = ["198.51.100.1","198.51.100.2"]

Proposal

StringList should be in a format like ["198.51.100.1","198.51.100.2"]

resource "aws_ssm_association" "identifier" {
name             = "AWS-JoinDirectoryServiceDomain"
association_name = "JoinDirectoryServiceDomain"

parameters = {
    directoryId    = "AWS-directory-ID"
    directoryName  = "DirectoryName"
    directoryOU    = "OU-DN"
    dnsIpAddresses =  ["198.51.100.1","198.51.100.2"] 
   }

  targets {
    key    = "InstanceIds"
    values = [aws_instance.windows-instance.id]
    }
}

References

https://aws.amazon.com/de/blogs/security/how-to-configure-your-ec2-instances-to-automatically-join-a-microsoft-active-directory-domain/ https://docs.aws.amazon.com/systems-manager/latest/userguide/ssm-plugins.html#aws-domainJoin

Old. closed issue (why?): https://github.com/hashicorp/terraform-provider-aws/issues/1889#issuecomment-548210587

rp42mt commented 3 years ago

Do you have any update on that issue? Will it be fixed to list(string)? If yes, with which provider version?

anthonyagresta commented 3 years ago

This is indeed still absolutely a showstopper to actually using the aws_ssm_association resource. I would love to see this fixed.

tmccombs commented 2 years ago

Is there any workaround for this?

tmccombs commented 2 years ago

It looks like the provider SDK still doesn't support a schema that accepts the equivalent of any (although I don't know why that is).

However, what if you could set the parametrs using a json string, so you could use jsonencode(...) to populate the data.

jeremymcgee73 commented 2 years ago

I just ran into this as well. You can create the document with hard set parameters. But, thats not as nice. I am wanting to use an AWS managed SSM document.

JordanLoehr commented 2 years ago

I've recently run into this too trying to use the AWS-RunShellCommand document, the commands parameter expects a StringList, but we can only pass a String value via terraform. Perhaps there is some weird history with this API, but its odd to me that the terraform provider set the value element type to just String in the first place, as the APIs for CreateAssociation, UpdateAssociation, and DescribeAssociation all take/return a StringList for any of the parameter map values.

"Parameters": { "string" : [ "string" ] },

Even in the current provider code, we see it takes our string value, and turns it into StringList with a single element (in the expandDocumentParameters function) to pass to the go SDK / AWS API:

"parameters": {
        Type:     schema.TypeMap,
        Optional: true,
        Computed: true,
        Elem:     &schema.Schema{Type: schema.TypeString},
    },
....
if v, ok := d.GetOk("parameters"); ok {
        associationInput.Parameters = expandDocumentParameters(v.(map[string]interface{}))
    }
....
func expandDocumentParameters(params map[string]interface{}) map[string][]*string {
    var docParams = make(map[string][]*string)
    for k, v := range params {
        values := make([]*string, 1)
        values[0] = aws.String(v.(string))
        docParams[k] = values
    }

    return docParams
}

Unfortunately this wasn't just StringList to begin with since it has to convert it internally, having it as string breaks the ability to use anything that legitimately needs a StringList. Unless the terraform provider sdk adds a Union or Any type schema, changing this to StringList will break backwards compatibility as any one using parameters with straight strings will need to update their templates to wrap it in a list themselves, eg:

resource "aws_ssm_association" "identifier" {
  name             = "AWS-JoinDirectoryServiceDomain"
  association_name = "JoinDirectoryServiceDomain"

  parameters = {
    directoryId    = ["AWS-directory-ID"]
    directoryName  = ["DirectoryName"]
    directoryOU    = ["OU-DN"]
    dnsIpAddresses = ["198.51.100.1"]
  }

  targets {
    key    = "InstanceIds"
    values = [aws_instance.<windows-instance>.id]
    }
}
tmccombs commented 2 years ago

It could be done in a backwards compatible way by creating a new attribute and deprecating the current one.

et304383 commented 1 year ago

Can we get an official answer on this one? This was designed wrong from the start, so you should fix it to be a proper list, and internally if you receive a string you convert to a list with one element, otherwise you pass the list as is. No backwards compatibility needed (no new fields please).

tmccombs commented 1 year ago

if you receive a string you convert to a list with one element

Unfortunately, I don't think that is possible to do with the terraform provider API. The schema for a resource doesn't allow you to specify a union type or an any type. This is, IMO, a significant failing of the provider system.

g-psantos commented 1 year ago

FYI, a workaround that has worked for us is to create a separate aws_ssm_parameter resource of type StringList and then reference it in the aws_ssm_association parameters as {{ ssm:[parameter name] }}.