-
Notifications
You must be signed in to change notification settings - Fork 9.2k
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
Sort ACM cert subject alternative names and domain validation opts #8708
Changes from all commits
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 |
---|---|---|
|
@@ -210,15 +210,16 @@ func resourceAwsAcmCertificateRead(d *schema.ResourceData, meta interface{}) err | |
d.Set("domain_name", resp.Certificate.DomainName) | ||
d.Set("arn", resp.Certificate.CertificateArn) | ||
|
||
if err := d.Set("subject_alternative_names", cleanUpSubjectAlternativeNames(resp.Certificate)); err != nil { | ||
sans := readSubjectAlternativeNames(resp.Certificate, d) | ||
if err := d.Set("subject_alternative_names", sans); err != nil { | ||
return resource.NonRetryableError(err) | ||
} | ||
|
||
domainValidationOptions, emailValidationOptions, err := convertValidationOptions(resp.Certificate) | ||
|
||
if err != nil { | ||
return resource.RetryableError(err) | ||
} | ||
sortDomainValidationOptions(d.Get("domain_name").(*string), sans, domainValidationOptions) | ||
|
||
if err := d.Set("domain_validation_options", domainValidationOptions); err != nil { | ||
return resource.NonRetryableError(err) | ||
|
@@ -244,6 +245,7 @@ func resourceAwsAcmCertificateRead(d *schema.ResourceData, meta interface{}) err | |
return nil | ||
}) | ||
} | ||
|
||
func resourceAwsAcmCertificateGuessValidationMethod(domainValidationOptions []map[string]interface{}, emailValidationOptions []string) string { | ||
// The DescribeCertificate Response doesn't have information on what validation method was used | ||
// so we need to guess from the validation options we see... | ||
|
@@ -275,16 +277,43 @@ func resourceAwsAcmCertificateUpdate(d *schema.ResourceData, meta interface{}) e | |
return resourceAwsAcmCertificateRead(d, meta) | ||
} | ||
|
||
func cleanUpSubjectAlternativeNames(cert *acm.CertificateDetail) []string { | ||
sans := cert.SubjectAlternativeNames | ||
vs := make([]string, 0) | ||
for _, v := range sans { | ||
if aws.StringValue(v) != aws.StringValue(cert.DomainName) { | ||
vs = append(vs, aws.StringValue(v)) | ||
// readSubjectAlternativeNames returns all subject alternative names (SANs) | ||
// fetched from remote in cert but ordered according to user-defined state. | ||
// Also, the domain_name is excluded from the result. | ||
// | ||
// Sorting keeps the state stable and is necessary because the API may return | ||
// SANS ordred differetnly from request to request. | ||
func readSubjectAlternativeNames(cert *acm.CertificateDetail, d *schema.ResourceData) []string { | ||
remotes := cert.SubjectAlternativeNames | ||
sans := make([]string, 0) | ||
|
||
// intersection of all SANs, user defined (ud) and remote. ordered as user defined (ud) in state. | ||
for _, ud := range d.Get("subject_alternative_names").([]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. I like this idea to have the certificates ordered as defined by user. 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 tried to use this PR as well, and had issues with it. I have created a new pull request that should address the problems: #10791 |
||
san := ud.(string) | ||
for _, r := range remotes { | ||
if san == aws.StringValue(r) { | ||
sans = append(sans, san) | ||
break | ||
} | ||
} | ||
} | ||
|
||
// append SANs exsting only in slice fetched from remote. exclude domainName. | ||
for _, r := range remotes { | ||
san := aws.StringValue(r) | ||
found := false | ||
for _, ud := range sans { | ||
if san == ud { | ||
found = true | ||
break | ||
} | ||
} | ||
if !found && san != aws.StringValue(cert.DomainName) { | ||
sans = append(sans, san) | ||
} | ||
} | ||
return vs | ||
|
||
return sans | ||
} | ||
|
||
func convertValidationOptions(certificate *acm.CertificateDetail) ([]map[string]interface{}, []string, error) { | ||
|
@@ -315,6 +344,29 @@ func convertValidationOptions(certificate *acm.CertificateDetail) ([]map[string] | |
return domainValidationResult, emailValidationResult, nil | ||
} | ||
|
||
// sortDomainValidationOptions sorts a slice of domain validation options | ||
// according to the order of domain names in the subject alternatnive names slice | ||
func sortDomainValidationOptions(domainName *string, subjectAlterntaiveNames []string, domainValidationOptions []map[string]interface{}) { | ||
sans := append([]string{*domainName}, subjectAlterntaiveNames...) | ||
|
||
// validation method is email and domainValidationOptions is empty | ||
if len(sans) != len(domainValidationOptions) { | ||
return | ||
} | ||
|
||
// This works because the requesting a certificate is either by email or by dns, | ||
// but not mixed and furthermore the method cannot be changed after creation. | ||
for i, san := range sans { | ||
for j, opt := range domainValidationOptions { | ||
if san == opt["domain_name"].(string) { | ||
domainValidationOptions[i], domainValidationOptions[j] = | ||
domainValidationOptions[j], domainValidationOptions[i] | ||
break | ||
} | ||
} | ||
} | ||
} | ||
|
||
func resourceAwsAcmCertificateDelete(d *schema.ResourceData, meta interface{}) error { | ||
acmconn := meta.(*AWSClient).acmconn | ||
|
||
|
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.
I tried to use this patch with terraform-provider-aws v2.23.0, but unfortunately it failed with an error.
I'm not an expert in golang, however it looks to me that
d.Get("domain_name")
returns juststring
, not*string
.So changing the type of
domainName
from*string
tostring
worked for me.