AWS Cloudformation DB Instance IAM Roles - amazon-web-services

I'm trying to associate an IAM role with by DB Instance as documented here:
https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/AuroraMySQL.Integrating.Authorizing.IAM.AddRoleToDBCluster.html
I can do it via the UI and see if via:
aws rds describe-db-instances --db-instance-identifier=myInstanceName
...
"AssociatedRoles": [
{
"RoleArn": "arn:aws:iam::123456789123:role/myRoleName",
"FeatureName": "s3Import",
"Status": "ACTIVE"
}
]
...
However I cannot find any reference of how to set this via cloud formation.
I tried setting AssociatedRoles but it fails saying:
Encountered unsupported property AssociatedRoles

I think you can't do it with CloudFormation (unless, of course, you build a custom resource, but if you don't know how to do it already it will be an overkill).

Related

How to solve this? AWS updateAutoScalingGroup - error: AccessDenied: You are not authorized to use launch template

(Solved)
I missed this mention on the aws user guide You can use the AmazonEC2FullAccess policy to give users complete access to work with Amazon EC2 Auto Scaling resources, launch templates, and other EC2 resources in their AWS account
Now I added permissions as same as on the AmazonEC2FullAccess policy on my custom policy, and the lambda is working well.
The AmazonEC2FullAccess has full permissions of CloudWatch, EC2, EC2 Auto Scaling, ELB, ELB v2, and limited IAM write permission.
#Marcin _ Thanks! your comment made me check this part.
I'm trying to update the ASG with 'updateAutoScalingGroup' API on lambda.
But this error "AccessDenied: You are not authorized to use launch template" is blocking me...
At the first time, I applied only related permissions on the IAM policy depend on the document, but now I allowed full permissions of EC2 and Autoscaling on the policy to solve this issue.
But no lucks.
On google, I saw some posts that saying this is just an error, or issue from AMI existence.
But my AMI for the launch template is in the same account, same region...
Could you give me some hint or reference to solve this?
Thanks
const AWS = require('aws-sdk')
exports.handler = (event) => {
const autoscaling = new AWS.AutoScaling()
const { asgName, templateName, version } = event
const params = {
AutoScalingGroupName: asgName,
LaunchTemplate: {
LaunchTemplateName: templateName,
Version: version
},
MaxSize: 4,
MinSize: 1,
DesiredCapacity: 1
}
autoscaling.updateAutoScalingGroup(params, async (err, data)=> {
if(err) console.log("err---", err)
else console.log("data---", data)
})
};
Below was added after the comments from Marcin, John Rotenstein, samtoddler
Now the policy has full permission for EC2, EC2 Auto Scaling, EC2 Image Builder, Auto Scaling, and some permissions on CloudWatch Logs. But no lucks yet.
The AMI is in the same account, same region. And I added the account number on the 'Modify Image Permissions' on it. (I don't know well on this but just tried.)
describeLaunchTemplates() shows the launchTemplate which I want to use.
CloudTrail shows 'RunInstances' and 'UpdateAutoScalingGroup' events. 'RunInstances' returned "errorCode": "Client.UnauthorizedOperation", and 'UpdateAutoScalingGroup' returned "errorCode": "AccessDenied", "errorMessage": "An unknown error occurred"
Without LaunchTemplate part, API is working well. (I tried update the min and max count only, and it succeed.)
Even I changed AMI as public, it's not working for this.
Now I'm trying to search about launch template and AMI related configuration..
Unfortunately, the errors provided by AWS in some cases are very unclear and could mislead.
Besides checking that you have the proper rights, this error is also returned when you are trying to create an autoscaling group with an invalid AMI or one that doesn't exist.
Actually, problem is your EC2 instance is having an IAM Role which you are not authorised to use it. Add below policy to lambda or whatever role or IAM user you using to pass the role that is attached to EC2 instance. Once that is done it will start working.
{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Action": [
"iam:GetRole",
"iam:PassRole"
],
"Resource": "arn:aws:iam::account-id:role/EC2-roles-for-XYZ-*"
}]
}

The actual ec2 instance does not get the iam instance profile that Elastic Beanstalk creates and says the environment has. How do make this happen?

I am using boto3 to create Elastic Beanstalk applications and environments remotely. I want one of these environments to call other AWS services using boto3. My understanding is that Elastic Beanstalk "creates a default instance profile, called aws-elasticbeanstalk-ec2-role, and assigns managed policies with default permissions to it." (from https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/iam-instanceprofile.html)
That page also states "An instance profile is a container for an AWS Identity and Access Management (IAM) role that you can use to pass role information to an Amazon EC2 instance when the instance starts."
When I inspect the Elastic Beanstalk Environment's configuration on the web console I see IAM instance profile: aws-elasticbeanstalk-ec2-role under the Security heading.
However, my instance cannot call boto3 functions without an error botocore.exceptions.NoCredentialsError: Unable to locate credentials.
When I inspect the ec2 instance on the console I see nothing under IAM role. If I set the IAM role from here the instance is then able to call boto3 functions.
How do I go about getting the ec2 instance to automatically inherit the IAM role .. or how do I specify that role to be set or indeed another custom role?
If we take a look the boto3 "create_environment()" function definition, we have an option to specify "optionSettings"
OptionSettings=[
{
'ResourceName': 'string',
'Namespace': 'string',
'OptionName': 'string',
'Value': 'string'
},
]
We can use this to explicitly specify the IAM instance profile to be attached to the EC2 instances launched as a part of your Beanstalk environment.
The Option setting to use would be "aws:autoscaling:launchconfiguration", option name : IamInstanceProfile, who's default value is "NONE". Specify the Instance profile name or ARN for value.
You get the instance profile from the metadata: curl -s 169.254.169.254/latest/meta-data/iam/info

how to update AWS ECS Container Agent on Fargate launch type instances

I am trying to configure AWS ECS using awsvpc mode with an IAM role to use specifically for tasks. Our ECS instances are of fargate launch types. After specifying a Task IAM role in the task configuration, we ssh into our task and try to run awscli commands and get the following error:
Unable to locate credentials. You can configure credentials by running "aws configure".
In order to troubleshoot, we ran the same docker image in a container with an EC2 launch type and when we ran the same awscli command, it errors by saying the assumed role does not have sufficient permissions. We noticed that this was because it was assuming the container instance IAM role, rather than the Task IAM role.
Based on the documentation here, it is clear that when using awsvpc networking mode, we need to set the ECS_AWSVPC_BLOCK_IMDS agent configuration variable to true in the agent configuration file and restart the agent in order for our instances to assume the Task IAM role rather than the container instance IAM role.
For the time being, for performance testing purposes, we need to deploy with the Fargate launch type and according to the docs, the container agent should be installed automatically for Fargate:
The Amazon ECS container agent is installed on the AWS managed infrastructure used for tasks using the Fargate launch type. If you are only using tasks with the Fargate launch type no additional configuration is needed and the content in this topic does not apply.
However, we still need to be able to assume our task IAM role. Is there a way to update the necessary environment variable in the AWS-managed agent configuration file so as to allow the assuming of the task IAM role? Or is there another way to allow this?
When creating the task definition for your Fargate Task, are you assigning a Task Role ARN? There are two IAM ARNs needed. The Execution Role ARN is the IAM role to start the container in your Fargate cluster and uses permissions to setup the CloudWatch logs and possibly pulling an image from ECR. The Task Role ARN is the IAM Role that the container has. Make sure the Task Role ARN has the ECS Trust Relationship.
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": "ecs-tasks.amazonaws.com"
},
"Action": "sts:AssumeRole"
}
]
}

How to use AWS ECS Task Role in Node AWS SDK code

Code that uses the AWS Node SDK doesn't seem to be able to gain the role permissions of the ECS task.
If I run the code on an EC2 ECS instance, the code seems to inherit the role on the instance, not of the task.
If I run the code on Fargate, the code doesn't get any permission.
By contrast, any bash scripts that run within the instance seem to have the proper permissions.
Indeed, the documentation doesn't mention this as an option for the node sdk, just:
Loaded from IAM roles for Amazon EC2 (if running on EC2),
Loaded from the shared credentials file (~/.aws/credentials),
Loaded from environment variables,
Loaded from a JSON file on disk,
Hardcoded in your application
Is there any way to have your node code gain the permissions of the ECS task?
This seems to be the logical way to pass permissions to your code. It works beautifully with code running on an instance.
The only workaround I can think of is to create one IAM user per ECS service and pass the API Key/Secret as environmental variables in the task definition. However, that doesn't seem very secure since it would be visible in plain text to anyone with access to the task definition.
Your question is missing a lot of details on how you setup your ECS Cluster plus I am not sure if the question is for ECS or for Fargate specifically.
Make sure that you are using the latest version of the SDK. Javascript supports ECS and Fargate task credentials.
Often there is confusion about credentials on ECS. There is the IAM role that is assigned to the Cluster EC2 instances and the IAM role that is assigned to ECS tasks.
The most common problem is the "Trust Relationship" has not been setup on the ECS Task Role. Select your IAM role and then the "Trust Relationships" tab and make sure that it looks like this:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "",
"Effect": "Allow",
"Principal": {
"Service": "ecs-tasks.amazonaws.com"
},
"Action": "sts:AssumeRole"
}
]
}
In addition to the standard Amazon ECS permissions required to run tasks and services, IAM users also require iam:PassRole permissions to use IAM roles for tasks.
Next verify that you are using the IAM role in the task definition. Specify the correct IAM role ARN in the Task Role field. Note that this different than Task Execution Role (which allows containers to pull images and publish logs).
Next make sure that your ECS Instances are using the latest version of the ECS Agent. The agent version is listed on the "ECS Instances" tab under the right hand side column "Agent version". The current version is 1.20.3.
Are you using an ECS optimized AMI? If not, add --net=host to your docker run command that starts the agent. Review this link for more information.
I figured it out. This was a weird one.
A colleague thought it would be "safer" if we call Object.freeze on proccess.env. This was somehow interfering with the SDK's ability to access the credentials.
Removed that "improvement" and all is fine again. I think the lesson is "do not mess with process.env".

Why is my Elastic Beanstalk app denied PutItem access to my DynamoDB, despite its role?

The goal
I want to programmatically add an item to a table in my DynamoDB from my Elastic Beanstalk application, using code similar to:
Item item = new Item()
.withPrimaryKey(UserIdAttributeName, userId)
.withString(UserNameAttributeName, userName);
table.putItem(item);
The unexpected result
Logs show the following error message, with the [bold parts] being my edits:
User: arn:aws:sts::[iam id?]:assumed-role/aws-elasticbeanstalk-ec2-role/i-[some number] is not authorized to perform: dynamodb:PutItem on resource: arn:aws:dynamodb:us-west-2:[iam id?]:table/PiggyBanks (Service: AmazonDynamoDBv2; Status Code: 400; Error Code: AccessDeniedException; Request ID: [the request id])
I am able to get the table just fine, but things go awry when PutItem is called.
The configuration
I created a new Elastic Beanstalk application. According to the documentation, this automatically assigns the application a new role, called:
aws-elasticbeanstalk-service-role
That same documentation indicates that I can add access to my database as follows:
Add permissions for additional services to the default service role in the IAM console.
So, I found the aws-elasticbeanstalk-service-role role and added to it the managed policy, AmazonDynamoDBFullAccess. This policy looks like the following, with additional actions removed for brevity:
{
"Version": "2012-10-17",
"Statement": [
{
"Action": [
"dynamodb:*",
[removed for brevity]
"lambda:DeleteFunction"
],
"Effect": "Allow",
"Resource": "*"
}
]
}
This certainly looks like it should grant the access I need. And, indeed, the policy simulator verifies this. With the following parameters, the action is allowed:
Role: aws-elasticbeanstalk-service-role
Service: DynamoDB
Action: PutItem
Simulation Resource: [Pulled from the above log] arn:aws:dynamodb:us-west-2:[iam id?]:table/PiggyBanks
Update
In answer to the good question by filipebarretto, I instantiate the DynamoDB object as follows:
private static DynamoDB createDynamoDB() {
AmazonDynamoDBClient client = new AmazonDynamoDBClient();
client.setRegion(Region.getRegion(Regions.US_WEST_2));
DynamoDB result = new DynamoDB(client);
return result;
}
According to this documentation, this should be the way to go about it, because it is using the default credentials provider chain and, in turn, the instance profile credentials,
which exist within the instance metadata associated with the IAM role
for the EC2 instance.
[This option] in the default provider chain is available only when
running your application on an EC2 instance, but provides the greatest
ease of use and best security when working with EC2 instances.
Other things I tried
This related Stack Overflow question had an answer that indicated region might be the issue. I've tried tweaking the region with no additional success.
I have tried forcing the usage of the correct credentials using the following:
AmazonDynamoDBClient client = new AmazonDynamoDBClient(new InstanceProfileCredentialsProvider());
I have also tried creating an entirely new environment from within Elastic Beanstalk.
In conclusion
By the error in the log, it certainly looks like my Elastic Beanstalk application is assuming the correct role.
And, by the results of the policy simulator, it looks like the role should have permission to do exactly what I want to do.
So...please help!
Thank you!
Update the aws-elasticbeanstalk-ec2-role role, instead of the aws-elasticbeanstalk-service-role.
This salient documentation contains the key:
When you create an environment, AWS Elastic Beanstalk prompts you to provide two AWS Identity and Access Management (IAM) roles, a service role and an instance profile. The service role is assumed by Elastic Beanstalk to use other AWS services on your behalf. The instance profile is applied to the instances in your environment and allows them to upload logs to Amazon S3 and perform other tasks that vary depending on the environment type and platform.
In other words, one of these roles (-service-role) is used by the Beanstalk service itself, while the other (-ec2-role) is applied to the actual instance.
It's the latter that pertains to any permissions you need from within your application code.
To load your credentials, try:
InstanceProfileCredentialsProvider mInstanceProfileCredentialsProvider = new InstanceProfileCredentialsProvider();
AWSCredentials credentials = mInstanceProfileCredentialsProvider.getCredentials();
AmazonDynamoDBClient client = new AmazonDynamoDBClient(credentials);
or
AmazonDynamoDBClient client = new AmazonDynamoDBClient(new DefaultAWSCredentialsProviderChain());