I'm trying to set up CodePipeline with an ECS blue/green deployment where the deployment is in a different AWS account.
I've been using the two guides for ECS Blue/Green and CodePipeline cross-account deployments. CodePipeline lives in Account A along with its KMS Key, S3 artifact bucket and ECR repository. The ECS cluster lives in Account B with the CodeDeploy setup.
The ECR, KMS key and S3 buckets have cross-account permissions (these give a different error when wrong). The cluster starts up and runs, and CodeDeploy works correctly when invoked inside Account B.
A role in Account B has been created for CodePipeline to assume and it has granted Account A permission to assume the role. This role currently has the AWSCodeDeployRoleForECS policy (I intend to reduce this once it works)
CodePipeline fails with an unhelpful message of
"code": "PermissionError",
"message": "The provided role does not have sufficient permissions to access CodeDeploy"
}```
The codepipeline role does have permission to access codedeploy as it's in the canned AWS policy. I can only assume there's some missing permission but I cannot find out what from this message.
I've discovered the answer after tracing through CloudTrail. There were two permissions missing from the CodePipeline deployment role which I can't find documented, they are ecs:RegisterTaskDefinition and iam:PassRole for the ECS Container role. CodeDeploy assumes a different role during deployment that also needs these permissions, but it looks like CodePipeline needs them to start the deployment.
The documentation I was working off had an example for CodeDeploy cross-account, but this was CodeDeploy to EC2 rather than to ECS.
My final permissions for the role assumed in Account B by CodePipeline looks like:
{
"Version": "2012-10-17",
"Statement": [
{
"Action": [
"codedeploy:CreateDeployment",
"codedeploy:GetDeployment",
"codedeploy:GetDeploymentConfig",
"codedeploy:GetApplicationRevision",
"codedeploy:RegisterApplicationRevision",
"codedeploy:GetApplication",
"ecs:RegisterTaskDefinition"
],
"Resource": "*",
"Effect": "Allow"
},
{
"Action": [
"s3:GetObject*",
"s3:PutObject",
"s3:PutObjectAcl"
],
"Resource": "arn:aws:s3:::deployment_intermediate_bucket/*",
"Effect": "Allow"
},
{
"Action": [ "s3:ListBucket"],
"Resource": "arn:aws:s3:::deployment_intermediate_bucket",
"Effect": "Allow"
},
{
"Effect": "Allow",
"Action": [
"kms:DescribeKey",
"kms:GenerateDataKey*",
"kms:Encrypt",
"kms:ReEncrypt*",
"kms:Decrypt"
],
"Resource": [
"deployment_kms_key_arn"
]
},
{
"Action": [
"iam:PassRole"
],
"Effect": "Allow",
"Resource": "ecs_container_role_arn"
}
]
}
I'm going to reduce this down to the minimum required.
To maybe help here, having had the same issue/error:
Using Cloud-formation, I have a pipeline in account a, with an ecs bluegreen action in account b (TestingAccount):
- Name: !Sub BlueGreenDeploy
Actions:
- Name: BlueGreenDeploy
InputArtifacts:
# - Name: PrepareCodeDeployOutput
- Name: !Ref SourceArtifactName
Region: !Ref DeployRegion1
ActionTypeId:
Category: Deploy
Owner: AWS
Version: '1'
Provider: CodeDeployToECS
RoleArn: !Sub arn:aws:iam::${TestingAccountId}:role/######/CrossAccountsDeploymentRole
Configuration:
AppSpecTemplateArtifact: !Ref SourceArtifactName
AppSpecTemplatePath: appspec.json
ApplicationName: ronantest1
DeploymentGroupName: ronantest1
TaskDefinitionTemplateArtifact: !Ref SourceArtifactName
TaskDefinitionTemplatePath: taskdef.json
Image1ArtifactName: !Ref SourceArtifactName
Image1ContainerName: "IMAGE1_NAME"
RunOrder: 4
In the task definition that I was trying to deploy, I had the following roles listed:
"taskRoleArn"
"executionRoleArn"
The role that the pipeline assumed in the target account, i.e:
arn:aws:iam::${TestingAccountId}:role/######/CrossAccountsDeploymentRole
It needed to be able to pass both those roles listed in the Task definition.
Hope that makes sense and helps. AWS does not make this stuff easy from their documentation.
Related
I am using Service Catalog to execute the SSM Automation Document, so my Service Catalog has its own Role called "My_END_USER_Role", and I've created another role with permission to stop the EC2 for SSM Automation Document.
My_END_USER_Role this roles has the AWSServiceCatalogEndUserFullAccess, the easy solution is to give this role directly the permission that I need but I do not want the user out of the Service Catalog do any action like stop EC2, so I want to assume MY_SSM_ROLE with extra permission, but I get this error
An error occurred (InvalidAutomationExecutionParametersException) when calling the StartAutomationExecution operation: The defined assume role is unable to be assumed.
base on AWS Troubleshooting - section Assume Role Can't Be Assumed either is role not existed which cannot be true for me or The assume role doesn't have a trust relationship with the Systems Manager service, now I am stuck here how should I give the trust relationship!!?
SSM Automation Document
description: Stop EC2 Instance
schemaVersion: '0.3'
assumeRole: '{{ AutomationAssumeRole }}'
parameters:
AutomationAssumeRole:
type: String
default: 'arn:aws:iam::ACCOUNTID:role/MY_SSM_ROLE'
description: The ARN of the role that allows Automation to perform the actions on your behalf.
InstanceId:
type: 'AWS::EC2::Instance::Id'
mainSteps:
- name: StopInstance
action: 'aws:changeInstanceState'
inputs:
InstanceIds:
- '{{ InstanceId }}'
DesiredState: stopped
just for a test I gave MY_SSM_ROLE the admin permission and also includes this policy:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "VisualEditor0",
"Effect": "Allow",
"Action": [
"sts:AssumeRole",
"iam:PassRole",
"ssm:StartAutomationExecution"
],
"Resource": "*"
}
]
}
found the solution, I had to add a proper services to trust relationship for MY_SSM_ROLE Role.
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": [
"ssm.amazonaws.com",
"iam.amazonaws.com"
]
},
"Action": "sts:AssumeRole"
}
]
}
I have bootstrapped CDK toolkit stack in this way
npx cdk bootstrap \
--trust 158******206 \
--toolkit-stack-name **** \
--qualifier ****\
--cloudformation-execution-policies arn:aws:iam::aws:policy/AdministratorAccess \
As a result, CDK toolkit stack has these resources:
ContainerAssetsRepository
DeploymentActionRole
FileAssetsBucketEncryptionKey
FileAssetsBucketEncryptionKeyAlias
FilePublishingRole
FilePublishingRoleDefaultPolicy
ImagePublishingRole
ImagePublishingRoleDefaultPolicy
StagingBucket
StagingBucketPolicy
Then I try to deploy CDK stack via IAM user and it's work correctly. I use this command:
cdk deploy --require-approval never --toolkit-stack-name **** --profile user-1
If I try deploy via STS I received this error
Error: Could not assume role in target account (did you bootstrap the environment with the right '--trust's?): User: arn:aws:sts::448*****770:assumed-role/cdktoolkit-test-role/91cb8d5a-57e9-4d73-9f66-ddc630b637f2 is not authorized to perform: sts:TagSession on resource: arn:aws:iam::448*****770:role/cdk-event-proc-deploy-role-448******770-us-east-1
My iam-sts-config.yml
---
aws_iam:
- type: sts-access-keys
version: V2
config:
iam_assume_role_name: cdktoolkit-test-role
Then I add
AWS_ACCESS_KEY_ID=***
AWS_SECRET_ACCESS_KEY=***
AWS_SESSION_TOKEN=***
AWS_DEFAULT_REGION=***
There is my trust relationship policy for the role cdk-event-proc-deploy-role:
{
"Version": "2008-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::448******770:root"
},
"Action": "sts:AssumeRole"
},
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::158*****206:root"
},
"Action": "sts:AssumeRole"
}
]
}
If I edit and add manually "Action": "sts:TagSession" in to trust relationship policy. I can deploy my stack.
So, my question is, could I set up a custom trust relationship policy when I bootstrap CDK toolkit stack for my roles?
I found only this parameter --trust but it's added only a new Principal could I add additional Actions?
I have S3 bucket "cross-bucket" in Account say B.Now i want EC2 which is present in Account A to access this bucket "cross-bucket" in Account B.
I need to achieve this using IAM roles as we are not allowed to create users.
I have used below template to create role in Account B
AWSTemplateFormatVersion : '2010-09-09'
Description: 'Cross account role for S3'
Parameters:
AccountId:
Type: String
Description: Account ID of admin account (containing user to allow)
Resources:
CrossAccountRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Statement:
- Effect: Allow
Action: sts:AssumeRole
Principal:
AWS:
- !Sub arn:aws:iam::${AccountId}:root
Path: /
Policies:
- PolicyName: my-s3-delegate
PolicyDocument:
Statement:
- Effect: Allow
Action:
- s3:ListBucket
- s3:GetObject
Resource: "*"
RootInstanceProfile:
Type: "AWS::IAM::InstanceProfile"
Properties:
Path: "/"
Roles:
-
Ref: "CrossAccountRole"
After creating this role how should i attach this to instance present in Account A?
Or i am missing something here?
Your situation is:
Amazon EC2 instance in Account-A
Amazon S3 bucket in Account-B
You would like to allow the EC2 instance to access the bucket
There are two ways to do this:
Option 1: Bucket Policy
Simply add a bucket policy to the bucket in Account-B that grants access to the IAM Role used by the EC2 instance:
{
"Version": "2012-10-17",
"Statement": [
{
"Action": [
"s3:GetObject",
"s3:ListBucket"
],
"Effect": "Allow",
"Resource": [
"arn:aws:s3:::my-bucket",
"arn:aws:s3:::my-bucket/*"
],
"Principal": {
"AWS": [
"arn:aws:iam::ACCOUNT-A:role/my-ec2-role"
]
}
}
]
}
The EC2 instance will use its normal IAM Role credentials to access the bucket. Also make sure the IAM Role has given permission to use Amazon S3 to access the bucket:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:GetObject",
"s3:ListBucket"
],
"Resource": [
"arn:aws:s3:::bucket-b",
"arn:aws:s3:::bucket-b/*"
]
}
]
}
Option 2: Assume Role
Create an IAM Role in Account-B that has permission to access the bucket
Code on the EC2 instance calls AssumeRole() on the IAM Role
Use the returned credentials to access the bucket
After creating this role how should i attach this to instance present in Account A?
You are not attaching it to an instance in Acc A. Instead, you create an instance role in Acc A. The role will have permissions to assume the role from Acc B.
Thus, the instance role would have a policy similar to the following one:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "VisualEditor0",
"Effect": "Allow",
"Action": "sts:AssumeRole",
"Resource": "<ARN-of-ROLE-in-ACC-B>"
}
}
]
}
Then any application running on the instance would have to use sts assume-role to actually assume the role and perform actions in Acc B.
Does anyone know what should be the minimum IAM permissions that would allow a user creating an EKS cluster?
I'm assuming a role to just create a cluster with Terraform and that role has got the following statements in its policy defined (nothing more than that):
{
"Sid": "AllowEKSCreate",
"Effect": "Allow",
"Action": [
"eks:List*",
"eks:Describe*",
"eks:CreateCluster",
"ec2:Describe*"
],
"Resource": "*"
},
{
"Sid": "AllowEKSAll",
"Effect": "Allow",
"Action": "eks:*",
"Resource": "arn:aws:eks:eu-west-1:XXXXXXXXXX:cluster/my-cluster"
}
In CloudTrail I'am only seeing:
AWS access key: XXXXXXXX
AWS region: eu-west-1
Error code: AccessDenied
Event ID: XXXXXXXX
Event name: CreateCluster
Event source: eks.amazonaws.com
Successful events:
sts:GetCallerIdentity
ec2:DescribeAccountAttributes
No other event is present in CloudTrail that would be unsuccessful.
Found it!
The missing permission was iam:PassRole on the Cluster IAM Role resource.
For some reason CloudTrail does not reveal that information :(
P.S.
I think I made my question very clear so am wondering why someone would give me -1.
ECS Tasks can be assigned IAM Roles to make it possible to communicate with AWS APIs without having to pass user credentials to the Task.
This works for both AWS CLI and SDK. There is quite good documentation here but I couldn't find a proper example that covers all the details, I'll create a self-answer question to spare the pain for others.
I created a Git repo with the full example. The important bits are:
Creating an IAM Role Definition with an AssumeRolePolicyDocument.
Assigning the IAM Role to the Task.
Using the AWS JS SDK.
IAMRole:
Type: AWS::IAM::Role
Properties:
RoleName: !Sub role-task-${AWS::StackName} # Doesn't matter too much but let's make it nice anyway
Path: / # No idea about this one but / seems to work
# This is the funky stuff.. don't try to understand just copy-paste. Source: http://docs.aws.amazon.com/AmazonECS/latest/developerguide/task_IAM_role.html
AssumeRolePolicyDocument: |
{
"Statement": [{
"Effect": "Allow",
"Principal": { "Service": [ "ecs-tasks.amazonaws.com" ]},
"Action": [ "sts:AssumeRole" ]
}]
}
Policies:
- PolicyName: !Sub ecs-task-${AWS::StackName}
# You can add any actions here you want your container to be allowed to execute.
PolicyDocument:
{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Action": [
"cloudwatch:PutMetricData" # more actions if needed
],
"Resource": "*"
}]
}
The initialisation of the AWS SDK. The AWS SDK will automatically detect that the container has access to the Role credentials and initialise itself. You don't have to do any initialisation, besides creating the API objects.
var AWS = require('aws-sdk');
var cw = new AWS.CloudWatch();
var s3 = new AWS.S3();