Skip to content
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

Add activation of ACMPCA CA to acceptance tests #13684

Merged
merged 2 commits into from
Aug 21, 2020
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion aws/resource_aws_acmpca_certificate_authority.go
Original file line number Diff line number Diff line change
Expand Up @@ -425,7 +425,10 @@ func resourceAwsAcmpcaCertificateAuthorityRead(d *schema.ResourceData, meta inte
tags, err := keyvaluetags.AcmpcaListTags(conn, d.Id())

if err != nil {
return fmt.Errorf("error listing tags for ACMPCA Certificate Authority (%s): %s", d.Id(), err)
if !isAWSErr(err, acmpca.ErrCodeInvalidStateException, "") {
ewbankkit marked this conversation as resolved.
Show resolved Hide resolved
// InvalidStateException: The certificate authority is in the DELETED state and must be restored to complete this action.
return fmt.Errorf("error listing tags for ACMPCA Certificate Authority (%s): %s", d.Id(), err)
}
}

if err := d.Set("tags", tags.IgnoreAws().IgnoreConfig(ignoreTagsConfig).Map()); err != nil {
Expand Down
197 changes: 131 additions & 66 deletions aws/resource_aws_acmpca_certificate_authority_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (

"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/acmpca"
"github.com/hashicorp/go-multierror"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
"github.com/hashicorp/terraform-plugin-sdk/v2/terraform"
Expand All @@ -23,7 +24,7 @@ func init() {
func testSweepAcmpcaCertificateAuthorities(region string) error {
client, err := sharedClientForRegion(region)
if err != nil {
return fmt.Errorf("error getting client: %s", err)
return fmt.Errorf("error getting client: %w", err)
}
conn := client.(*AWSClient).acmpcaconn

Expand All @@ -33,31 +34,52 @@ func testSweepAcmpcaCertificateAuthorities(region string) error {
log.Printf("[WARN] Skipping ACMPCA Certificate Authorities sweep for %s: %s", region, err)
return nil
}
return fmt.Errorf("Error retrieving ACMPCA Certificate Authorities: %s", err)
return fmt.Errorf("Error retrieving ACMPCA Certificate Authorities: %w", err)
}
if len(certificateAuthorities) == 0 {
log.Print("[DEBUG] No ACMPCA Certificate Authorities to sweep")
return nil
}

var sweeperErrs *multierror.Error

for _, certificateAuthority := range certificateAuthorities {
arn := aws.StringValue(certificateAuthority.Arn)

if aws.StringValue(certificateAuthority.Status) == acmpca.CertificateAuthorityStatusActive {
log.Printf("[INFO] Disabling ACMPCA Certificate Authority: %s", arn)
_, err := conn.UpdateCertificateAuthority(&acmpca.UpdateCertificateAuthorityInput{
CertificateAuthorityArn: aws.String(arn),
Status: aws.String(acmpca.CertificateAuthorityStatusDisabled),
})
if isAWSErr(err, acmpca.ErrCodeResourceNotFoundException, "") {
continue
}
if err != nil {
sweeperErr := fmt.Errorf("error disabling ACMPCA Certificate Authority (%s): %w", arn, err)
log.Printf("[ERROR] %s", sweeperErr)
sweeperErrs = multierror.Append(sweeperErrs, sweeperErr)
continue
}
}

log.Printf("[INFO] Deleting ACMPCA Certificate Authority: %s", arn)
input := &acmpca.DeleteCertificateAuthorityInput{
_, err := conn.DeleteCertificateAuthority(&acmpca.DeleteCertificateAuthorityInput{
CertificateAuthorityArn: aws.String(arn),
PermanentDeletionTimeInDays: aws.Int64(int64(7)),
})
if isAWSErr(err, acmpca.ErrCodeResourceNotFoundException, "") {
continue
}

_, err := conn.DeleteCertificateAuthority(input)
if err != nil {
if isAWSErr(err, acmpca.ErrCodeResourceNotFoundException, "") {
continue
}
log.Printf("[ERROR] Failed to delete ACMPCA Certificate Authority (%s): %s", arn, err)
sweeperErr := fmt.Errorf("error deleting ACMPCA Certificate Authority (%s): %w", arn, err)
log.Printf("[ERROR] %s", sweeperErr)
sweeperErrs = multierror.Append(sweeperErrs, sweeperErr)
continue
}
}

return nil
return sweeperErrs.ErrorOrNil()
}

func TestAccAwsAcmpcaCertificateAuthority_basic(t *testing.T) {
Expand Down Expand Up @@ -104,32 +126,63 @@ func TestAccAwsAcmpcaCertificateAuthority_basic(t *testing.T) {
})
}

func TestAccAwsAcmpcaCertificateAuthority_Enabled(t *testing.T) {
func TestAccAwsAcmpcaCertificateAuthority_disappears(t *testing.T) {
var certificateAuthority acmpca.CertificateAuthority
resourceName := "aws_acmpca_certificate_authority.test"

// error updating ACMPCA Certificate Authority: InvalidStateException: The certificate authority must be in the Active or DISABLED state to be updated
TestAccSkip(t, "We need to fully sign the certificate authority CSR from another CA in order to test this functionality, which requires another resource")
resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckAwsAcmpcaCertificateAuthorityDestroy,
Steps: []resource.TestStep{
{
Config: testAccAwsAcmpcaCertificateAuthorityConfig_Required,
Check: resource.ComposeTestCheckFunc(
testAccCheckAwsAcmpcaCertificateAuthorityExists(resourceName, &certificateAuthority),
testAccCheckResourceDisappears(testAccProvider, resourceAwsAcmpcaCertificateAuthority(), resourceName),
),
// As the CA enters DELETED state and does not disappear, we do get an empty plan.
// ExpectNonEmptyPlan: true,
ewbankkit marked this conversation as resolved.
Show resolved Hide resolved
},
},
})
}

func TestAccAwsAcmpcaCertificateAuthority_Enabled(t *testing.T) {
var certificateAuthority acmpca.CertificateAuthority
rName := acctest.RandomWithPrefix("tf-acc-test")
resourceName := "aws_acmpca_certificate_authority.test"

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckAwsAcmpcaCertificateAuthorityDestroy,
Steps: []resource.TestStep{
{
Config: testAccAwsAcmpcaCertificateAuthorityConfig_Enabled(true),
Config: testAccAwsAcmpcaCertificateAuthorityConfig_Enabled(rName, acmpca.CertificateAuthorityTypeRoot, true),
Check: resource.ComposeTestCheckFunc(
testAccCheckAwsAcmpcaCertificateAuthorityExists(resourceName, &certificateAuthority),
resource.TestCheckResourceAttr(resourceName, "type", acmpca.CertificateAuthorityTypeRoot),
resource.TestCheckResourceAttr(resourceName, "enabled", "true"),
resource.TestCheckResourceAttr(resourceName, "status", "PENDING_CERTIFICATE"),
resource.TestCheckResourceAttr(resourceName, "status", acmpca.CertificateAuthorityStatusPendingCertificate),
testAccCheckAwsAcmpcaCertificateAuthorityActivateCA(&certificateAuthority),
),
},
{
Config: testAccAwsAcmpcaCertificateAuthorityConfig_Enabled(rName, acmpca.CertificateAuthorityTypeRoot, true),
Check: resource.ComposeTestCheckFunc(
testAccCheckAwsAcmpcaCertificateAuthorityExists(resourceName, &certificateAuthority),
resource.TestCheckResourceAttr(resourceName, "type", acmpca.CertificateAuthorityTypeRoot),
resource.TestCheckResourceAttr(resourceName, "enabled", "true"),
resource.TestCheckResourceAttr(resourceName, "status", acmpca.CertificateAuthorityStatusActive),
),
},
{
Config: testAccAwsAcmpcaCertificateAuthorityConfig_Enabled(false),
Config: testAccAwsAcmpcaCertificateAuthorityConfig_Enabled(rName, acmpca.CertificateAuthorityTypeRoot, false),
Check: resource.ComposeTestCheckFunc(
testAccCheckAwsAcmpcaCertificateAuthorityExists(resourceName, &certificateAuthority),
resource.TestCheckResourceAttr(resourceName, "enabled", "false"),
resource.TestCheckResourceAttr(resourceName, "status", "DISABLED"),
resource.TestCheckResourceAttr(resourceName, "status", acmpca.CertificateAuthorityStatusDisabled),
),
},
{
Expand Down Expand Up @@ -410,34 +463,6 @@ func TestAccAwsAcmpcaCertificateAuthority_Tags(t *testing.T) {
})
}

func TestAccAwsAcmpcaCertificateAuthority_Type_Root(t *testing.T) {
ewbankkit marked this conversation as resolved.
Show resolved Hide resolved
var certificateAuthority acmpca.CertificateAuthority
resourceName := "aws_acmpca_certificate_authority.test"

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckAwsAcmpcaCertificateAuthorityDestroy,
Steps: []resource.TestStep{
{
Config: testAccAwsAcmpcaCertificateAuthorityConfigType(acmpca.CertificateAuthorityTypeRoot),
Check: resource.ComposeTestCheckFunc(
testAccCheckAwsAcmpcaCertificateAuthorityExists(resourceName, &certificateAuthority),
resource.TestCheckResourceAttr(resourceName, "type", acmpca.CertificateAuthorityTypeRoot),
),
},
{
ResourceName: resourceName,
ImportState: true,
ImportStateVerify: true,
ImportStateVerifyIgnore: []string{
"permanent_deletion_time_in_days",
},
},
},
})
}

func testAccCheckAwsAcmpcaCertificateAuthorityDestroy(s *terraform.State) error {
conn := testAccProvider.Meta().(*AWSClient).acmpcaconn

Expand Down Expand Up @@ -496,6 +521,63 @@ func testAccCheckAwsAcmpcaCertificateAuthorityExists(resourceName string, certif
}
}

func testAccCheckAwsAcmpcaCertificateAuthorityActivateCA(certificateAuthority *acmpca.CertificateAuthority) resource.TestCheckFunc {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While we're trying to solve this problem here, I wonder if its worth trying to solve this for practitioners as well (#5552). I'm not sure all the workflows off the top of my head to recommend whether it will make more sense to add functionality to the existing resource or create a separate resource though.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I intend to do that once this PR is merged, extracting this code into the internal/service/acmpca package.
I think we can also enable this test:

https://github.com/terraform-providers/terraform-provider-aws/blob/2849645e3831ef12c14e6ba01593b7c45d12362e/aws/resource_aws_msk_cluster_test.go#L155-L156

return func(s *terraform.State) error {
conn := testAccProvider.Meta().(*AWSClient).acmpcaconn

arn := aws.StringValue(certificateAuthority.Arn)

getCsrResp, err := conn.GetCertificateAuthorityCsr(&acmpca.GetCertificateAuthorityCsrInput{
CertificateAuthorityArn: aws.String(arn),
})
if err != nil {
return fmt.Errorf("error getting ACMPCA Certificate Authority (%s) CSR: %s", arn, err)
}

issueCertResp, err := conn.IssueCertificate(&acmpca.IssueCertificateInput{
CertificateAuthorityArn: aws.String(arn),
Csr: []byte(aws.StringValue(getCsrResp.Csr)),
IdempotencyToken: aws.String(resource.UniqueId()),
SigningAlgorithm: certificateAuthority.CertificateAuthorityConfiguration.SigningAlgorithm,
TemplateArn: aws.String("arn:aws:acm-pca:::template/RootCACertificate/V1"),
Validity: &acmpca.Validity{
Type: aws.String(acmpca.ValidityPeriodTypeYears),
Value: aws.Int64(10),
},
})
if err != nil {
return fmt.Errorf("error issuing ACMPCA Certificate Authority (%s) Root CA certificate from CSR: %s", arn, err)
}

// Wait for certificate status to become ISSUED.
err = conn.WaitUntilCertificateIssued(&acmpca.GetCertificateInput{
CertificateAuthorityArn: aws.String(arn),
CertificateArn: issueCertResp.CertificateArn,
})
if err != nil {
return fmt.Errorf("error waiting for ACMPCA Certificate Authority (%s) Root CA certificate to become ISSUED: %s", arn, err)
}

getCertResp, err := conn.GetCertificate(&acmpca.GetCertificateInput{
CertificateAuthorityArn: aws.String(arn),
CertificateArn: issueCertResp.CertificateArn,
})
if err != nil {
return fmt.Errorf("error getting ACMPCA Certificate Authority (%s) issued Root CA certificate: %s", arn, err)
}

_, err = conn.ImportCertificateAuthorityCertificate(&acmpca.ImportCertificateAuthorityCertificateInput{
CertificateAuthorityArn: aws.String(arn),
Certificate: []byte(aws.StringValue(getCertResp.Certificate)),
})
if err != nil {
return fmt.Errorf("error importing ACMPCA Certificate Authority (%s) Root CA certificate: %s", arn, err)
}

return err
}
}

func listAcmpcaCertificateAuthorities(conn *acmpca.ACMPCA) ([]*acmpca.CertificateAuthority, error) {
certificateAuthorities := []*acmpca.CertificateAuthority{}
input := &acmpca.ListCertificateAuthoritiesInput{}
Expand All @@ -515,22 +597,23 @@ func listAcmpcaCertificateAuthorities(conn *acmpca.ACMPCA) ([]*acmpca.Certificat
return certificateAuthorities, nil
}

func testAccAwsAcmpcaCertificateAuthorityConfig_Enabled(enabled bool) string {
func testAccAwsAcmpcaCertificateAuthorityConfig_Enabled(rName, certificateAuthorityType string, enabled bool) string {
return fmt.Sprintf(`
resource "aws_acmpca_certificate_authority" "test" {
enabled = %[1]t
permanent_deletion_time_in_days = 7
type = %[2]q

certificate_authority_configuration {
key_algorithm = "RSA_4096"
signing_algorithm = "SHA512WITHRSA"

subject {
common_name = "terraformtesting.com"
common_name = "%[3]s.com"
}
}
}
`, enabled)
`, enabled, certificateAuthorityType, rName)
}

const testAccAwsAcmpcaCertificateAuthorityConfig_Required = `
Expand Down Expand Up @@ -722,21 +805,3 @@ resource "aws_acmpca_certificate_authority" "test" {
}
}
`

func testAccAwsAcmpcaCertificateAuthorityConfigType(certificateAuthorityType string) string {
return fmt.Sprintf(`
resource "aws_acmpca_certificate_authority" "test" {
permanent_deletion_time_in_days = 7
type = %[1]q

certificate_authority_configuration {
key_algorithm = "RSA_4096"
signing_algorithm = "SHA512WITHRSA"

subject {
common_name = "terraformtesting.com"
}
}
}
`, certificateAuthorityType)
}