-
Notifications
You must be signed in to change notification settings - Fork 9.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
rd/aws_instance and rd/aws_launch_template: Add support for metadata_options #11076
Conversation
It was confirmed in the SEC310 reInvent session that launch template support is due in the next few weeks: https://youtu.be/2B5bhZzayjI?t=1966 |
…form-provider-aws into metadata_options
…_response_hop_limit.
It seems that the launch template support was launched without being announced anywhere (at least not as far as I could see). I just looked for it in the API docs today, and I saw that it had been added. I spent some time to add the launch template support, so I think this PR is ready for review now. My
I suspect this is because the metadata options are "pending" before fully applied to the launch template? It may be an error (i.e. copy-paste from the EC2 instances API), since there's something called Anyway, let me know what to do here. Thanks. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hey @stefansundin 👋 Thank you for submitting this. I left some initial feedback below. Please take a look and reach out if you have any questions or do not have time to implement the items.
mo["http_put_response_hop_limit"] = instance.MetadataOptions.HttpPutResponseHopLimit | ||
var metadataOptions []map[string]interface{} | ||
metadataOptions = append(metadataOptions, mo) | ||
d.Set("metadata_options", metadataOptions) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When using d.Set()
with aggregate types (TypeList, TypeSet, TypeMap), we should perform error checking to prevent issues where the code is not properly able to set the Terraform state. e.g.
d.Set("metadata_options", metadataOptions) | |
if err := d.Set("metadata_options", metadataOptions); err != nil { | |
return fmt.Errorf("error setting metadata_options: %s", err) | |
} |
The existing code may not be working since the map elements have pointer types, which can be fixed by wrapping the response fields with aws.StringValue()
, aws.Int64Value()
, etc.
@@ -450,6 +453,11 @@ resource "aws_instance" "test" { | |||
# us-west-2 | |||
ami = "ami-4fccb37f" | |||
instance_type = "m1.small" | |||
metadata_options { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of modifying an existing test function and test configuration, can you please create a new test and configuration so we can ensure there are no regressions with existing functionality? Copy-paste-modify is fine. Thanks. 👍
@@ -132,3 +132,10 @@ func suppressRoute53ZoneNameWithTrailingDot(k, old, new string, d *schema.Resour | |||
} | |||
return strings.TrimSuffix(old, ".") == strings.TrimSuffix(new, ".") | |||
} | |||
|
|||
func suppressMetadataOptionsHttpEndpointDisabled(k, old, new string, d *schema.ResourceData) bool { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of introducing new difference suppression, we may want to instead mark attributes that need this with Computed: true
instead.
@@ -518,6 +518,36 @@ func resourceAwsInstance() *schema.Resource { | |||
}, | |||
}, | |||
}, | |||
|
|||
"metadata_options": { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In some unrelated testing today, it appears EC2 Instances can include this in their API response by default. Instead of requiring all operators to always include this new configuration, we should mark this attribute with Computed: true
.
Default: ec2.HttpTokensStateOptional, | ||
ValidateFunc: validation.StringInSlice([]string{ec2.HttpTokensStateOptional, ec2.HttpTokensStateRequired}, false), | ||
DiffSuppressFunc: suppressMetadataOptionsHttpEndpointDisabled, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See note above about potentially replacing Default
and DiffSuppressFunc
here with Computed: true
instead.
Default: 1, | ||
ValidateFunc: validation.IntBetween(1, 64), | ||
DiffSuppressFunc: suppressMetadataOptionsHttpEndpointDisabled, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See note above about potentially replacing Default
and DiffSuppressFunc
here with Computed: true
instead.
mo["http_put_response_hop_limit"] = instance.MetadataOptions.HttpPutResponseHopLimit | ||
var metadataOptions []map[string]interface{} | ||
metadataOptions = append(metadataOptions, mo) | ||
d.Set("metadata_options", metadataOptions) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same note here regarding error checking. It may be easier to instead make this into a "flatten" function to be shared, e.g.
func flattenEc2InstanceMetadataOptions(opts *ec2.MetadataOptions) []interface{} {
if opts == nil {
return nil
}
m := map[string]interface{}{
"http_endpoint": aws.StringValue(opts.HttpEndpoint),
"http_put_response_hop_limit": aws.Int64Value(opts.HttpPutResponseHopLimit),
"http_tokens": aws.StringValue(opts.HttpTokens),
}
return []interface{}{m}
}
// ...
if err := d.Set("metadata_options", flattenEc2InstanceMetadataOptions(instance.MetadataOptions)); err != nil {
return fmt.Errorf("error setting metadata_options: %s", err)
}
if mo, ok := v.([]interface{})[0].(map[string]interface{}); ok { | ||
opts.MetadataOptions = &ec2.InstanceMetadataOptionsRequest{ | ||
HttpEndpoint: aws.String(mo["http_endpoint"].(string)), | ||
} | ||
if mo["http_endpoint"].(string) == ec2.InstanceMetadataEndpointStateEnabled { | ||
// These parameters are not allowed unless HttpEndpoint is enabled | ||
opts.MetadataOptions.HttpTokens = aws.String(mo["http_tokens"].(string)) | ||
opts.MetadataOptions.HttpPutResponseHopLimit = aws.Int64(int64(mo["http_put_response_hop_limit"].(int))) | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Similar to creating a flatten function above, the inverse expand function could be created and used in the multiple places with this logic:
func expandEc2InstanceMetadataOptions(l []interface{}) *ec2.MetadataOptions {
m, ok := l[0].(map[string]interface{})
if !ok {
return nil
}
opts := &ec2.InstanceMetadataOptionsRequest{
HttpEndpoint: aws.String(m["http_endpoint"].(string)),
}
if m["http_endpoint"].(string) == ec2.InstanceMetadataEndpointStateEnabled {
// These parameters are not allowed unless HttpEndpoint is enabled
if v, ok := m["http_tokens"].(string); ok && v != "" {
opts.HttpTokens = aws.String(v)
}
if v, ok := m["http_put_response_hop_limit"].(int); ok && v != 0 {
opts.HttpPutResponseHopLimit = aws.Int64(int64(v))
}
}
return opts
}
// ...
MetadataOptions: expandEc2InstanceMetadataOptions(d.Get("metadata_options").([]interface{})),
@@ -2814,6 +2817,12 @@ resource "aws_instance" "test" { | |||
instance_type = "m1.small" | |||
security_groups = ["${aws_security_group.tf_test_test.name}"] | |||
user_data = "foo:-with-character's" | |||
|
|||
metadata_options { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please create a new test function and test configuration so we can verify existing testing for regressions.
@@ -978,6 +979,12 @@ resource "aws_launch_template" "test" { | |||
|
|||
key_name = "test" | |||
|
|||
metadata_options { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here about creating a separate test function and configuration.
@stefansundin Will you have a chance to address the review comments? |
@stefansundin I have addressed @bflad's review comments via #12491. |
I'm going to lock this issue because it has been closed for 30 days ⏳. This helps our maintainers find and focus on the active issues. If you feel this issue should be reopened, we encourage creating a new issue linking back to this one for added context. Thanks! |
This adds support to set the Metadata Options options for an EC2 instance. TL;DR: opt-in to a more secure metadata service.
Documentation:
I am hopeful that they will add support for this to launch templates as well, but it seems like this has not happened yet. We can wait a few weeks to see if it comes out after reInvent.
Please let me know what you want to be changed. I'm not sure to what extent you want this to be tested. I've been testing this a bit and it is working well. I was unsure if you wanted the
state
attribute to be made available?Community Note
Release note for CHANGELOG:
Output from acceptance testing: