如何使用CloudFormation将IAM角色与Aurora群集相关联?

时间:2017-03-13 17:42:43

标签: amazon-web-services amazon-s3 amazon-iam amazon-cloudformation amazon-rds-aurora

按照here发现的说明,我创建了以下IAM角色

"DatabaseS3Role": {
    "Type": "AWS::IAM::Role",
    "Properties": {
        "AssumeRolePolicyDocument": {
            "Version": "2012-10-17",
            "Statement": [
                {
                    "Effect": "Allow",
                    "Principal": {
                        "Service": ["rds.amazonaws.com"]
                    },
                    "Action": "sts:AssumeRole"
                }
            ]
        },
        "Policies": [
            {
                "PolicyName": "AllowAuroraToReadS3",
                "PolicyDocument": {
                    "Version": "2012-10-17",
                    "Statement": [
                        {
                            "Effect": "Allow",
                            "Action": ["s3:GetObject", "s3:GetObjectVersion", "s3:ListBucket"],
                            "Resource": {"Fn::Join": ["", [
                                "arn:aws:s3:::",
                                {"Fn::Join": ["-",[
                                    {"Ref": "ClientName"}, 
                                    {"Ref": "SourceBucketName"},
                                    {"Ref": "EnvironmentType"},
                                    { "Fn::FindInMap" : [ "Regions", { "Ref" : "AWS::Region" }, "Name" ] }
                                ]]} ,
                                "*"
                            ]]}
                        }
                    ]
                }
            }
        ]
    }
}

我可以将它添加到群集参数组并使用以下内容关联它。

"RDSDBClusterParameterGroup" : {
    "DependsOn": "DatabaseS3Role",
    "Type": "AWS::RDS::DBClusterParameterGroup",
    "Properties" : {
        "Description" : "CloudFormation Aurora Cluster Parameter Group",
        "Family" : "aurora5.6",
        "Parameters" : {
            "time_zone" : "US/Eastern",
            "aws_default_s3_role": {"Fn::GetAtt": ["DatabaseS3Role", "Arn"]}
        }
    }
},
"RDSAuroraCluster" : {
    "Type" : "AWS::RDS::DBCluster",
    "Properties" : {
        "MasterUsername" : { "Ref" : "Username" },
        "MasterUserPassword" : { "Ref" : "Password" },
        "Engine" : "aurora",
        "DBSubnetGroupName" : { "Ref" : "RDSSubnetGroup" },
        "DBClusterParameterGroupName" : { "Ref" : "RDSDBClusterParameterGroup" },
        "VpcSecurityGroupIds" : [ { "Ref" : "SecurityGroupId" } ],
        "Tags" : [
              { "Key" : "Name", "Value" : { "Fn::Join" : [ "-", [ 
              { "Ref" : "ClientName" }, 
              "aurclstr001",
              {"Ref" : "EnvironmentType" },
              { "Fn::FindInMap" : [ "Regions", { "Ref" : "AWS::Region" }, "Name" ] }
          ] ] } }
        ]
    }
}

但是,除非我通过控制台或cli命令add-role-to-db-cluster手动将角色与群集关联,否则Aurora仍然无法连接到S3。

挖掘云形成文档并未提供通过模板执行此操作的任何方法。 This documentation未提供允许角色关联的任何参数。

如何在不必为部署过程添加手动步骤的情况下执行此操作?

1 个答案:

答案 0 :(得分:5)

它不是一个很好的解决方案,但我决定生成在输出中运行所需的命令。我将向亚马逊开放支持请求,以确认无法通过DSL向群集添加角色。

当我运行aws rds describe-db-clusters时,我看到" AssociatedRoles"的条目它包含一个具有Status和RoleArn的对象数组。

PostRunCommand:
  Description: You must run this awscli command after the stack is created and may also need to reboot the cluster/instance.
  Value: !Join [" ", [
    "aws rds add-role-to-db-cluster --db-cluster-identifier",
    !Ref AuroraSandboxCluster,
    "--role-arn",
    !GetAtt AuroraS3Role.Arn,
    "--profile",
    !FindInMap [ AccountNameMap, !Ref AccountNamespace, profile ]
  ]]

你很可能不会需要最后一部分WRT资料......

亚马逊回应我之后的后续行动。他们说:

  

我了解到您正在寻找一种方法将IAM角色与Cloudformation中的Aurora群集相关联,以代表您访问其他AWS服务。

     

正确地说,RDS群集资源没有角色属性,因为CloudFormation尚不支持它。已经有一个已经打开的功能请求,因为它是一个非常常见的问题,我已经添加了你的声音,以增加功能的重量。   像往常一样,我无法为您提供ETA,但是一旦发布,它应该发布在Cloudformation发布历史页面中:

     

http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/ReleaseHistory.html

     

但是,您可以创建一个CFN模板来创建RDS Aurora设置,并在模板的末尾创建一个自定义资源[1],作为Lambda函数,它进行API调用以将IAM角色附加到RDS集群,这样整个RDS Aurora Cluster设置就可以集中在CFN模板中,无需手动操作,集群也可以调用Lambda函数。

     

请附上一个"示例"上述解决方法的模板。

     

我还将代表您发送有关创建角色以向AWS服务委派权限所需的示例中缺少主要属性的反馈。

{
"AWSTemplateFormatVersion": "2010-09-09",
"Description": "AWS Cloud resources for DevTools services.",
"Metadata": {
    "Version": "0.2.0"
},
"Parameters": {
    "RDSPassword": {
        "Description": "Password for root user on the RDS instance.",
        "Type": "String",
        "NoEcho":"true"
    },
    "RDSDatabaseName": {
        "Description": "DB Identifier for RDS instance.",
        "Type": "String",
        "Default": "mydbname"
    },
    "RDSClass": {
        "Description": "RDS Instance Class",
        "Type": "String",
        "Default": "db.r3.xlarge"
    },
    "DBIdentifier": {
        "Description": "Database Instance Identifier",
        "Type": "String"
    },
    "DBSubnetGroupName": {
        "Description": " The Subnet group Group for the RDS instance",
        "Type": "String"
    },
    "RDSSecurityGroupId": {
        "Description": "Existing internal SG for RDS instance access",
        "Type": "AWS::EC2::SecurityGroup::Id"
    },
    "RDSRetention": {
        "Description": "How long to retain RDS snapshots",
        "Type": "String"
    },
    "RDSVpcId": {
        "Description": "VpcId for RDS instance",
        "Type": "AWS::EC2::VPC::Id"
    },
    "PubliclyAccessible": {
        "Description": "Set the RDS to be publically available",
        "Type": "String",
        "AllowedValues" : ["true", "false"],
        "Default": "true"
    },
    "DBClusterIdentifier": {
        "Description": "The name of the DBCluster",
        "Type": "String"
    },
    "RDSRoleTag": {
        "Description": "sets if the tag for dev/prod use",
        "Type": "String",
        "Default": "dev"
    }
},

"Resources": {

  "LambdaRole" : {
    "Type" : "AWS::IAM::Role",
    "Properties" : {
        "AssumeRolePolicyDocument" : {
            "Version" : "2012-10-17",
            "Statement" : [
                {
                    "Effect" : "Allow",
                    "Principal" : {
                        "Service" : [
                            "lambda.amazonaws.com"
                        ]
                    },
                    "Action"    : [
                        "sts:AssumeRole"
                    ]
                }
            ]
        }
      }
    },

    "LambdaPolicy": {
      "Type" : "AWS::IAM::Policy",
      "Properties" : {
         "PolicyName" : "LambdaPolicy",
         "PolicyDocument" : {
            "Version" : "2012-10-17",
            "Statement": [ {
            "Effect"   : "Allow",
            "Action"   : [
               "iam:*",
               "ec2:*",
               "rds:*",
               "logs:*"
            ],
            "Resource" : "*"
            } ]
         },
         "Roles": [ { "Ref": "LambdaRole" } ]
      }
   },

    "LambdaFunction": {
      "Type" : "AWS::Lambda::Function",
      "DeletionPolicy" : "Delete",
      "DependsOn"      : [
          "LambdaRole"
      ],
      "Properties"     : {
          "Code" : {
              "ZipFile" : {
                  "Fn::Join" : [
                      "\n",
                      [
                        "          var AWS = require('aws-sdk');",
                        "          var rds = new AWS.RDS();",
                        "          var response = require('cfn-response');",
                        "          exports.handler = (event, context, callback) => {",
                        "              var rolearn = event.ResourceProperties.RDSRole;",
                        "              var dbclusteridentifier = event.ResourceProperties.DBClusterIdentifier;",
                        "              var responseData = {};",
                        "              console.log('Role ARN: ' + rolearn);",
                        "              console.log('DBClusterIdentifier: ' + dbclusteridentifier);",
                        "              var addroleparams = {",
                        "                  RoleArn: rolearn,",
                        "                  DBClusterIdentifier: dbclusteridentifier",
                        "                };",
                        "                if (event.RequestType == 'Delete') {",
                        "                  response.send(event, context, response.SUCCESS);",
                        "                  return;",
                        "                }",
                        "                rds.addRoleToDBCluster(addroleparams, function(err, data) {",
                        "                  if (err) {",
                        "                  console.log(err, err.stack); // an error occurred",
                        "                  responseData = {Error: 'Create call failed'};",
                        "                  response.send(event, context, response.FAILED, responseData);",
                        "                  }",
                        "                  else {",
                        "                  response.send(event, context, response.SUCCESS, responseData);",
                        "                  console.log(data);  // successful response",
                        "                  }",
                        "                });",
                        "          };",
                      ]
                  ]
              }
          },
          "Handler" : "index.handler",
          "MemorySize" : 128,
          "Role"       : {
              "Fn::GetAtt" : [
                  "LambdaRole",
                  "Arn"
              ]
          },
          "Runtime"    : "nodejs4.3",
          "Timeout"    : 10
      }
    },

    "RDSRole": {
      "Type": "AWS::IAM::Role",
      "Properties": {
        "AssumeRolePolicyDocument": {
          "Version": "2012-10-17",
          "Statement": [
            {
              "Effect": "Allow",
              "Principal": {
                "Service": ["rds.amazonaws.com"]
              },
              "Action": ["sts:AssumeRole"]
            }
          ]
        },
        "Path": "/"
      }
    },

    "RDSPolicy": {
       "Type" : "AWS::IAM::Policy",
       "Properties" : {
          "PolicyName" : "RDSPolicy",
          "PolicyDocument" : {
             "Version" : "2012-10-17",
             "Statement": [ {
             "Effect"   : "Allow",
             "Action"   : [
                "lambda:InvokeFunction"
             ],
             "Resource" : "*"
             } ]
          },
          "Roles": [ { "Ref": "RDSRole" } ]
       }
    },

    "RDSDBClusterParameterGroup" : {
      "Type" : "AWS::RDS::DBClusterParameterGroup",
      "Properties" : {
        "Parameters" : {
          "aws_default_lambda_role" : { "Fn::GetAtt" : [ "LambdaFunction", "Arn" ] }

        },
        "Family" : "aurora5.6",
        "Description" : "A sample parameter group"
      }
    },

    "RDSDBCluster": {
        "Type" : "AWS::RDS::DBCluster",
        "DeletionPolicy": "Retain",
        "Properties" : {
            "BackupRetentionPeriod" : { "Ref": "RDSRetention" },
            "DatabaseName": { "Ref": "RDSDatabaseName" },
            "DBSubnetGroupName": { "Ref": "DBSubnetGroupName" },
            "DBClusterParameterGroupName": { "Ref" : "RDSDBClusterParameterGroup" },
            "Engine" : "aurora",
            "StorageEncrypted" : true,
            "MasterUsername" : "sa",
            "MasterUserPassword" : { "Ref": "RDSPassword" },
            "Port" : 3306,
            "Tags": [
                { "Key": "Role", "Value": { "Ref": "RDSRoleTag" } }
                ],
            "VpcSecurityGroupIds": [{ "Ref": "RDSSecurityGroupId" } ]
        }
    },
    "RDSInstance": {
        "Type": "AWS::RDS::DBInstance",
        "DeletionPolicy": "Retain",
        "Properties": {
            "AllowMajorVersionUpgrade": false,
            "AutoMinorVersionUpgrade": true,
            "DBClusterIdentifier" : { "Ref": "RDSDBCluster" },
            "DBInstanceIdentifier": { "Ref": "DBIdentifier" },
            "DBInstanceClass": { "Ref": "RDSClass" },
            "Engine": "aurora",
            "PubliclyAccessible": { "Ref": "PubliclyAccessible" },
            "Tags": [
                { "Key": "Role", "Value": { "Ref": "RDSRoleTag" } }
                ]
        }
    },
    "RDSInstanceSecurityGroup": {
        "Type": "AWS::EC2::SecurityGroup",
        "DeletionPolicy": "Retain",
        "Properties": {
            "GroupDescription": "Security group for the RDSInstance resource",
            "SecurityGroupEgress": [
                {
                    "IpProtocol": "tcp",
                    "CidrIp": "127.0.0.1/32",
                    "FromPort": "1",
                    "ToPort": "1"
                }
            ],
            "SecurityGroupIngress": [
                {
                    "IpProtocol": "tcp",
                    "SourceSecurityGroupId": { "Ref": "RDSSecurityGroupId" },
                    "FromPort": "3306",
                    "ToPort": "3306"
                }
            ],
            "VpcId": { "Ref": "RDSVpcId" },
            "Tags": [
                { "Key": "Role", "Value": { "Ref": "RDSRoleTag" } }
                ]
        }
    },

    "AddRoleToDBCluster": {
        "DependsOn" : [
            "RDSDBCluster",
            "RDSInstance"
        ],
        "Type": "Custom::AddRoleToDBCluster",
        "Properties" : {
            "ServiceToken" : {
                "Fn::GetAtt" : [
                    "LambdaFunction",
                    "Arn"
                ]
            },
            "RDSRole" : { "Fn::GetAtt" : [ "RDSRole", "Arn" ] },
            "DBClusterIdentifier" : {"Ref":"RDSDBCluster"}
        }
    }
}

}