Add sts:SetSourceIdentity to AssumeRolePolicyDocument in CDK - amazon-web-services

I am creating a role using the CDK and I need to add sts:SetSourceIdentity to the AssumeRolePolicyDocument.
My code looks like this currently:
new Role(this, 'MyRole', {
assumedBy: new AccountPrincipal(Stack.of(this).account),
...
});
This results in an AssumeRolePolicyDocument that looks like this:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::0123456789012:root"
},
"Action": "sts:AssumeRole"
}
]
}
I need it to look like this:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::0123456789012:root"
},
"Action": ["sts:AssumeRole", "sts:SetSourceIdentity"]
}
]
}
The generate CloudFormation from the CDK code above ends up like this:
"MyRoleCF2E104D": {
"Type": "AWS::IAM::Role",
"Properties": {
"AssumeRolePolicyDocument": {
"Statement": [
{
"Action": "sts:AssumeRole",
"Effect": "Allow",
"Principal": {
"AWS": {
"Fn::Join": [
"",
[
"arn:",
{
"Ref": "AWS::Partition"
},
":iam::0123456789012:root"
]
]
}
}
}
],
"Version": "2012-10-17"
},
...
},
I can't figure out how to get the sts:SetSourceIdentity added to the Action in the CloudFormation. Any ideas? Do I need to eject to the L1 construct?

addStatements adds new actions to the role's assume role policy document:
role.assumeRolePolicy?.addStatements(
new iam.PolicyStatement({
actions: ['sts:SetSourceIdentity'],
principals: [new iam.AccountPrincipal(this.account)],
})
);

Related

I am unable to add condition in resource based policy in lambda function using terraform

I want to add source_account in lambda resource-based policy condition. So I am executing below terraform code.
data "aws_caller_identity" "current" {
# Retrieves information about the AWS account corresponding to the
# access key being used to run Terraform, which we need to populate
# the "source_account" on the permission resource.
}
resource "aws_lambda_permission" "example" {
statement_id = "AllowExecutionFromS3Bucket"
action = "lambda:InvokeFunction"
function_name = "${aws_lambda_function.example.arn}"
principal = "s3.amazonaws.com"
source_account = "${data.aws_caller_identity.current.account_id}"
source_arn = "${aws_s3_bucket.example.arn}"
}
after applying terraform changes and doing plan I am unable to get (this is desired but not getting for S3)
{
"Version": "2012-10-17",
"Id": "default",
"Statement": [
{
"Sid": "lambda-8433be2d-00f7-48dc-9296-7c432662f91e",
"Effect": "Allow",
"Principal": {
"Service": "logs.us-east-1.amazonaws.com"
},
"Action": "lambda:InvokeFunction",
"Resource": "arn:aws:lambda:us-east-1:xxxxxxxxxxxx:function:yyyyyyyyyyyy",
"Condition": {
"StringEquals": {
"AWS:SourceAccount": "xxxxxxxxxxxx"
},
"ArnLike": {
"AWS:SourceArn": "arn:aws:logs:us-east-1:xxxxxxxxxxxx:log-group:/aws/lambda/lambda_handler:*"
}
}
}
]
}
I have tried many ways I am not getting any clue.
afer doing terraform plan i am getting below output :
module.environment.aws_lambda_permission.xxxxxxxxxxxx: Creating...
action: "" => "lambda:InvokeFunction"
function_name: "" => "arn:aws:lambda:us-east-1:yyyyyyyyyyyyyy:function:xxxxxxxxxxxx"
principal: "" => "s3.amazonaws.com"
source_arn: "" => "arn:aws:s3:::xxxxxxxxxxxx"
statement_id: "" => "AllowExecutionFromS3Bucket"
I am getting like this :
{
"Version": "2012-10-17",
"Id": "default",
"Statement": [
{
"Sid": "AllowExecutionFromS3Bucket",
"Effect": "Allow",
"Principal": {
"Service": "s3.amazonaws.com"
},
"Action": "lambda:InvokeFunction",
"Resource": "arn:aws:lambda:us-east-1:yyyyyyyyyy:function:xxxxxxxxxx",
"Condition": {
"ArnLike": {
"AWS:SourceArn": "arn:aws:s3:::xxxxxxxxxx"
}
}
}
]
}
I am able to add conditions using AWS CLI .
I am not using the root account. Someone please help me.
You just need to add source_account
resource "aws_lambda_permission" "allow_bucket" {
statement_id = "AllowExecutionFromS3Bucket"
action = "lambda:InvokeFunction"
function_name = "arn:aws:lambda:us-east-1:123456789123:function:mylambda"
principal = "s3.amazonaws.com"
source_account = "123456789123"
source_arn = "arn:aws:s3:::my-bucket"
}
will create
{
"Version": "2012-10-17",
"Id": "default",
"Statement": [
{
"Sid": "AllowExecutionFromS3Bucket",
"Effect": "Allow",
"Principal": {
"Service": "s3.amazonaws.com"
},
"Action": "lambda:InvokeFunction",
"Resource": "arn:aws:lambda:us-east-1:123456789123:function:mylambda",
"Condition": {
"StringEquals": {
"AWS:SourceAccount": "123456789123"
},
"ArnLike": {
"AWS:SourceArn": "arn:aws:s3:::my-bucket"
}
}
}
]
}

How do I correctly call a lambda function in another account from a lambda?

I'm having issues with calling a lambda in account B from a different lambda in account A.
Account A's role arn is arn:aws:iam::ACCOUNT_A:role/DeviceApiStack-simServiceRole427DA44E-1WS2T3INIV6IP
Account A's role name is DeviceApiStack-simServiceRole427DA44E-1WS2T3INIV6IP
Account B's role name is Chris-APIStack1-Q6AJ1PZ8V-LambdaCrossAccountExecut-1N3JU88L5AON1
Account B's role arn is arn:aws:lambda:us-east-1:462087996972:function:GetActiveDeviceIdsLambdaChris
For account A my lambda role has the following permissions:
{
"Version": "2012-10-17",
"Statement": [
{
"Action": "sts:AssumeRole",
"Resource": "arn:aws:iam::ACCOUNT_B:role/Chris-APIStack1-Q6AJ1PZ8V-LambdaCrossAccountExecut-1N3JU88L5AON1",
"Effect": "Allow"
},
{
"Action": "lambda:InvokeFunction",
"Resource": "*",
"Effect": "Allow"
},
{
"Action": "lambda:InvokeFunction",
"Resource": "arn:aws:iam::ACCOUNT_B:role/Chris-APIStack1-Q6AJ1PZ8V-LambdaCrossAccountExecut-1N3JU88L5AON1",
"Effect": "Allow"
}
]
}
My lambda in account B has the following role as defined using cloudformation:
"CrossAccountExecutionRoleDemo": {
"Type": "AWS::IAM::Role",
"Properties": {
"AssumeRolePolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:sts::ACCOUNT_A:role/DeviceApiStack-simServiceRole427DA44E-1WS2T3INIV6IP"
},
"Action": "sts:AssumeRole"
},
{
"Effect": "Allow",
"Principal": { "Service": ["lambda.amazonaws.com"] },
"Action": ["sts:AssumeRole"]
}
]
}
}
},
"CrossAccountExecutionPolicyDemo": {
"Type": "AWS::IAM::ManagedPolicy",
"Properties": {
"PolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "lambda:InvokeFunction",
"Resource": { "Fn::GetAtt": ["GetActiveDeviceIdsLambdaDemo", "Arn"] }
}
]
},
"Roles": [
{
"Ref": "CrossAccountExecutionRoleDemo"
}
]
}
}
When I make the following request I get an error
let roleArn = 'arn:aws:iam::ACCOUNT_B:role/Chris-APIStack1-Q6AJ1PZ8V-CrossAccountExecutionRol-1ANKXFZ6YS23'
sts.assumeRole(
{
RoleArn: roleArn,
RoleSessionName: 'NightlySimService',
}, function(err, res){ ... }
Error:
'
AccessDenied: User: arn:aws:sts::ACCOUNT_A:assumed-role/DeviceApiStack-simServiceRole427DA44E-1WS2T3INIV6IP/DeviceApiStack-nightlySimServiceLambdaA51B2AFE-JSUFU8F5BZGC is not authorized to perform: sts:AssumeRole on resource: arn:aws:iam::ACCOUNT_B:role/Chris-APIStack1-Q6AJ1PZ8V-CrossAccountExecutionRol-1ANKXFZ6YS23F
'
I can spot two apparent issues in the roles, which could be the cause of your errors.
First. Incorrect principle:
"Principal": {
"AWS": "arn:aws:sts::ACCOUNT_A:role/DeviceApiStack-simServiceRole427DA44E-1WS2T3INIV6IP"
},
As you wrote the role arn is arn:aws:iam::ACCOUNT_A:role/DeviceApiStack-simServiceRole427DA44E-1WS2T3INIV6IP, which does not match of what you provided in the Principal.
Second. Incorrect resource:
{
"Action": "lambda:InvokeFunction",
"Resource": "arn:aws:iam::ACCOUNT_B:role/Chris-APIStack1-Q6AJ1PZ8V-LambdaCrossAccountExecut-1N3JU88L5AON1",
"Effect": "Allow"
}
The action lambda:InvokeFunction applies to lambda functions, not IAM roles. Thus, the Resource should be ARN of the lambda.
There could be more issues, which are not that obvious at present.

How to give permissions to my uploaded aws lambda function?

I need to give permission for all logged users on my application.
This is my code:
this.amplifyService.auth().currentUserCredentials().then(credentials => {
const lambda = new Lambda({
credentials: this.amplifyService.auth().essentialCredentials(credentials)
});
lambda.invoke({
FunctionName: 'my-function',
}, res => {
console.log(res);
});
});
And this is the return:
authRole/CognitoIdentityCredentials is not authorized to perform: lambda:InvokeFunction on resource: arn:aws:lambda:us-east-2:function:my-function
I already try to create a IAM role manually:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "logs:CreateLogGroup",
"Resource": "arn:aws:logs:us-east-2:XXXXXXXXX:*"
},
{
"Effect": "Allow",
"Action": [
"logs:CreateLogStream",
"logs:PutLogEvents"
],
"Resource": [
"arn:aws:logs:us-east-2:XXXXX:log-group:/aws/lambda/my-function:*"
]
},
{
"Effect": "Allow",
"Action": [
"lambda:*"
],
"Resource": [
"arn:aws:lambda:us-east-2:XXXXXXXXX:function:my-function"
]
}
]
}
But doesn't work yet.

Planning to create a CFT which need 3 roles with managed policy and a inline policy attached to them

I am trying to create an CFT which has
1. 3 different roles with Managed policy
2. INline policy which should be added to three roles which are created in CFT.
But i could not do as this is throwing me error saying atleast one resource must be defined.
Please help me in achieving this.
{
"AWSTemplateFormatVersion": "2010-09-09",
"Resources": {
"EMRDefaultRole": {
"Type": "AWS::IAM::Role",
"Properties": {
"RoleName": "EMR_DefaultRole",
"AssumeRolePolicyDocument": {
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Principal": {
"Service": "elasticmapreduce.amazonaws.com"
},
"Action": "sts:AssumeRole"
}]
},
"ManagedPolicyArns": [
"arn:aws:iam::aws:policy/service-role/AmazonElasticMapReduceRole"
]
}
},
"EMREC2DefaultRole": {
"Type": "AWS::IAM::Role",
"Properties": {
"RoleName": "EMR_EC2_DefaultRole",
"AssumeRolePolicyDocument": {
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Principal": {
"Service": "ec2.amazonaws.com"
},
"Action": "sts:AssumeRole"
}]
},
"ManagedPolicyArns": [
"arn:aws:iam::aws:policy/service-role/AmazonElasticMapReduceforEC2Role"
]
}
},
"EMRAutoScalingDefaultRole": {
"Type": "AWS::IAM::Role",
"Properties": {
"RoleName": "EMR_AutoScaling_DefaultRole",
"AssumeRolePolicyDocument": {
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Principal": {
"Service": [ "elasticmapreduce.amazonaws.com",
"application-autoscaling.amazonaws.com"]
},
"Action": "sts:AssumeRole"
}]
},
"ManagedPolicyArns": [
"arn:aws:iam::aws:policy/service-role/AmazonElasticMapReduceforAutoScalingRole"
]
}
},
"EMRS3Policies": {
"Type": "AWS::IAM::Policy",
"Properties": {
"PolicyName": "Moodys-IAM-EMR-S3-Access-Policy",
"PolicyDocument": {
"Statement": [{
"Effect": "Allow",
"Action": [
"s3:HeadBucket",
"s3:GetObject"
],
"Resource": {
"Fn::Join": ["", ["arn:aws:s3:::mit-", {
"Ref": "AWS::AccountId"
}, "-emr-files/*"]]
}
}
]
},
"Roles": [{
"Ref": "EMRDefaultRole"},
{"Ref": "EMREC2DefaultRole"},
{"Ref": "EMRAutoScalingDefaultRole"
}]
}
}
}
}
Like i am expecting three Role where an managed policy and inline policy are attached.
You are missing resource attribute in your role statements.
"Statement": [{
"Effect": "Allow",
"Principal": {
"Service": [ "elasticmapreduce.amazonaws.com",
"application-autoscaling.amazonaws.com"]
},
"Action": "sts:AssumeRole"
}]
This should be (it holds for all of the statements)
"Statement": [{
"Effect": "Allow",
"Principal": {
"Service": [ "elasticmapreduce.amazonaws.com",
"application-autoscaling.amazonaws.com"]
},
"Action": "sts:AssumeRole",
"Resource": [
"arn-of-your-resource-or-wildcard"
]
}]

creating aws IAM Role using cloudformation does not create RolePolicies

I'm creating an ec2 instance with a role that provides access to kinesis streams and Dynamodb offset Tables. I am using aws cloudformation for that.
Problem I'm having is while creating the Streaming Access IAM Role itself.
So, I will have following structure,
has
StreamingAccessRole ----------> RolePolicy1(kinesis:*), RolePolicy2(dynamodb:*)
The template to create the AWS IAM role with two policies, one for kinesis and the other for dynamodb :
{
"AWSTemplateFormatVersion": "2010-09-09",
"Parameters": {
"teamIdentifier": {
"Type": "String",
"Default": "a28",
"Description": "Identifier for the team"
}
},
"Resources": {
"StreamingAccessRole": {
"Type": "AWS::IAM::Role",
"Properties": {
"AssumeRolePolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": [
"ec2.amazonaws.com"
]
},
"Action": [
"sts:AssumeRole"
]
}
]
},
"Path": "/a28/",
"Policies": [
{
"PolicyName": "Stream-ConsumerOffset-RW-AccessPolicy",
"PolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "kinesis:*",
"Resource": "arn:aws:kinesis:us-west-2:*:stream/a28-*"
},
{
"Effect": "Allow",
"Action": "dynamodb:*",
"Resource": "arn:aws:dynamodb:us-west-2:*:table/a28-*"
}
]
}
}
]
}
}
}
}
It creates the Access Role but without role-policies.
$ aws iam get-role --role-name a28-streaming-access-role-st-StreamingAccessRole-14QHMTIOIRN5X --region us-west-2 --profile aws-federated
{
"Role": {
"AssumeRolePolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Action": "sts:AssumeRole",
"Effect": "Allow",
"Principal": {
"Service": "ec2.amazonaws.com"
}
}
]
},
"RoleId": "AROAIFD6X2CJXTKLVQNLE",
"CreateDate": "2017-04-07T18:54:59Z",
"RoleName": "a28-streaming-access-role-st-StreamingAccessRole-14QHMTIOIRN5X",
"Path": "/a28/",
"Arn": "arn:aws:iam::500238854089:role/a28/a28-streaming-access-role-st-StreamingAccessRole-14QHMTIOIRN5X"
}
}
Listing the role-policies
$ aws iam list-role-policies --role-name a28-streaming-access-role-st-StreamingAccessRole-14QHMTIOIRN5X --region us-west-2 --profile aws-federated
{
"PolicyNames": []
}
which means it did not even create any policies,
aws iam list-policies --region us-west-2 --profile aws-federated | grep Stream-ConsumerOffset-RW-AccessPolicy
But if I supplied only kinesis:* statement in above example, it creates a policy, but not with dynamodb:* alone.
So, my question is how am supposed to provide multiple RolePolicies using one cloudformation AWS::IAM::Role template, or is this specific to dynamodb?
There's an intermittent race condition when you create the Policy in the Role. Create the Policy separately with AWS::IAM::Policy and set the Roles property to the Role. The problem will go away.
Your template worked perfectly fine for me.
I ran your template and then:
$ aws iam get-role --role-name stack1-StreamingAccessRole-1KDUTVG1OLLQM
{
"Role": {
"AssumeRolePolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Action": "sts:AssumeRole",
"Effect": "Allow",
"Principal": {
"Service": "ec2.amazonaws.com"
}
}
]
},
"RoleId": "AROAJADV75HTIM6C62YXQ",
"CreateDate": "2017-04-08T22:22:21Z",
"RoleName": "stack1-StreamingAccessRole-1KDUTVG1OLLQM",
"Path": "/a28/",
"Arn": "arn:aws:iam::123456789012:role/a28/stack1-StreamingAccessRole-1KDUTVG1OLLQM"
}
}
Listing the role-policies:
$ aws iam list-role-policies --role-name stack1-StreamingAccessRole-1KDUTVG1OLLQM
{
"PolicyNames": [
"Stream-ConsumerOffset-RW-AccessPolicy"
]
}
The policy is attached as an inline policy, so it will not appear in list-policies. Rather, use get-role-policy to view it:
$ aws iam get-role-policy --role-name stack1-StreamingAccessRole-1KDUTVG1OLLQM --policy-name Stream-ConsumerOffset-RW-AccessPolicy
{
"RoleName": "stack1-StreamingAccessRole-1KDUTVG1OLLQM",
"PolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Action": "kinesis:*",
"Resource": "arn:aws:kinesis:us-west-2:*:stream/a28-*",
"Effect": "Allow"
},
{
"Action": "dynamodb:*",
"Resource": "arn:aws:dynamodb:us-west-2:*:table/a28-*",
"Effect": "Allow"
}
]
},
"PolicyName": "Stream-ConsumerOffset-RW-AccessPolicy"
}
The reason could be race condition as already answered in this answer by Tim Bassett, I simply wanted to add final solution that worked, and how to add AWS::IAM::Policy to cloudformation.
{
"AWSTemplateFormatVersion": "2010-09-09",
"Description": "Some Streaming api devops",
"Parameters": {
"environment": {
"Type": "String",
"Default": "staging",
"Description": "environment"
}
},
"Resources": {
"StreamingAccessRole": {
"Type": "AWS::IAM::Role",
"Properties": {
"RoleName": "StreamingAccessRole",
"AssumeRolePolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": [
"ec2.amazonaws.com"
]
},
"Action": [
"sts:AssumeRole"
]
}
]
},
"Path": "/a28/"
}
},
"StreamConsumerOffsetRWAccessPolicy": {
"Type": "AWS::IAM::Policy",
"Properties": {
"PolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"cloudwatch:*"
],
"Resource": [
"*"
]
},
{
"Effect": "Allow",
"Action": "kinesis:*",
"Resource": "arn:aws:kinesis:us-west-2:051620159240:stream/a28-*"
},
{
"Effect": "Allow",
"Action": [
"dynamodb:BatchGetItem",
"dynamodb:BatchWriteItem",
"dynamodb:CreateTable",
"dynamodb:DeleteItem",
"dynamodb:DeleteTable",
"dynamodb:DescribeLimits",
"dynamodb:DescribeReservedCapacity",
"dynamodb:DescribeReservedCapacityOfferings",
"dynamodb:DescribeStream",
"dynamodb:DescribeTable",
"dynamodb:GetItem",
"dynamodb:GetRecords",
"dynamodb:GetShardIterator",
"dynamodb:ListStreams",
"dynamodb:ListTables",
"dynamodb:PutItem",
"dynamodb:Query",
"dynamodb:Scan",
"dynamodb:UpdateItem",
"dynamodb:UpdateTable"
],
"Resource": "arn:aws:dynamodb:us-west-2:051620159240:table/a28-*"
},
{
"Action": [
"sns:*Permission",
"sns:Create*",
"sns:Delete*",
"sns:Publish",
"sns:ReceiveMessage",
"sns:Set*"
],
"Resource": [
"arn:aws:sns:us-west-2:051620159240:a28-*"
],
"Effect": "Allow"
}
]
},
"PolicyName": "StreamConsumerOffsetRWAccessPolicy",
"Roles": [
{
"Ref": "StreamingAccessRole"
}
]
}
}
}
}