Skip to content

Commit

Permalink
Merge pull request #35003 from obounaim/f-rds-certificates
Browse files Browse the repository at this point in the history
[New Resource]: aws_rds_certificate
  • Loading branch information
ewbankkit authored Jul 12, 2024
2 parents 67a4dcc + b5855f9 commit dd0dfa0
Show file tree
Hide file tree
Showing 6 changed files with 347 additions and 0 deletions.
3 changes: 3 additions & 0 deletions .changelog/35003.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:new-resource
aws_rds_certificate
```
147 changes: 147 additions & 0 deletions internal/service/rds/certificate.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0

package rds

import (
"context"
"log"

"github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/aws-sdk-go-v2/service/rds"
"github.com/aws/aws-sdk-go-v2/service/rds/types"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/retry"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-provider-aws/internal/conns"
"github.com/hashicorp/terraform-provider-aws/internal/errs"
"github.com/hashicorp/terraform-provider-aws/internal/errs/sdkdiag"
tfslices "github.com/hashicorp/terraform-provider-aws/internal/slices"
"github.com/hashicorp/terraform-provider-aws/internal/tfresource"
)

// @SDKResource("aws_rds_certificate", name="Default Certificate")
func resourceCertificate() *schema.Resource {
return &schema.Resource{
CreateWithoutTimeout: resourceCertificatePut,
ReadWithoutTimeout: resourceCertificateRead,
UpdateWithoutTimeout: resourceCertificatePut,
DeleteWithoutTimeout: resourceCertificateDelete,

Importer: &schema.ResourceImporter{
StateContext: schema.ImportStatePassthroughContext,
},

Schema: map[string]*schema.Schema{
"certificate_identifier": {
Type: schema.TypeString,
Required: true,
},
},
}
}

func resourceCertificatePut(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
var diags diag.Diagnostics
conn := meta.(*conns.AWSClient).RDSClient(ctx)

certificateID := d.Get("certificate_identifier").(string)
input := &rds.ModifyCertificatesInput{
CertificateIdentifier: aws.String(certificateID),
}

_, err := conn.ModifyCertificates(ctx, input)

if err != nil {
return sdkdiag.AppendErrorf(diags, "setting RDS Default Certificate (%s): %s", certificateID, err)
}

if d.IsNewResource() {
d.SetId(meta.(*conns.AWSClient).Region)
}

return append(diags, resourceCertificateRead(ctx, d, meta)...)
}

func resourceCertificateRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
var diags diag.Diagnostics
conn := meta.(*conns.AWSClient).RDSClient(ctx)

output, err := findDefaultCertificate(ctx, conn)

if !d.IsNewResource() && tfresource.NotFound(err) {
log.Printf("[WARN] RDS Default Certificate (%s) not found, removing from state", d.Id())
d.SetId("")
return diags
}

if err != nil {
return sdkdiag.AppendErrorf(diags, "reading RDS Default Certificate (%s): %s", d.Id(), err)
}

d.Set("certificate_identifier", output.CertificateIdentifier)

return diags
}

func resourceCertificateDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
var diags diag.Diagnostics
conn := meta.(*conns.AWSClient).RDSClient(ctx)

log.Printf("[DEBUG] Deleting RDS Default Certificate: %s", d.Id())
_, err := conn.ModifyCertificates(ctx, &rds.ModifyCertificatesInput{
RemoveCustomerOverride: aws.Bool(true),
})

if err != nil {
return sdkdiag.AppendErrorf(diags, "removing RDS Default Certificate (%s): %s", d.Id(), err)
}

return diags
}

func findCertificate(ctx context.Context, conn *rds.Client, input *rds.DescribeCertificatesInput, filter tfslices.Predicate[*types.Certificate]) (*types.Certificate, error) {
output, err := findCertificates(ctx, conn, input, filter)

if err != nil {
return nil, err
}

return tfresource.AssertSingleValueResult(output)
}

func findCertificates(ctx context.Context, conn *rds.Client, input *rds.DescribeCertificatesInput, filter tfslices.Predicate[*types.Certificate]) ([]types.Certificate, error) {
var output []types.Certificate

pages := rds.NewDescribeCertificatesPaginator(conn, input)
for pages.HasMorePages() {
page, err := pages.NextPage(ctx)

if errs.IsA[*types.CertificateNotFoundFault](err) {
return nil, &retry.NotFoundError{
LastError: err,
LastRequest: input,
}
}

if err != nil {
return nil, err
}

for _, v := range page.Certificates {
if filter(&v) {
output = append(output, v)
}
}
}

return output, nil
}

func findDefaultCertificate(ctx context.Context, conn *rds.Client) (*types.Certificate, error) {
input := &rds.DescribeCertificatesInput{}

return findCertificate(ctx, conn, input, func(v *types.Certificate) bool {
return aws.ToBool(v.CustomerOverride)
})
}
142 changes: 142 additions & 0 deletions internal/service/rds/certificate_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0

package rds_test

import (
"context"
"fmt"
"testing"

"github.com/aws/aws-sdk-go-v2/service/rds/types"
"github.com/hashicorp/terraform-plugin-testing/helper/resource"
"github.com/hashicorp/terraform-plugin-testing/terraform"
"github.com/hashicorp/terraform-provider-aws/internal/acctest"
"github.com/hashicorp/terraform-provider-aws/internal/conns"
tfrds "github.com/hashicorp/terraform-provider-aws/internal/service/rds"
"github.com/hashicorp/terraform-provider-aws/internal/tfresource"
"github.com/hashicorp/terraform-provider-aws/names"
)

func TestAccRDSCertificate_serial(t *testing.T) {
t.Parallel()

testCases := map[string]func(t *testing.T){
acctest.CtBasic: testAccCertificate_basic,
acctest.CtDisappears: testAccCertificate_disappears,
}

acctest.RunSerialTests1Level(t, testCases, 0)
}

func testAccCertificate_basic(t *testing.T) {
ctx := acctest.Context(t)
var v types.Certificate
resourceName := "aws_rds_certificate.test"

resource.Test(t, resource.TestCase{
PreCheck: func() { acctest.PreCheck(ctx, t) },
ErrorCheck: acctest.ErrorCheck(t, names.RDSServiceID),
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories,
CheckDestroy: testAccCheckCertificateDestroy(ctx),
Steps: []resource.TestStep{
{
Config: testAccCertificateConfig_basic("rds-ca-rsa4096-g1"),
Check: resource.ComposeTestCheckFunc(
testAccCheckCertificateExists(ctx, resourceName, &v),
resource.TestCheckResourceAttr(resourceName, "certificate_identifier", "rds-ca-rsa4096-g1"),
),
},
{
ResourceName: resourceName,
ImportState: true,
ImportStateVerify: true,
},
{
Config: testAccCertificateConfig_basic("rds-ca-ecc384-g1"),
Check: resource.ComposeTestCheckFunc(
testAccCheckCertificateExists(ctx, resourceName, &v),
resource.TestCheckResourceAttr(resourceName, "certificate_identifier", "rds-ca-ecc384-g1"),
),
},
},
})
}

func testAccCertificate_disappears(t *testing.T) {
ctx := acctest.Context(t)
var v types.Certificate
resourceName := "aws_rds_certificate.test"

resource.Test(t, resource.TestCase{
PreCheck: func() { acctest.PreCheck(ctx, t) },
ErrorCheck: acctest.ErrorCheck(t, names.RDSServiceID),
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories,
CheckDestroy: testAccCheckCertificateDestroy(ctx),
Steps: []resource.TestStep{
{
Config: testAccCertificateConfig_basic("rds-ca-rsa4096-g1"),
Check: resource.ComposeTestCheckFunc(
testAccCheckCertificateExists(ctx, resourceName, &v),
acctest.CheckResourceDisappears(ctx, acctest.Provider, tfrds.ResourceCertificate(), resourceName),
),
ExpectNonEmptyPlan: true,
},
},
})
}

func testAccCheckCertificateDestroy(ctx context.Context) resource.TestCheckFunc {
return func(s *terraform.State) error {
conn := acctest.Provider.Meta().(*conns.AWSClient).RDSClient(ctx)

for _, rs := range s.RootModule().Resources {
if rs.Type != "aws_rds_certificate" {
continue
}

_, err := tfrds.FindDefaultCertificate(ctx, conn)

if tfresource.NotFound(err) {
continue
}

if err != nil {
return err
}

return fmt.Errorf("RDS Default Certificate %s still exists", rs.Primary.ID)
}

return nil
}
}

func testAccCheckCertificateExists(ctx context.Context, n string, v *types.Certificate) resource.TestCheckFunc {
return func(s *terraform.State) error {
_, ok := s.RootModule().Resources[n]
if !ok {
return fmt.Errorf("Not found: %s", n)
}

conn := acctest.Provider.Meta().(*conns.AWSClient).RDSClient(ctx)

output, err := tfrds.FindDefaultCertificate(ctx, conn)

if err != nil {
return err
}

*v = *output

return nil
}
}

func testAccCertificateConfig_basic(certificateID string) string {
return fmt.Sprintf(`
resource "aws_rds_certificate" "test" {
certificate_identifier = %[1]q
}
`, certificateID)
}
2 changes: 2 additions & 0 deletions internal/service/rds/exports_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ package rds

// Exports for use in tests only.
var (
ResourceCertificate = resourceCertificate
ResourceEventSubscription = resourceEventSubscription
ResourceProxy = resourceProxy
ResourceProxyDefaultTargetGroup = resourceProxyDefaultTargetGroup
Expand All @@ -17,6 +18,7 @@ var (
FindDBProxyEndpointByTwoPartKey = findDBProxyEndpointByTwoPartKey
FindDBProxyTargetByFourPartKey = findDBProxyTargetByFourPartKey
FindDBSubnetGroupByName = findDBSubnetGroupByName
FindDefaultCertificate = findDefaultCertificate
FindDefaultDBProxyTargetGroupByDBProxyName = findDefaultDBProxyTargetGroupByDBProxyName
FindEventSubscriptionByID = findEventSubscriptionByID
ListTags = listTags
Expand Down
5 changes: 5 additions & 0 deletions internal/service/rds/service_package_gen.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

48 changes: 48 additions & 0 deletions website/docs/r/rds_certificate.html.markdown
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
---
subcategory: "RDS (Relational Database)"
layout: "aws"
page_title: "AWS: aws_rds_certificate"
description: |-
Terraform resource for managing an AWS RDS (Relational Database) Certificate.
---

# Resource: aws_rds_certificate

Provides a resource to override the system-default Secure Sockets Layer/Transport Layer Security (SSL/TLS) certificate for Amazon RDS for new DB instances in the current AWS region.

~> **NOTE:** Removing this Terraform resource removes the override. New DB instances will use the system-default certificate for the current AWS region.

## Example Usage

```terraform
resource "aws_rds_certificate" "example" {
certificate_identifier = "rds-ca-rsa4096-g1"
}
```

## Argument Reference

The following arguments are required:

* `certificate_identifier` - (Required) Certificate identifier. For example, `rds-ca-rsa4096-g1`. Refer to [AWS RDS (Relational Database) Certificate Identifier](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/UsingWithRDS.SSL.html#UsingWithRDS.SSL.CertificateIdentifier) for more information.

## Attribute Reference

This resource exports no additional attributes.

## Import

In Terraform v1.5.0 and later, use an [`import` block](https://developer.hashicorp.com/terraform/language/import) to import the RDS certificate override. For example:

```terraform
import {
to = aws_rds_certificate.example
id = default
}
```

Using `terraform import`, import the default EBS encryption state. For example:

```console
% terraform import aws_rds_certificate.example default
```

0 comments on commit dd0dfa0

Please sign in to comment.