-
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
resource/aws_elasticsearch_domain: Add support for encrypt_at_rest #2632
Changes from 4 commits
69a87dc
793f0f1
5d1b545
ca73236
a56d511
60a99c4
a13f2a9
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -13,6 +13,7 @@ import ( | |
"github.com/hashicorp/errwrap" | ||
"github.com/hashicorp/terraform/helper/resource" | ||
"github.com/hashicorp/terraform/helper/schema" | ||
"strings" | ||
) | ||
|
||
func resourceAwsElasticSearchDomain() *schema.Resource { | ||
|
@@ -89,6 +90,27 @@ func resourceAwsElasticSearchDomain() *schema.Resource { | |
}, | ||
}, | ||
}, | ||
"encrypt_at_rest": { | ||
Type: schema.TypeList, | ||
Optional: true, | ||
Computed: true, | ||
Elem: &schema.Resource{ | ||
Schema: map[string]*schema.Schema{ | ||
"enabled": { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What purpose does this
IMHO makes the implementation way simpler There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I was mirroring the API which takes those as options. I did consider setting it automatically when kms_key_id is set but it would prevent you from having Terraform encrypt it with the service KMS key that you get by default when using the console to create an encrypted domain. The There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yea true. Does AWS API create a default key if only For example, when adding triggers to lambda functions via aws console, aws does a lot of stuff in the background like creating IAM roles and adding policies and stuff. However in Terraform we don't do it and all the resources required to trigger a lambda function must be created. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah looks like it does, added a test that runs without specifying the key id and that works nicely without needing to do anything extra which is neat. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Lovely! :) |
||
Type: schema.TypeBool, | ||
Required: true, | ||
ForceNew: true, | ||
}, | ||
"kms_key_id": { | ||
Type: schema.TypeString, | ||
Optional: true, | ||
Computed: true, | ||
ForceNew: true, | ||
DiffSuppressFunc: suppressEquivalentKmsKeyIds, | ||
}, | ||
}, | ||
}, | ||
}, | ||
"cluster_config": { | ||
Type: schema.TypeList, | ||
Optional: true, | ||
|
@@ -291,6 +313,21 @@ func resourceAwsElasticSearchDomainCreate(d *schema.ResourceData, meta interface | |
} | ||
} | ||
|
||
if v, ok := d.GetOk("encrypt_at_rest"); ok { | ||
options := v.([]interface{}) | ||
|
||
if len(options) > 1 { | ||
return fmt.Errorf("Only a single encrypt_at_rest block is expected") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think we should also validate the instance types here since, like you mentioned, not all instance types support encryption at rest. I saw a similar approach in There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think that will run at plan time though so it's just returning a different error to what you'll get from the AWS API on apply time. You already get the following error on apply (and immediately):
From memory the validatefuncs in the schema can't validate different parameters to a resource (so you can't put a validatefunc on the encrypted parameter that checks what the instance_type is set to) so we can't put it there unfortunately to give us a plan time failure. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. (Also, hardcoding what instance types support encryption in the provider means that the list has to be re-synchronized if it changes, and people need to wait for a new release of the provider, or you have to give them an override command-line flag... Too much complexity for little benefit, IMO!) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I agree with @Puneeth-n here that we should move validation to the schema here. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That's nice, means I can remove some logic there. Is it worth doing the same to some of the other blocks that are using that other style? Or (if you do want it changing) would you prefer that in a separate PR? |
||
} else if len(options) == 1 { | ||
if options[0] == nil { | ||
return fmt.Errorf("At least one field is expected inside encrypt_at_rest") | ||
} | ||
|
||
s := options[0].(map[string]interface{}) | ||
input.EncryptionAtRestOptions = expandESEncryptAtRestOptions(s) | ||
} | ||
} | ||
|
||
if v, ok := d.GetOk("cluster_config"); ok { | ||
config := v.([]interface{}) | ||
|
||
|
@@ -461,6 +498,10 @@ func resourceAwsElasticSearchDomainRead(d *schema.ResourceData, meta interface{} | |
if err != nil { | ||
return err | ||
} | ||
err = d.Set("encrypt_at_rest", flattenESEncryptAtRestOptions(ds.EncryptionAtRestOptions)) | ||
if err != nil { | ||
return err | ||
} | ||
err = d.Set("cluster_config", flattenESClusterConfig(ds.ElasticsearchClusterConfig)) | ||
if err != nil { | ||
return err | ||
|
@@ -674,3 +715,10 @@ func resourceAwsElasticSearchDomainDelete(d *schema.ResourceData, meta interface | |
|
||
return err | ||
} | ||
|
||
func suppressEquivalentKmsKeyIds(k, old, new string, d *schema.ResourceData) bool { | ||
// The Elasticsearch API accepts a short KMS key id but always returns the ARN of the key. | ||
// The ARN is of the format 'arn:aws:kms:REGION:ACCOUNT_ID:key/KMS_KEY_ID'. | ||
// These should be treated as equivalent. | ||
return strings.Contains(old, new) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1045,6 +1045,32 @@ func expandESEBSOptions(m map[string]interface{}) *elasticsearch.EBSOptions { | |
return &options | ||
} | ||
|
||
func flattenESEncryptAtRestOptions(o *elasticsearch.EncryptionAtRestOptions) []map[string]interface{} { | ||
m := map[string]interface{}{} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you also add a We can just return empty There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not sure I follow that, what would cause the crash? If There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
No, it will crash on line 1052 in such case because that condition is trying to access a field of a struct which isn't struct, but There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Right, sorry, completely missed that for some reason. Fixed now, thanks for the review. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No worries 😸 That's why we do reviews. |
||
|
||
if o.Enabled != nil { | ||
m["enabled"] = *o.Enabled | ||
} | ||
if o.KmsKeyId != nil { | ||
m["kms_key_id"] = *o.KmsKeyId | ||
} | ||
|
||
return []map[string]interface{}{m} | ||
} | ||
|
||
func expandESEncryptAtRestOptions(m map[string]interface{}) *elasticsearch.EncryptionAtRestOptions { | ||
options := elasticsearch.EncryptionAtRestOptions{} | ||
|
||
if v, ok := m["enabled"]; ok { | ||
options.Enabled = aws.Bool(v.(bool)) | ||
} | ||
if v, ok := m["kms_key_id"]; ok && v.(string) != "" { | ||
options.KmsKeyId = aws.String(v.(string)) | ||
} | ||
|
||
return &options | ||
} | ||
|
||
func flattenESVPCDerivedInfo(o *elasticsearch.VPCDerivedInfo) []map[string]interface{} { | ||
m := map[string]interface{}{} | ||
|
||
|
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.
Nitpick: Do you mind moving this import above? We tend to follow the convention of grouping stdlib imports and keeping them at the top per https://github.com/golang/go/wiki/CodeReviewComments#imports
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.
Aha, didn't spot that
gofmt
and/or Goland's import optimiser doesn't do this for you. Seems odd thatgoimports
seems to add newlines between stdlib stuff when adding it and thengofmt
won't rectify that either which is annoying consideringgofmt
is so good otherwise.