Skip to content

Commit

Permalink
Merge pull request #1258 from stack72/f-aws-rds-cluster-iam_roles-382
Browse files Browse the repository at this point in the history
resource/aws_rds_cluster: Add support for iam_roles to rds_cluster
  • Loading branch information
grubernaut authored Aug 2, 2017
2 parents 82ab5ee + 0b21e99 commit 887d994
Show file tree
Hide file tree
Showing 3 changed files with 338 additions and 0 deletions.
80 changes: 80 additions & 0 deletions aws/resource_aws_rds_cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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)
}

Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
}
256 changes: 256 additions & 0 deletions aws/resource_aws_rds_cluster_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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:")
Expand Down Expand Up @@ -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 = <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Action": "sts:AssumeRole",
"Principal": {
"Service": "rds.amazonaws.com"
},
"Effect": "Allow",
"Sid": ""
}
]
}
EOF
}
resource "aws_iam_role_policy" "rds_policy" {
name = "rds_sample_role_policy_%d"
role = "${aws_iam_role.rds_sample_role.name}"
policy = <<EOF
{
"Version": "2012-10-17",
"Statement": {
"Effect": "Allow",
"Action": "*",
"Resource": "*"
}
}
EOF
}
resource "aws_iam_role" "another_rds_sample_role" {
name = "another_rds_sample_role_%d"
path = "/"
assume_role_policy = <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Action": "sts:AssumeRole",
"Principal": {
"Service": "rds.amazonaws.com"
},
"Effect": "Allow",
"Sid": ""
}
]
}
EOF
}
resource "aws_iam_role_policy" "another_rds_policy" {
name = "another_rds_sample_role_policy_%d"
role = "${aws_iam_role.another_rds_sample_role.name}"
policy = <<EOF
{
"Version": "2012-10-17",
"Statement": {
"Effect": "Allow",
"Action": "*",
"Resource": "*"
}
}
EOF
}
resource "aws_rds_cluster" "default" {
cluster_identifier = "tf-aurora-cluster-%d"
availability_zones = ["us-west-2a","us-west-2b","us-west-2c"]
database_name = "mydb"
master_username = "foo"
master_password = "mustbeeightcharaters"
db_cluster_parameter_group_name = "default.aurora5.6"
skip_final_snapshot = true
tags {
Environment = "production"
}
depends_on = ["aws_iam_role.another_rds_sample_role", "aws_iam_role.rds_sample_role"]
}`, n, n, n, n, n)
}

func testAccAWSClusterConfigAddIamRoles(n int) string {
return fmt.Sprintf(`
resource "aws_iam_role" "rds_sample_role" {
name = "rds_sample_role_%d"
path = "/"
assume_role_policy = <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Action": "sts:AssumeRole",
"Principal": {
"Service": "rds.amazonaws.com"
},
"Effect": "Allow",
"Sid": ""
}
]
}
EOF
}
resource "aws_iam_role_policy" "rds_policy" {
name = "rds_sample_role_policy_%d"
role = "${aws_iam_role.rds_sample_role.name}"
policy = <<EOF
{
"Version": "2012-10-17",
"Statement": {
"Effect": "Allow",
"Action": "*",
"Resource": "*"
}
}
EOF
}
resource "aws_iam_role" "another_rds_sample_role" {
name = "another_rds_sample_role_%d"
path = "/"
assume_role_policy = <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Action": "sts:AssumeRole",
"Principal": {
"Service": "rds.amazonaws.com"
},
"Effect": "Allow",
"Sid": ""
}
]
}
EOF
}
resource "aws_iam_role_policy" "another_rds_policy" {
name = "another_rds_sample_role_policy_%d"
role = "${aws_iam_role.another_rds_sample_role.name}"
policy = <<EOF
{
"Version": "2012-10-17",
"Statement": {
"Effect": "Allow",
"Action": "*",
"Resource": "*"
}
}
EOF
}
resource "aws_rds_cluster" "default" {
cluster_identifier = "tf-aurora-cluster-%d"
availability_zones = ["us-west-2a","us-west-2b","us-west-2c"]
database_name = "mydb"
master_username = "foo"
master_password = "mustbeeightcharaters"
db_cluster_parameter_group_name = "default.aurora5.6"
skip_final_snapshot = true
iam_roles = ["${aws_iam_role.rds_sample_role.arn}","${aws_iam_role.another_rds_sample_role.arn}"]
tags {
Environment = "production"
}
depends_on = ["aws_iam_role.another_rds_sample_role", "aws_iam_role.rds_sample_role"]
}`, n, n, n, n, n)
}

func testAccAWSClusterConfigRemoveIamRoles(n int) string {
return fmt.Sprintf(`
resource "aws_iam_role" "another_rds_sample_role" {
name = "another_rds_sample_role_%d"
path = "/"
assume_role_policy = <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Action": "sts:AssumeRole",
"Principal": {
"Service": "rds.amazonaws.com"
},
"Effect": "Allow",
"Sid": ""
}
]
}
EOF
}
resource "aws_iam_role_policy" "another_rds_policy" {
name = "another_rds_sample_role_policy_%d"
role = "${aws_iam_role.another_rds_sample_role.name}"
policy = <<EOF
{
"Version": "2012-10-17",
"Statement": {
"Effect": "Allow",
"Action": "*",
"Resource": "*"
}
}
EOF
}
resource "aws_rds_cluster" "default" {
cluster_identifier = "tf-aurora-cluster-%d"
availability_zones = ["us-west-2a","us-west-2b","us-west-2c"]
database_name = "mydb"
master_username = "foo"
master_password = "mustbeeightcharaters"
db_cluster_parameter_group_name = "default.aurora5.6"
skip_final_snapshot = true
iam_roles = ["${aws_iam_role.another_rds_sample_role.arn}"]
tags {
Environment = "production"
}
depends_on = ["aws_iam_role.another_rds_sample_role"]
}`, n, n, n)
}
2 changes: 2 additions & 0 deletions website/docs/r/rds_cluster.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -83,8 +83,10 @@ Default: A 30-minute window selected at random from an 8-hour block of time per
* `db_subnet_group_name` - (Optional) A DB subnet group to associate with this DB instance. **NOTE:** This must match the `db_subnet_group_name` specified on every [`aws_rds_cluster_instance`](/docs/providers/aws/r/rds_cluster_instance.html) in the cluster.
* `db_cluster_parameter_group_name` - (Optional) A cluster parameter group to associate with the cluster.
* `kms_key_id` - (Optional) The ARN for the KMS encryption key. When specifying `kms_key_id`, `storage_encrypted` needs to be set to true.
* `iam_roles` - (Optional) A List of ARNs for the IAM roles to associate to the RDS Cluster.
* `iam_database_authentication_enabled` - (Optional) Specifies whether or mappings of AWS Identity and Access Management (IAM) accounts to database accounts is enabled.


## Attributes Reference

The following attributes are exported:
Expand Down

0 comments on commit 887d994

Please sign in to comment.