diff --git a/aws/resource_aws_rds_cluster.go b/aws/resource_aws_rds_cluster.go index d2500683712..f138d3fe3b5 100644 --- a/aws/resource_aws_rds_cluster.go +++ b/aws/resource_aws_rds_cluster.go @@ -222,6 +222,13 @@ func resourceAwsRDSCluster() *schema.Resource { Optional: true, }, + "iam_roles": { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Set: schema.HashString, + }, + "iam_database_authentication_enabled": { Type: schema.TypeBool, Optional: true, @@ -490,6 +497,15 @@ func resourceAwsRDSClusterCreate(d *schema.ResourceData, meta interface{}) error return fmt.Errorf("[WARN] Error waiting for RDS Cluster state to be \"available\": %s", err) } + if v, ok := d.GetOk("iam_roles"); ok { + for _, role := range v.(*schema.Set).List() { + err := setIamRoleToRdsCluster(d.Id(), role.(string), conn) + if err != nil { + return err + } + } + } + return resourceAwsRDSClusterRead(d, meta) } @@ -570,6 +586,15 @@ func resourceAwsRDSClusterRead(d *schema.ResourceData, meta interface{}) error { return fmt.Errorf("[DEBUG] Error saving RDS Cluster Members to state for RDS Cluster (%s): %s", d.Id(), err) } + var roles []string + for _, r := range dbc.AssociatedRoles { + roles = append(roles, *r.RoleArn) + } + + if err := d.Set("iam_roles", roles); err != nil { + return fmt.Errorf("[DEBUG] Error saving IAM Roles to state for RDS Cluster (%s): %s", d.Id(), err) + } + // Fetch and save tags arn, err := buildRDSClusterARN(d.Id(), meta.(*AWSClient).partition, meta.(*AWSClient).accountid, meta.(*AWSClient).region) if err != nil { @@ -649,6 +674,35 @@ func resourceAwsRDSClusterUpdate(d *schema.ResourceData, meta interface{}) error } } + if d.HasChange("iam_roles") { + oraw, nraw := d.GetChange("iam_roles") + if oraw == nil { + oraw = new(schema.Set) + } + if nraw == nil { + nraw = new(schema.Set) + } + + os := oraw.(*schema.Set) + ns := nraw.(*schema.Set) + removeRoles := os.Difference(ns) + enableRoles := ns.Difference(os) + + for _, role := range enableRoles.List() { + err := setIamRoleToRdsCluster(d.Id(), role.(string), conn) + if err != nil { + return err + } + } + + for _, role := range removeRoles.List() { + err := removeIamRoleFromRdsCluster(d.Id(), role.(string), conn) + if err != nil { + return err + } + } + } + if arn, err := buildRDSClusterARN(d.Id(), meta.(*AWSClient).partition, meta.(*AWSClient).accountid, meta.(*AWSClient).region); err == nil { if err := setTagsRDS(conn, d, arn); err != nil { return err @@ -758,3 +812,29 @@ func buildRDSClusterARN(identifier, partition, accountid, region string) (string return arn, nil } + +func setIamRoleToRdsCluster(clusterIdentifier string, roleArn string, conn *rds.RDS) error { + params := &rds.AddRoleToDBClusterInput{ + DBClusterIdentifier: aws.String(clusterIdentifier), + RoleArn: aws.String(roleArn), + } + _, err := conn.AddRoleToDBCluster(params) + if err != nil { + return err + } + + return nil +} + +func removeIamRoleFromRdsCluster(clusterIdentifier string, roleArn string, conn *rds.RDS) error { + params := &rds.RemoveRoleFromDBClusterInput{ + DBClusterIdentifier: aws.String(clusterIdentifier), + RoleArn: aws.String(roleArn), + } + _, err := conn.RemoveRoleFromDBCluster(params) + if err != nil { + return err + } + + return nil +} diff --git a/aws/resource_aws_rds_cluster_test.go b/aws/resource_aws_rds_cluster_test.go index 5023bd84a4d..1f26952e0f0 100644 --- a/aws/resource_aws_rds_cluster_test.go +++ b/aws/resource_aws_rds_cluster_test.go @@ -146,6 +146,41 @@ func TestAccAWSRDSCluster_updateTags(t *testing.T) { }) } +func TestAccAWSRDSCluster_updateIamRoles(t *testing.T) { + var v rds.DBCluster + ri := acctest.RandInt() + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSClusterDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSClusterConfigIncludingIamRoles(ri), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSClusterExists("aws_rds_cluster.default", &v), + ), + }, + { + Config: testAccAWSClusterConfigAddIamRoles(ri), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSClusterExists("aws_rds_cluster.default", &v), + resource.TestCheckResourceAttr( + "aws_rds_cluster.default", "iam_roles.#", "2"), + ), + }, + { + Config: testAccAWSClusterConfigRemoveIamRoles(ri), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSClusterExists("aws_rds_cluster.default", &v), + resource.TestCheckResourceAttr( + "aws_rds_cluster.default", "iam_roles.#", "1"), + ), + }, + }, + }) +} + func TestAccAWSRDSCluster_kmsKey(t *testing.T) { var v rds.DBCluster keyRegex := regexp.MustCompile("^arn:aws:kms:") @@ -591,3 +626,224 @@ resource "aws_rds_cluster" "default" { skip_final_snapshot = true }`, n) } + +func testAccAWSClusterConfigIncludingIamRoles(n int) string { + return fmt.Sprintf(` +resource "aws_iam_role" "rds_sample_role" { + name = "rds_sample_role_%d" + path = "/" + assume_role_policy = <