AWS Service Unable To Assume Role - amazon-web-services

I've two AWS Cloudformation stacks, one for IAM roles and the second to create an AWS service and import the respective roles into it using Cloudformation.
When 10+ services are deployed the following error appears randomly on 1 or 2 of the services -
AWS::ECS::Service service Unable to assume role and validate the
listeners configured on your load balancer. Please verify that the ECS
service role being passed has the proper permissions.
If all the services are torn down and the services redployed to the ECS cluster, the error appears but for different services.
The AWS fix for this can be seen here
If the 1 or 2 broken services are torn down and redeployed the services deploy without issue. So the problem appears to only occur when many services are deployed at the same time - this indicates it may be an IAM propagation timing issue within Cloudformation.
I've tried adding depends on in the service definition -
"service" : {
"Type" : "AWS::ECS::Service",
"DependsOn" : [
"taskdefinition",
"ECSServiceRole"
],
"Properties" : {
"Cluster" : { "Ref": "ECSCluster"},
"Role" : {"Ref" : "ECSServiceRole"},
etc...
}
}
But this doesn't work.
As you can note, I've also removed the IAM import value for the ECSServiceRole and replaced it with an inline resource policy seen here -
"ECSServiceRole" : {
"Type" : "AWS::IAM::Role",
"Properties" : {
"AssumeRolePolicyDocument" : {
"Statement" : [
{
"Sid": "",
"Effect" : "Allow",
"Principal" : {
"Service" : [
"ecs.amazonaws.com"
]
},
"Action" : [
"sts:AssumeRole"
]
}
]
},
"Path" : "/",
"Policies" : [
{
"PolicyName" : "ecs-service",
"PolicyDocument" : {
"Statement" : [
{
"Effect" : "Allow",
"Action" : [
"ec2:Describe*",
"ec2:AuthorizeSecurityGroupIngress",
"elasticloadbalancing:DeregisterInstancesFromLoadBalancer",
"elasticloadbalancing:DeregisterTargets",
"elasticloadbalancing:Describe*",
"elasticloadbalancing:RegisterInstancesWithLoadBalancer",
"elasticloadbalancing:RegisterTargets",
"sns:*"
],
"Resource" : "*"
}
]
}
}
]
}
}
But again - the inline policy doesn't fix the issue either.
Any ideas or pointers would be much appreciated!
In reply to answer 1.
Thank you - I wasn't aware of this improvment.
Is this the correct way to associate the service linked role for ECS?
"ECSServiceRole": {
"Type": "AWS::IAM::Role",
"Properties": {
"AssumeRolePolicyDocument": {
"Statement": [
{
"Sid": "",
"Effect": "Allow",
"Principal": {
"Service": [
"ecs.amazonaws.com"
]
},
"Action": [
"sts:AssumeRole"
]
}
]
},
"Path": "/",
"Policies": [
{
"PolicyName": "CreateServiceLinkedRoleForECS",
"PolicyDocument": {
"Statement": [
{
"Effect": "Allow",
"Action": [
"iam:CreateServiceLinkedRole",
"iam:PutRolePolicy",
"iam:UpdateRoleDescription",
"iam:DeleteServiceLinkedRole",
"iam:GetServiceLinkedRoleDeletionStatus"
],
"Resource": "arn:aws:iam::*:role/aws-service-role/ecs.amazonaws.com/AWSServiceRoleForECS*",
"Condition": {
"StringLike": {
"iam:AWSServiceName": "ecs.amazonaws.com"
}
}
}
]
}
}
]
}
}
Final Answer
After months of intermittent on-going issues with AWS regarding this matter AWS came back to say they were throttling us in the background, on the ELB. This is why the random and varied issues were appearing when deploying 3+ docker services via Cloudformation at the same time. The solution was nothing to do with IAM permissions, rather it was to increase the rate limit on the ELB via the "AWS Service Team".

So the fix was to continue using the two stack approach in Cloudformation, one with the IAM roles, which in turn were imported into the service layer stack. The fix was to add a depends on in the service definition for all of the other stack resources in the service layer script. By doing this it allows sufficient time for the IAM roles to be imported and executed by the service, thus this was a Cloudformation resource creation timing issue.
"service" : {
"Type" : "AWS::ECS::Service",
"DependsOn" : [
"TaskDefinition",
"EcsElasticLoadBalancer",
"DnsRecord"
],
"Properties" : {
etc...
}
}

UPDATE:
As of July 19th 2018, it is now possible to create a IAM Service-Linked Roles using CloudFormation https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iam-servicelinkedrole.html.
EcsServiceLinkedRole:
Type: "AWS::IAM::ServiceLinkedRole"
Properties:
AWSServiceName: "ecs.amazonaws.com"
Description: "Role to enable Amazon ECS to manage your cluster."
OLD ANSWER:
Creating your own ECSServiceRole is no longer required. By not specifying a role for your service, AWS will default on using the ECS Service-Linked role. If your AWS account is recent enough, or you have already created a cluster via the console you don't have to do anything for this to work. If not, run the following command to create the role: aws iam create-service-linked-role --aws-service-name ecs.amazonaws.com.

Related

CodeDeploy on EC2 - Missing credentials error

I have gone through lot of posts and articles but couldn't solve my problem, hence posting this questions.
I have set of python scripts and wanted to setup CI/CD with Github actions and CodeDeploy so when I push a commit to GitHub, the code is automatically deployed on EC2 instance where I have scheduled the scripts to run using Cron. I have configured Github to integrate with CodeDeploy and no issues there. On CodeDeploy, I created an IAM role CD_Role with below policies
AmazonEC2FullAccess
AmazonS3FullAccess
AWSCodeDeployFullAccess
AWSCodeDeployRole
AdministratorAccess
The AdministratorAccess I added recently to check if that can solve my problem but no luck. The trust relationship for this role looks like
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": "codedeploy.amazonaws.com"
},
"Action": "sts:AssumeRole"
}
]
}
When I created the EC2 instance, I actually had another role assigned EC2-Role and I tried replacing it with CD_Role when I wanted to start using CodeDeploy, but the role association was not happening properly, so I modified the EC2-Role to have same policies as CD_Role and the trust relationship looks like
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": [
"ec2.amazonaws.com",
"codedeploy.amazonaws.com"
]
},
"Action": "sts:AssumeRole"
}
]
}
Point to note here is that I deploy the CodeDeploy agent at a latter point of configuring EC2 and I tried rebooting the EC2 as well. Listing the instance profile associations gives me,
{
"IamInstanceProfileAssociations": [
{
"InstanceId": "i-XXX",
"State": "disassociating",
"AssociationId": "iip-assoc-RRR",
"IamInstanceProfile": {
"Id": "XXX",
"Arn": "arn:aws:iam::XXX:instance-profile/EC2-Role"
}
},
{
"InstanceId": "i-XXX",
"State": "associating",
"AssociationId": "iip-assoc-XXX",
"IamInstanceProfile": {
"Id": "XXX",
"Arn": "arn:aws:iam::XXX:instance-profile/CD_Role"
}
}
]
}
Since both the role have same policies assigned, I would expect the Deployment to work at some stage but I keep getting ERROR [codedeploy-agent(664)]: InstanceAgent::Plugins::CodeDeployPlugin::CommandPoller: Missing credentials - please check if this instance was started with an IAM instance profile
Can someone please guide to fix this issue?

AWS Api Gateway attach existing policy

Normally if I want to create a private AWS::ApiGateway::RestApi with policy only allowing VPC traffic to invoke any resources on the API I'd do something like so:
"ApiGatewayRestApi": {
"Type": "AWS::ApiGateway::RestApi",
"Properties": {
"Name": "api-foo-bar",
"EndpointConfiguration": {
"Types": [
"PRIVATE"
]
},
"Policy": {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": "*",
"Action": [
"execute-api:Invoke"
],
"Resource": "execute-api:/*",
"Condition": {
"StringEquals": {
"aws:SourceVpc": "vpc-000000000000"
}
}
}
]
}
}
}
I have been asked if we can create a policy and then reuse it for different Api Gateways we may create? something amongst the lines:
"ApiGatewayRestApi": {
"Type": "AWS::ApiGateway::RestApi",
"Properties": {
"Name": "api-foo-bar",
"EndpointConfiguration": {
"Types": [
"PRIVATE"
]
},
"Policy": "arn:aws:*whatever*"
}
},
And I have no idea! Nor can I find any documentation or examples showing that. Has anyone done this? Is it at all doable? Thanks :)
No, it's not doable currently. The policy you are attaching to the Api Gateway is Resource-based policy.
From aws documentation,
With resource-based policies, you can specify who has access to the
resource and what actions they can perform on it.
Aws documentation shows the type that each property in cloudformation can take. The following is the properties and the types allowed in "AWS::ApiGateway::RestApi"
{
"Type" : "AWS::ApiGateway::RestApi",
"Properties" : {
"ApiKeySourceType" : String,
"BinaryMediaTypes" : [ String, ... ],
"Body" : Json,
"BodyS3Location" : S3Location,
"CloneFrom" : String,
"Description" : String,
"DisableExecuteApiEndpoint" : Boolean,
"EndpointConfiguration" : EndpointConfiguration,
"FailOnWarnings" : Boolean,
"MinimumCompressionSize" : Integer,
"Mode" : String,
"Name" : String,
"Parameters" : {Key : Value, ...},
"Policy" : Json,
"Tags" : [ Tag, ... ]
}
}
Notice that Policy property takes the type of JSON. Furthermore, the documentation writes the following for the Policy property:
A policy document that contains the permissions for the RestApi
resource.
and gives us a hint that Policy property does not take the following form: "Policy": "arn:aws:*whatever*" and only accepts a policy document in the form of JSON as Api Gateway's resource-based policy.
ref:
https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigateway-restapi.html#cfn-apigateway-restapi-policy
https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies_identity-vs-resource.html
you can find the docs here.
Policy
A policy document that contains the permissions for the RestApi resource. To set the ARN for the policy, use the !Join intrinsic function with "" as delimiter and values of "execute-api:/" and "*".

Amazon EventBridge Policies for AWS Services as targets using CF/SAM

I'm using AWS CloudFormation to setup an EventBridge Bus + Rules + Targets (say SNS). For SNS as a target, per the doc at https://docs.aws.amazon.com/eventbridge/latest/userguide/resource-based-policies-eventbridge.html#sns-permissions, I need to apply resource policies outside of CloudFormation and I don't think CF supports this yet?
For CW Logs Group as a target, Im using the aws logs put-resource-policy to set this up in a script. Is there a better way to automate this?
The link you've provided refers to setting up permissions for SNS topic. Setting such permissions is supported by the CloudFormation by means of AWS::SNS::TopicPolicy.
However, you also state that you want to set resource-based policies on the CloudWatch Logs (aws logs put-resource-policy). If this is the case, then you are correct and it is not supported in CloudFormation.
You would have to use custom resource based on a lambda function to add such functionality to your templates.
Here is a snippet from my SAM:
{
"MyDevQueue": {
"Properties": {
"QueueName": "my-dev-queue",
"ReceiveMessageWaitTimeSeconds": 20,
"Tags": [
{
"Key": "env",
"Value": "dev"
}
],
"VisibilityTimeout": 300
},
"Type": "AWS::SQS::Queue"
},
"MyDevQueuePolicy": {
"Properties": {
"PolicyDocument": {
"Statement": [
{
"Action": [
"SQS:SendMessage"
],
"Condition": {
"ArnEquals": {
"aws:SourceArn": "arn:aws:events:<region>:<AccountID>:rule/my-dev-queue/my-dev-queue"
}
},
"Effect": "Allow",
"Principal": {
"Service": [
"events.amazonaws.com"
]
},
"Resource": [
{
"Fn::GetAtt": [
"MyDevQueue",
"Arn"
]
}
]
}
]
},
"Queues": [
"MyDevQueue"
]
},
"Type": "AWS::SQS::QueuePolicy"
}
}

AWS Redshift: Masteruser not authorized to assume role

I created a cloudformation stack with redshift cluster and a masteruser: testuser
"RedshiftCluster" : {
"IamRoles" : [
{
"Fn::GetAtt": [
"IAMInstanceRole",
"Arn"
]
}
]
... other configurations
It uses the below IAM role (IAMInstanceRole) which is in in-sync status and the redshift cluster is up and running:
"IAMInstanceRole": {
"Properties": {
"RoleName": "test-iam-role",
"AssumeRolePolicyDocument": {
"Statement": [
{
"Action": [
"sts:AssumeRole"
],
"Effect": "Allow",
"Principal": {
"Service": [
"ec2.amazonaws.com",
"redshift.amazonaws.com",
"s3.amazonaws.com"
]
}
}
]
},
"Path": "/",
"Policies": [
{
"PolicyName": "root",
"PolicyDocument": {
"Version" : "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "*",
"Resource": "*"
}
]
}
}
]
}
I'm trying to load csv file from s3 to redshift using copy command and iam_role as credential. The iam_role has the arn of IAMInstanceRole (declared above).
Whenever I execute the below command:
copy test_table from 's3://test-bucket/test.csv' CREDENTIALS 'aws_iam_role=arn:aws:iam::<account-id>:role/test-iam-role' MAXERROR 100000 removequotes TRIMBLANKS emptyasnull blanksasnull delimiter '|';
I get the error:
ERROR: User arn:aws:redshift:us-west-2:189675173661:dbuser:automated-data-sanity-redshiftcluster-fbp9fgls6lri/sanityuser is not authorized to assume IAM Role arn:aws:iam::189675173661:role/sanity-test-iam-instance-role
DETAIL:
-----------------------------------------------
error: User arn:aws:redshift:us-west-2:<account-id>:dbuser:test-redshiftcluster-fbp9fgls6lri/testuser is not authorized to assume IAM Role arn:aws:iam::<account-id>:role/test-iam-role
code: 8001
context: IAM Role=arn:aws:iam::<account-id>:role/test-iam-role
query: 1139
location: xen_aws_credentials_mgr.cpp:236
process: padbmaster [pid=29280]
-----------------------------------------------
Please suggest some resolution.
I ran into the same problem but after a good 1 hour of troubleshooting, I realised I had failed to add the Redshift role to the cluster while I was creating it. If you select the cluster from Redshift, choose the drop-down on 'Actions' and select 'Manage IAM roles' from there you will be able to attach the Redshift role you may have created for this cluster.
That solved the problem for me, anyways.
Hope this helps.
I resolved this issue !!
By default, IAM roles that are available to an Amazon Redshift cluster are available to all users on that cluster. You can choose to restrict IAM roles to specific Amazon Redshift database users on specific clusters or to specific regions.
To permit only specific database users to use an IAM role, take the following steps.
To identify specific database users with access to an IAM role
Identify the Amazon Resource Name (ARN) for the database users in your Amazon Redshift cluster. The ARN for a database user is in the format: arn:aws:redshift:region:account-id:dbuser:cluster-name/user-name.
Open the IAM Console at url="https://console.aws.amazon.com/.
In the navigation pane, choose Roles.
Choose the IAM role that you want to restrict to specific Amazon Redshift database users.
Choose the Trust Relationships tab, and then choose Edit Trust Relationship. A new IAM role that allows Amazon Redshift to access other AWS services on your behalf has a trust relationship as follows:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": "redshift.amazonaws.com"
},
"Action": "sts:AssumeRole"
}
]
}
Add a condition to the sts:AssumeRole action section of the trust relationship that limits the sts:ExternalId field to values that you specify. Include an ARN for each database user that you want to grant access to the role.
For example, the following trust relationship specifies that only database users user1 and user2 on cluster my-cluster in region us-west-2 have permission to use this IAM role.
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": "redshift.amazonaws.com"
},
"Action": "sts:AssumeRole",
"Condition": {
"StringEquals": {
"sts:ExternalId": [
"arn:aws:redshift:us-west-2:123456789012:dbuser:my-cluster/user1",
"arn:aws:redshift:us-west-2:123456789012:dbuser:my-cluster/user2"
]
}
}
}]
}
7.Choose Update Trust Policy.
Here's a template that works fine:
{
"AWSTemplateFormatVersion": "2010-09-09",
"Resources": {
"RedshiftRole": {
"Type": "AWS::IAM::Role",
"Properties": {
"RoleName": "Redshift-Role",
"AssumeRolePolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": [
"redshift.amazonaws.com"
]
},
"Action": [
"sts:AssumeRole"
]
}
]
},
"Path": "/",
"Policies": [
{
"PolicyName": "root",
"PolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "s3:*",
"Resource": "*"
}
]
}
}
]
}
},
"RedshiftSG": {
"Type": "AWS::EC2::SecurityGroup",
"Properties": {
"GroupName": "Redshift Security Group",
"GroupDescription": "Enable access to redshift",
"VpcId": "vpc-11223344",
"SecurityGroupIngress": [
{
"IpProtocol": "tcp",
"FromPort": 5439,
"ToPort": 5439,
"CidrIp": "0.0.0.0/0"
}
],
"Tags": [
{
"Key": "Name",
"Value": "Redshift Security Group"
}
]
}
},
"RedshiftCluster": {
"Type": "AWS::Redshift::Cluster",
"Properties": {
"ClusterType": "single-node",
"NodeType": "dc2.large",
"MasterUsername": "master",
"MasterUserPassword": "YourPassword",
"IamRoles": [
{
"Fn::GetAtt": [
"RedshiftRole",
"Arn"
]
}
],
"VpcSecurityGroupIds": [
{
"Ref": "RedshiftSG"
}
],
"PubliclyAccessible": true,
"Port": 5439,
"DBName": "foo"
}
}
}
}
Be sure to insert your own VpcId in the security group.
The Role can be assumed by Redshift and grants access to s3:* (which you should reduce in scope).
I was trying to access Glue data catalog from Redshift. I created the role with the necessary policies attached (AWSGlueServiceRole, AmazonS3FullAccess), and added it to the cluster. However, I had set the AWS service as Glue but it should've been Redshift since Redshift is the service needing the access. Attaching these policies the Redshift role I have (and adding the role to the cluster, if necessary) solved the problem for me.
Resolved it
Complete Steps followed :
Create s3 bucket in the same region as redshift ( move-redshift-data)
create a folder inside it. ( move-redshift-data)
create an IAM role (move-redshift-data-role) ,attach S3Fullaccesss and add the following to trust relationship
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::126111577039:root”
},
"Action": "sts:AssumeRole"
}
]
}
where 126111577039 is the account ID of redshift cluster
Find you already attached role to your cluster
Open your redshift cluster
Click on actions -->Manage IAM roles
You could see the role (mine is RedshiftDynamoDBAccess)
Open the role in IAM console and attach the following inline policy to it .
Add below policy to the role already associated to redshift cluster (See in manage cluster)
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"sts:AssumeRole"
],
"Resource": "arn:aws:iam::888850378087:role/move-redshift-data-role"
}
]
}
where 888850378087 : account which has s3 bucket in it and move-redshift-data role
Finally Run command
unload ('select * from sellercompliancestate')
to 's3://unload-swarnimg/unload-swarnimg/'
iam_role 'arn:aws:iam::126111577039:role/RedshiftDynamoDBAccess,arn:aws:iam::888850378087:role/move-redshift-data-role'
allowoverwrite
format as csv;
Got the solution after searching for a while. I created separate IAM role for redshift as John suggested, which is a correct advice but was not the issue in my case.
Then followed the thread to resolve the issue: Copy from remote S3 using IAM Role - not authorized to assume IAM Role
I'd to activate the region where my cluster was in Account Settings
I solved by editing function like this
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": [
"sagemaker.amazonaws.com",
"redshift.amazonaws.com"
]
},
"Action": "sts:AssumeRole"
}
]
}
I add "sagemaker.amazonaws.com" to my function AmazonRedshiftML
Function
I figured it out.
There is no use of deleting a cluster, rebooting or managing IAM Roles in redshift Cluster.
Though I did all above many times, still I was getting the error. Then I tried below steps.
Give Access Key Id and secret Key in COPY command, instead of IAM role. Example as below.
copy users from 's3://awssampledbuswest2/tickit/allusers_pipe.txt'
credentials 'aws_access_key_id=;SKDFHSJKD;aws_secret_access_key=SDJHFJHajhsdjh'
delimiter '|' region 'us-west-2';

Specifying ARN for a ElastiCache Cluster in Multiple region

In my cloudformation template I am creating a policy for ElastiCache cluster which is set to have availability in Multiple region, how should I specify the ARN for the ElasticCache cluster.
From the AWS docs
http://docs.aws.amazon.com/general/latest/gr/aws-arns-and-namespaces.html#arn-syntax-elasticache
I'm skipping the cluster-region name below, is this is the way to do this.
"ElastiCachePolicy" :{
"Type" : "AWS::IAM::Policy",
"Properties" : {
"PolicyName" : "ElastiCache",
"PolicyDocument" : {
"Version": "2012-10-17",
"Statement": [
{
"Action": "elasticache:*",
"Effect": "Allow",
"Resource": "arn:aws:elasticache::account-id:cluster:cluster-name"
}]
},
"Roles": [ { "Ref": "SomeRole" }]
}
}
Got it I got confused between specifying the region with availability zones. I had to specify the region-id regardless of the cluster availability zones.