AWS: Iam role cross account Lambda/S3 with Terraform
HowTo: AWS IAM cross-account role to write in an S3 bucket in a different Account
Context: the aws Lambda in account lambda_account
must gain access to an S3 bucket in the s3_account
.
How does it work?
- The Lambda has a role in its account;
- The lambda code use assume the role in
s3_account
; - The lambda call the S3 api using the assumed role
1. The roles in lambda_Account
This is the regular execution role for the lambda. This role nee permission to do sts:AssumeRole
on the role in the other account
resource "aws_iam_role" "lambda_inbound_email" {
provider = aws.lambda_account # <-- this role is in the lambda_account
name = "lambda_role"
assume_role_policy = jsonencode({
Version = "2012-10-17",
Statement = [
{
Action = "sts:AssumeRole",
Effect = "Allow",
Principal = {
Service = "lambda.amazonaws.com",
}
}
]
})
inline_policy {
name = "assume-role"
policy = jsonencode({
Version = "2012-10-17",
Statement = [
{
Effect = "Allow",
Action = "sts:AssumeRole",
Resource = "arn:aws:iam::${s3_account.account_id}:role/s3-account-role" # <-- allow sts:AssumeRole on the role in the other account
},
],
})
}
}
resource "aws_iam_role_policy_attachment" "lambda_basic_execution" {
provider = aws.my-ideas
policy_arn = "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"
role = aws_iam_role.lambda_inbound_email.name
}
2. Create the role in the other account (s3_account)
resource "aws_iam_role" "inbound_role" {
provider = aws.s3_account
name = "s3-account-role"
assume_role_policy = jsonencode({
Version = "2012-10-17",
Statement = [
{
Action = "sts:AssumeRole",
Effect = "Allow",
Principal = {
AWS = aws_iam_role.lambda_inbound_email.arn # <-- set the lambda_account role as the principal - allow the lambda_account to assume this role
},
},
],
})
# regular policy for this role
inline_policy {
name = "write-videorequest"
policy = jsonencode({
Version = "2012-10-17",
Statement = [
{
Action = [
"s3:PutObject",
],
Effect = "Allow",
Resource = "${aws_s3_bucket.blabla.arn}/*",
},
]
})
}
}
3. Minor updates to the lambda code
Lambda runs with the role we assigned to it. To call the API in a different acocunt, we need to assume the new role
// Create a new AWS session
sess, err := session.NewSession()
if err != nil {
return fmt.Errorf("failed to create session, %v", err)
}
// Assume the role in the different account
creds := stscreds.NewCredentials(sess, "arn:aws:iam::<s3_account>:role/s3-account-role")
// Create a new S3 service with the assumed role credentials
svc := s3.New(sess, &aws.Config{Credentials: creds})
// Create an upload input parameters
upParams := &s3.PutObjectInput{ Bucket: &bucket, Key: &key, Body: bytes.NewReader(body)}
_, err = svc.PutObject(upParams)