The open blogging platform. Say no to algorithms and paywalls.

Cross Account Amazon S3 Bucket Access Setup Using Terraform

How to set up cross account Amazon S3 bucket access using Terraform.

Sometimes you need to access objects of S3 bucket present in other AWS account. So for that you need to do cross account setup.

Let’s say you want to access objects of S3 bucket present in AWS account A from AWS account B.

Cross account Amazon S3 setup:

For that we need to follow below steps:

  1. Create S3 bucket in account A:
resource "aws_s3_bucket" "account-a-s3-bucket" {  
  bucket = "account-a-s3-bucket"  
  acl    = "private"  
  
  tags = {  
    # provide tags if you want  
  }  
}  
  
resource "aws_s3_bucket_object" "users-object" {  
  bucket = aws_s3_bucket.account-a-s3-bucket.id  
  key    = "User/"  
  acl    = "private"  
}  
  
resource "aws_s3_bucket_object" "user-usera-edu-data" {  
  bucket = aws_s3_bucket.account-a-s3-bucket.id  
  key    = "User/user-a/edu-data/"  
  acl    = "private"  
}  
  
resource "aws_s3_bucket_object" "user-usera-other-data" {  
  bucket = aws_s3_bucket.account-a-s3-bucket.id  
  key    = "User/user-a/other-data/"  
  acl    = "private"  
}  
  
resource "aws_s3_bucket_object" "user-userb" {  
  bucket = aws_s3_bucket.account-a-s3-bucket.id  
  key    = "User/user-b/"  
  acl    = "private"  
}  
  
resource "aws_s3_bucket_object" "user-userc" {  
  bucket = aws_s3_bucket.account-a-s3-bucket.id  
  key    = "User/user-c/"  
  acl    = "private"  
}

This will create objects as below:

  1. Now, create IAM policy in AWS account A, which will be used to access S3 bucket objects:

2.1 Do below if you want to give access of complete S3 bucket:

resource "aws_iam_policy" "cross-account-s3-bucket-rw-access-policy" {  
  name   = "cross-account-s3-bucket-rw-access-policy"  
  policy = data.aws_iam_policy_document.cross-account-s3-bucket-rw-access-policy-document.json  
}  
  
data "aws_iam_policy_document" "cross-account-s3-bucket-rw-access-policy-document" {  
   statement {  
    sid    = "AllowListGetPutAndDeleteActions"  
    effect = "Allow"  
    actions = [  
      "s3:List*",  
      "s3:Get*",  
      "s3:PutObject",  
      "s3:DeleteObject"  
    ]  
    resources = ["arn:aws:s3:::account-a-s3-bucket/*"]  
  }  
  
}

2.2 Do below if you want to give access of specific objects of S3 bucket:

resource "aws_iam_policy" "cross-account-s3-bucket-rw-access-policy" {  
  name   = "cross-account-s3-bucket-rw-access-policy"  
  policy = data.aws_iam_policy_document.cross-account-s3-bucket-rw-access-policy-document.json  
}  
  
data "aws_iam_policy_document" "cross-account-s3-bucket-rw-access-policy-document" {  
  #give access to list all objects at root level of bucket and User object level  
  statement {  
    sid       = "AllowRootAndUserListingOfAccountABucket"  
    actions   = ["s3:ListBucket"]  
    effect    = "Allow"  
    resources = ["arn:aws:s3:::account-a-s3-bucket"]  
    condition {  
      test     = "StringEquals"  
      values   = ["", "User/"]  
      variable = "s3:prefix"  
    }  
  }  
  
  # give access to list all objects in objects user-a and user-b  
  statement {  
    sid       = "AllowListingOfOtherFoldersInUserFolder"  
    actions   = ["s3:ListBucket"]  
    effect    = "Allow"  
    resources = ["arn:aws:s3:::account-a-s3-bucket"]  
    condition {  
      test     = "StringLike"  
      values   = ["User/user-a/*", "User/user-b/*"]  
      variable = "s3:prefix"  
    }  
  }  
    
  # give access to get, put and delete objects of user-a's and user-b's all subfolders/objects  
  statement {  
    sid    = "AllowGetPutAndDeleteActions"  
    effect = "Allow"  
    actions = [  
      "s3:PutObject",  
      "s3:GetObject",  
      "s3:DeleteObject"  
    ]  
    resources = ["arn:aws:s3:::account-a-s3-bucket/User/user-a/edu-data/*", "arn:aws:s3:::account-a-s3-bucket/User/user-b/*"]  
  }  
  
}
  1. Now, create IAM role in AWS account A and attach above(point 2) created policy to it:
resource "aws_iam_role" "cross-account-s3-bucket-access-role" {  
  name               = "cross-account-s3-bucket-rw-access-role"  
  assume_role_policy = data.aws_iam_policy_document.cross-role-s3-bucket-rw-access-policy-document.json  
}  
  
data "aws_iam_policy_document" "cross-role-s3-bucket-rw-access-policy-document" {  
  statement {  
    actions = ["sts:AssumeRole"]  
    principals {  
      type        = "AWS"  
      # this will allow account B's IAM role to assume cross-account-s3-bucket-rw-access-role  
      identifiers = ["arn:aws:iam::<aws_account_b_id>:role/<account_b_iam_role_name>"]  
    }  
  
    # uncomment below condition block if you want to use ExternalId validation while role assumption  
    # condition {  
    #   test     = "StringEquals"  
    #   values   = ["some-external-id"]  
    #  variable = "sts:ExternalId"  
    # }  
      
    effect = "Allow"  
  }  
}  
  
resource "aws_iam_policy_attachment" "cross-account-s3-bucket-rw-access-policy-attachment" {  
  name = "CrossAccountS3rwAccessPolicyAttachment"  
  roles = [  
    aws_iam_role.cross-account-s3-bucket-access-role.name  
  ]  
  policy_arn = aws_iam_policy.cross-account-s3-bucket-rw-access-policy.arn  
}
  1. Now, create IAM policy in AWS account B to assume AWS account A’s IAM role:
resource "aws_iam_policy" "cross-account-assume-role-policy" {  
  name   = "cross-account-assume-role-policy"  
  policy = data.aws_iam_policy_document.cross-account-assume-role-policy-document.json  
}  
  
data "aws_iam_policy_document" "cross-account-assume-role-policy-document" {  
   statement {  
    sid    = "AllowToAssumeAccountAIAMRole"  
    effect = "Allow"  
    actions = [  
      "sts:AssumeRole"  
    ]  
    resources = ["arn:aws:iam::<aws_account_a_id>:role/cross-account-s3-bucket-rw-access-role"]  
  }  
  
}
  1. Now, create IAM role in account B and attach above(point 4) created policy to it:
resource "aws_iam_role" "cross-account-s3-access-role" {  
  name               = "cross-account-s3-access-role"  
  assume_role_policy = data.aws_iam_policy.cross-account-assume-role-policy.json  
}

Hurray, you are done with setup :)

Now, after assuming IAM role cross-account-s3-access-role, you can assume account A’s IAM role cross-account-s3-bucket-rw-access-role using AWS cli and access objects of bucket account-a-s3-bucket:

aws sts assume-role --role-arn arn:aws:iam::<aws_account_a_id>:role/cross-account-s3-bucket-rw-access-role --role-session-name cross-account-s3-access

Thank you for reading, please follow if you like the article.

Subscribe to stay tuned for upcoming articles.




Continue Learning