How to assign IAM Role for ECS Task - amazon-web-services

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();

Related

AWS SSM DOcument Assume Role is unable to be assumed for Service Catalog

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"
}
]
}

Control Tower AWS - Share s3 bucket

I have recently started to use Control Tower from AWS to manage my multiple account environment.
My current question is:
I have a bucket belonging to the master account that I would like to share console access with some of the accounts of the organization. How can I do that? I have tried adding a bucket policy specifying the accounts and an SSO permission set attached to that account granting access to the bucket but when accessing with that role to s3 I can't see that bucket.
I am able to access the bucket through CLI but not through console, though. I.e. When accessing with the assigned role through CLI I am able to do aws s3 ls s3://mybucket and it shows the folders inside it (other commands work as well). But when doing aws s3 ls the bucket is not listed.
bucket policy:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "Example permissions",
"Effect": "Allow",
"Principal": {
"AWS": [
"123456789101",
"112131415161",
]
},
"Action": "s3:*",
"Resource": "arn:aws:s3:::mybucket"
}
]
}
permission set:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "Example",
"Effect": "Allow",
"Action": [
"s3:*"
],
"Resource": [
"arn:aws:s3:::mybucket",
"arn:aws:s3:::mybucket/*"
]
}
]
}
Does anyone know how to allow the users to list it with the rest of the account buckets and through the console on the s3 page?
Thank you!!
Daiana
As I understand ControlTower, you are not supposed to do anything meaningful in the root account.
Also, there is no shared Console access unless you allow other users to "federate" into the very same account where the bucket was created. Using the ControlTower this is usually done via Single-Sign-On (SSO)
My suggestion is: Create a Shared Services/Resources account and allow access to those resources to any member of your organization. Do this by making use of the new AWS:PrincipalOrgID. For example, see this CloudFormation Snippet for a central SNS queue with sns:Publish permission from within the AWS organization.:
Resources:
Topic:
Type: AWS::SNS::Topic
Properties:
DisplayName: Name
TopicName: name
TopicPolicy:
Type: AWS::SNS::TopicPolicy
Properties:
Topics:
- !Ref Topic
PolicyDocument:
Version: '2012-10-17'
Statement:
# default permission allow same account: https://www.terraform.io/docs/providers/aws/r/sns_topic_subscription.html
- Sid: __default_statement_ID
Effect: Allow
Principal:
AWS: "*"
Action:
- SNS:GetTopicAttributes
- SNS:SetTopicAttributes
- SNS:AddPermission
- SNS:RemovePermission
- SNS:DeleteTopic
- SNS:Subscribe
- SNS:ListSubscriptionsByTopic
- SNS:Publish
- SNS:Receive
Resource: !Ref Topic
Condition:
StringEquals:
AWS:SourceOwner: !Sub ${AWS::AccountId}
- Sid: SnsTopicPolicy
Effect: Allow
Principal:
AWS: "*"
Condition:
StringEquals:
# allow access from within your organization
AWS:PrincipalOrgID: "o-xxxxxxxxxx"
Action: sns:Publish
Resource: !Ref Topic

IAM - How to restrict access on queue creation?

Below is the rule:
- Effect: Allow
Action:
- "sqs:CreateQueue"
- "sqs:GetQueueAttributes"
- "sqs:DeleteQueue"
Resource: "*"
Condition:
ForAllValues:StringEquals:
cloudformation:TemplateUrl: !Sub "https://sqs.us-east-1.amazonaws.com/${AWS::AccountId}/some_queue*”
that we use to allow any Principal to create queues with name starting with some_queue*.
but am not sure, if I need to use Resource: "*" with Condition that restricts access to only create some_queue*
Can we rewrite this in a better way?
Below is the better version of the required policy:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "sqs:CreateQueue",
"Resource": "arn:aws:sqs:us-east-1:123456789:some_queue*"
}
]
}
You can limit the CreateQueue operation on a resource using wild cards.
For more details, check out the links below:
Amazon SQS API Permissions: Actions and Resource Reference
Basic Examples of IAM Policies for Amazon SQS

CodePipeline ECS Blue/Green Deployment cross account fails with PermissionError

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.

AWS Cloudwatch can not publish to SNS Topic with SSE

I have a Route53 health check, which submits its metrics into Cloudwatch, and finally Cloudwatch specifies thresholds and should send alerts through SNS.
However, I would like my SNS Topic to be encrypted. When I turn on SNS Topic encryption using the alias/aws/sns key I receive these messages in the Cloudwatch message history:
{
"actionState": "Failed",
"stateUpdateTimestamp": 123456778899,
"notificationResource": "arn:aws:sns:xx-region-y:zzzzzzzzzz:topic_name",
"publishedMessage": null,
"error": "null (Service: AWSKMS; Status Code: 400; Error Code: AccessDeniedException; Request ID: ccccccccccccccccccc)"
}
This appears to not be an IAM issue with Cloudwatch, but with SNS itself being unauthorized to use the KMS resources.
I enjoy using the IAM Policy Simulator for IAM users to identify where their permissions are lacking, but there doesn't seem to be a way to validate a Service's access to other services. Is that a thing I can manage?
https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies_testing-policies.html
I have also tried this with a CMK with the following policy:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "",
"Effect": "Allow",
"Principal": {
"Service": "sns.amazonaws.com"
},
"Action": [
"kms:GenerateDataKey*",
"kms:Decrypt"
],
"Resource": "*"
},
{
"Sid": "",
"Effect": "Allow",
"Principal": {
"Service": "route53.amazonaws.com"
},
"Action": [
"kms:GenerateDataKey*",
"kms:Decrypt"
],
"Resource": "*"
},
{
"Sid": "",
"Effect": "Allow",
"Principal": {
"Service": "events.amazonaws.com"
},
"Action": [
"kms:GenerateDataKey*",
"kms:Decrypt"
],
"Resource": "*"
},
{
"Sid": "",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::XXXXXXXX:role/OrganizationAccountAccessRole"
},
"Action": "kms:*",
"Resource": "*"
}
]
}
I'm pretty much throwing darts at a wall with the principals, but I think there's validation for sns.amazonaws.comfor SNS and events.amazonaws.com for Cloudwatch.
I received the exact same error, "null (Service: AWSKMS; Status Code: 400; Error Code: AccessDeniedException; Request ID: ccccccccccccccccccc)", when using a CMK in this manner as well. I can understand my CMK not working properly, but the Amazon managed key I think should just work out of the box.
I've tried using a CMK which grants sns.amazonaws.com and events.amazonaws.com with kms:* permissions. Same error.
Just summarizing the correct answer here because the accepted answer seems to be outdated:.
You cannot use the Amazon managed CMK alias/aws/sns because in order to connect cloudwatch with an SNS topic encrypted with a KMS CMK, you need to set a resource-policy/access-policy on the CMK so that cloudwatch service can perform kms:GenerateDataKey* and kms:Decrypt actions on the key and the access-policy on amazon managed keys cannot be edited.
For your case, you would need to create a customer managed symmetric CMK, and edit the access-policy to allow cloudwatch service principal to access that CMK. The access-policy will look like:
"Version": "2012-10-17",
"Id": "key-policies",
"Statement": [
{
"Sid": "Enable IAM User Permissions for administration of this key",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::xxxxxxxxxxxx:root"
},
"Action": "kms:*",
"Resource": "*"
},
{
"Sid": "Allow cloudwatch metric to use this key",
"Effect": "Allow",
"Principal": {
"Service": "cloudwatch.amazonaws.com"
},
"Action": [
"kms:Decrypt",
"kms:GenerateDataKey*"
],
"Resource": "*"
}
]
}
Update: It's likely this information is out of date. Please try the other answers and let everyone know if they work for you.
Apparently, CloudWatch can't send messages to encrypted SNS topics according to Protecting Amazon SNS Data Using Server-Side Encryption (SSE) and AWS KMS:
Currently, CloudWatch alarms don't work with Amazon SNS encrypted topics. For information about publishing alarms to unencrypted topics, see Using Amazon CloudWatch Alarms in the Amazon CloudWatch User Guide.
However, the blog post Encrypting messages published to Amazon SNS with AWS KMS seems to indicate you can...
🤦
The service is not "events.amazonaws.com", it is "cloudwatch.amazonaws.com". You should get the SNS notifications once you change this in the key policy.
See https://docs.aws.amazon.com/sns/latest/dg/sns-server-side-encryption.html for more information.
While some AWS services use an IAM Role in your account, others use a specific principal to be granted access instead. See https://aws.amazon.com/blogs/compute/encrypting-messages-published-to-amazon-sns-with-aws-kms/.
I think in your case you need to allow the cloudwatch principal, events.amazonaws.com, to be allowed to use the KMS key you specified, in the key's policy. See the section "Enabling compatibility between encrypted topics and event sources" in the above link.
Note that as the document says, "Several AWS services publish events to Amazon SNS topics. To allow these event sources to work with encrypted topics, you must first create a customer-managed CMK and then add the following statement to the policy of the CMK." This only works with customer managed keys.
Adding just the below events.amazon.com permissions to the KMS key's resource policy did the trick for me, specifically to allow AWS::Events::Rule that had encrypted SNS topics registered as Targets for 'FAILED' CodeBuild and CodePipeline states.
{
"Sid": "Allow Events use of key (for publishing to CMK encrypted SNS topics)",
"Effect": "Allow",
"Principal": {
"Service": "events.amazonaws.com"
},
"Action": [
"kms:Decrypt",
"kms:GenerateDataKey*"
],
"Resource": "*"
}
Hope this saves someone else some of the frustration and time this had caused me.
I ran into the same issue today! I see there are suggestions for granting the CMK to cloudwatch.amazonaws.com and also to events.amazonaws.com. For me, I needed to grant to both for that to work. Here is the entirety of my Cloudformation definition for the CMK.
InternalSNSKey:
Type: AWS::KMS::Key
Properties:
Description: IA-Internal-SNS Encryption Key
KeyPolicy:
Version: 2012-10-17
Id: allow-root-access-to-key
Statement:
- Sid: allow-root-to-delegate-actions
Effect: Allow
Principal:
AWS: !Sub arn:aws:iam::${AWS::AccountId}:root
Action:
- kms:*
Resource: '*'
- Sid: allow-cloudwatch-to-use-key
Effect: Allow
Principal:
Service: cloudwatch.amazonaws.com
Action:
- kms:Decrypt
- kms:GenerateDataKey*
Resource: '*'
- Sid: allow-events-to-use-key
Effect: Allow
Principal:
Service: events.amazonaws.com
Action:
- kms:Decrypt
- kms:GenerateDataKey*
Resource: '*'