{ "AWSTemplateFormatVersion": "2010-09-09", "Description": "This template creates a role and a user that can be used to deploy tasks to CloudReactor. It also creates a managed policy you can attach to existing roles or users.", "Outputs": { "CloudreactorDeployerPolicyARN": { "Description": "The ARN of the policy containing permissions required to deploy tasks to CloudReactor", "Value": { "Ref": "deployerPolicy" } }, "CloudreactorDeployerRoleARN": { "Description": "The ARN of a role that can deploy tasks to CloudReactor", "Value": { "Fn::GetAtt": [ "deployerRole", "Arn" ] } }, "CloudreactorDeployerInstanceProfileARN": { "Description": "The ARN of an instance profile that can deploy tasks to CloudReactor. If you assign an EC2 instance this instance profile, it will be able to deploy to tasks to ECS.", "Value": { "Fn::GetAtt": [ "deployerInstanceProfile", "Arn" ] } }, "CloudreactorDeployerUserARN": { "Description": "The ARN of a user that can deploy tasks to CloudReactor", "Value": { "Fn::GetAtt": [ "deployerUser", "Arn" ] } } }, "Parameters": { "DeploymentEnvironment": { "Description": "The name of the deployment environment, e.g. 'staging' or 'production'. Must consist only of alphanumeric characters or dashes. May be blank if the deployer role is to be used for multiple environments.", "Default": "", "MinLength": "0", "MaxLength": "128", "AllowedPattern": "[a-zA-Z0-9\\-]*", "NoEcho": "false", "Type": "String" }, "SecretsPathPrefix": { "Description": "A path prefix which can limit the secret values the deployer role can modify. Leave blank if no Secrets Manager access is required.", "AllowedPattern": "[a-zA-Z0-9_/+=.@-]*", "Default": "", "MinLength": "0", "MaxLength": "128", "NoEcho": "false", "Type": "String" }, "RoleAssumerPatterns": { "Description": "A comma-separated list of patterns for AWS principals (user ARNs or other role ARNs) that may assume the deployer role. Leave blank if no other AWS principal should be allowed to assume the role. Each pattern may contain wildcard ('*') characters.", "AllowedPattern": "[a-zA-Z0-9:/_+=,.@*-]*", "Default": "", "NoEcho": "false", "Type": "CommaDelimitedList" }, "S3PathPrefix": { "Description": "A path prefix which can limit the S3 resources deployer role can read and modify. It may contain wildcard characters, but not '*' at the end. Leave blank if no limitation on S3 access is required. Can be set to '*' to allow access to all S3 resources.", "AllowedPattern": "([a-zA-Z0-9!_./()?*-]*)", "MaxLength": 1024, "Default": "", "NoEcho": "false", "Type": "String" }, "CloudWatchLogGroupPathPrefix": { "Description": "A path prefix which can limit the deployer to write to certain log groups in CloudWatch logs.", "Default": "", "MinLength": "1", "MaxLength": "512", "NoEcho": "false", "Type": "String" } }, "Conditions": { "HasEnvSuffix": { "Fn::Not": [ { "Fn::Equals": [ { "Ref": "DeploymentEnvironment" }, "" ] } ] }, "HasSecretManagerAccess": { "Fn::Not": [ { "Fn::Equals": [ { "Ref": "SecretsPathPrefix" }, "" ] } ] }, "HasRoleAssumer": { "Fn::Not": [ { "Fn::Equals": [ { "Fn::Join": [ "", { "Ref": "RoleAssumerPatterns" } ] }, "" ] } ] }, "HasAllS3PathsAccess": { "Fn::Equals": [ { "Ref": "S3PathPrefix" }, "*" ] }, "HasNoS3Access": { "Fn::Equals": [ { "Ref": "S3PathPrefix" }, "" ] } }, "Resources": { "deployerPolicy": { "Type" : "AWS::IAM::ManagedPolicy", "Properties" : { "PolicyDocument" : { "Statement": [ { "Effect": { "Fn::If": [ "HasNoS3Access", "Deny", "Allow" ] }, "Action": [ "s3:PutObject", "s3:ListBucket", "s3:GetObject", "s3:DeleteObject" ], "Resource": { "Fn::If": [ "HasNoS3Access", "arn:aws:s3:::/dummy/*", { "Fn::If": [ "HasAllS3PathsAccess", "arn:aws:s3:::*", { "Fn::Join": [ "", [ "arn:aws:s3::", { "Ref" : "S3PathPrefix" }, "*" ] ] } ] } ] } }, { "Effect": "Allow", "Action": "codebuild:*", "Resource": "*" }, { "Effect": "Allow", "Action": "codestar-connections:*", "Resource": "*" }, { "Effect": "Allow", "Resource": { "Fn::Join": [ "", [ "arn:aws:logs:", { "Ref": "AWS::Region" }, ":", { "Ref" : "AWS::AccountId" }, ":log-group:", { "Ref" : "CloudWatchLogGroupPathPrefix" }, "*" ] ] }, "Action": [ "logs:CreateLogGroup", "logs:CreateLogStream", "logs:PutLogEvents" ] }, { "Effect": "Allow", "Action": [ "ecr:BatchCheckLayerAvailability", "ecr:CompleteLayerUpload", "ecr:CreateRepository", "ecr:DescribeRepositories", "ecr:GetAuthorizationToken", "ecr:GetRepositoryPolicy", "ecr:InitiateLayerUpload", "ecr:PutImage", "ecr:UploadLayerPart", "ecs:RegisterTaskDefinition" ], "Resource": [ "*" ] }, { "Effect": { "Fn::If": [ "HasSecretManagerAccess", "Allow", "Deny" ] }, "Action": [ "secretsmanager:CancelRotateSecret", "secretsmanager:CreateSecret", "secretsmanager:DeleteResourcePolicy", "secretsmanager:DeleteSecret", "secretsmanager:DescribeSecret", "secretsmanager:GetRandomPassword", "secretsmanager:GetResourcePolicy", "secretsmanager:GetSecretValue", "secretsmanager:ListSecretVersionIds", "secretsmanager:PutResourcePolicy", "secretsmanager:PutSecretValue", "secretsmanager:RemoveRegionsFromReplication", "secretsmanager:ReplicateSecretToRegions", "secretsmanager:RestoreSecret", "secretsmanager:RotateSecret", "secretsmanager:StopReplicationToReplica", "secretsmanager:TagResource", "secretsmanager:UntagResource", "secretsmanager:UpdateSecret", "secretsmanager:UpdateSecretVersionStage", "secretsmanager:ValidateResourcePolicy" ], "Resource": [ { "Fn::Join": [ "", [ "arn:aws:secretsmanager:", { "Ref": "AWS::Region" }, ":", { "Ref" : "AWS::AccountId" }, ":secret:", { "Ref": "SecretsPathPrefix" }, "*" ] ] } ] }, { "Effect": "Allow", "Action": [ "iam:GetRole", "iam:PassRole" ], "Resource": [ { "Fn::Join": [ "", [ "arn:aws:iam::", { "Ref" : "AWS::AccountId" }, ":role/*" ] ] } ] } ], "Version": "2012-10-17" }, "ManagedPolicyName": { "Fn::If": [ "HasEnvSuffix", { "Fn::Join": [ "", [ "cloudreactorDeployerPolicy-", { "Ref": "DeploymentEnvironment" } ] ] }, "cloudreactorDeployerPolicy" ] }, "Description": "A managed policy containing permissions needed to deploy tasks to CloudReactor" } }, "deployerRole": { "Type": "AWS::IAM::Role", "Properties": { "Description": "A role that can deploy tasks to CloudReactor", "Path": "/", "AssumeRolePolicyDocument": { "Version" : "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "Service": [ "ec2.amazonaws.com", "codebuild.amazonaws.com", "codedeploy.amazonaws.com" ] }, "Action": [ "sts:AssumeRole" ] }, { "Effect": "Allow", "Principal": { "AWS": { "Fn::If": [ "HasRoleAssumer", { "Ref": "RoleAssumerPatterns" }, { "Fn::GetAtt": [ "deployerUser", "Arn" ] } ] } }, "Action": "sts:AssumeRole" }, { "Effect": "Allow", "Principal": { "AWS": { "Fn::GetAtt": [ "deployerUser", "Arn" ] } }, "Action": "sts:AssumeRole" }, { "Effect": "Allow", "Principal": { "Service": [ "codebuild.amazonaws.com", "codepipeline.amazonaws.com" ] }, "Action": "sts:AssumeRole" } ] }, "ManagedPolicyArns": [ { "Ref": "deployerPolicy" }, "arn:aws:iam::aws:policy/AWSCodeBuildDeveloperAccess" ], "Tags": [ { "Key": "ManagedBy", "Value": "CloudReactor" } ] } }, "deployerInstanceProfile": { "Type": "AWS::IAM::InstanceProfile", "Properties": { "Path": "/", "Roles": [ { "Ref": "deployerRole" } ] } }, "deployerUser": { "Type" : "AWS::IAM::User", "Properties" : { "UserName": { "Fn::If": [ "HasEnvSuffix", { "Fn::Join": [ "", [ "cloudreactor-deployer-", { "Ref": "DeploymentEnvironment" } ] ] }, "cloudreactor-deployer" ] }, "ManagedPolicyArns": [ { "Ref": "deployerPolicy" }, "arn:aws:iam::aws:policy/AWSCodeBuildDeveloperAccess" ], "Tags": [ { "Key": "ManagedBy", "Value": "CloudReactor" } ] } } } }