Skip to main content

Use IAM Roles for service accounts to access resources in a different AWS account

This article explains how to utilise IAM roles for Kubernetes Service Accounts (on the EKS cluster), to enable connection and authorization:

  • from applications (running in the AWS Cloud platform account)
  • to AWS resources within a different AWS account.

For more information on AWS “IAM roles for Service Accounts” (IRSA) please see IAM roles for Kubernetes Service Accounts:

The Cloud Platform utilises an cloud-platform-terraform-irsa module. Please make sure you are using the latest release in the following config:

Required Configuration:

  1. Create the IAM role for service accounts config

    Create a file (cross-iam-role-sa.tf) inside your environment folder in the cloud-platform-environments repo, update the template below with the correct values and raise a PR.

    Click here to see a template code block
    
        module "irsa" {
          source = "github.com/ministryofjustice/cloud-platform-terraform-irsa?ref=0.0.1"
          namespace        = ""
          role_policy_arns = ["_.arn>"]
        }
        data "aws_iam_policy_document" "_" {
          # "api" policy statements for the namespace
          # allows direct access to "landing" S3 bucket
          statement {
            actions = [
              "s3:PutObject",
              "s3:PutObjectAcl",
            ]
            resources = [
              "/*",
            ]
          }
        }
        resource "aws_iam_policy" "_" {
          name   = "-"
          policy = data.aws_iam_policy_document._.json
        } 
        variable "-tags" {
          type = map(string)
          default = {
            business-unit          = ""
            application            = ""
            is-production          = ""
            environment-name       = ""
            owner                  = ""
            infrastructure-support = ""
          }
        }
        resource "kubernetes_secret" "irsa" {
          metadata {
            name      = "irsa-output"
            namespace = ""
          }
          data = {
            role = module.irsa.aws_iam_role_name
            serviceaccount = module.irsa.service_account_name
          }
        }
    
    
    Here is an example using the template above, with typical values provided
    
          module "irsa" {
          source = "github.com/ministryofjustice/cloud-platform-terraform-irsa?ref=0.0.1"
          namespace        = "my-namespace"
          role_policy_arns = [aws_iam_policy.my_namespace_my_policy.arn]
        }
        data "aws_iam_policy_document" "my_namespace_my_policy" {
          # "api" policy statements for the namespace/policy
          # allows direct access to "landing" S3 bucket
          statement {
            actions = [
              "s3:PutObject",
              "s3:PutObjectAcl",
            ]
            resources = [
              "arn:aws:s3:::my-destination-s3-bucket/*",
            ]
          }
        }
        resource "aws_iam_policy" "my_namespace_my_policy" {
          name   = "my-namespace-my-policy"
          policy = data.aws_iam_policy_document.my_namespace_my_policy.json
        }
        variable "my-namespace-tags" {
          type = map(string)
          default = {
            business-unit          = "Cloud Platform"
            application            = "My Application"
            is-production          = "false"
            environment-name       = "Development"
            owner                  = "cloud-platform"
            infrastructure-support = "platforms@digital.justice.gov.uk"
          }
        }
        resource "kubernetes_secret" "irsa" {
          metadata {
            name      = "irsa-output"
            namespace = "my-namespace"
          }
          data = {
            role = module.irsa.aws_iam_role_name
            serviceaccount = module.irsa.service_account_name
          }
        }
    
    
  • The service account and the service account IAM role will be created with a random string in the format cloud-platform-jhsdflisuhdfih and can be changed by passing the service_account variable. Make sure there is no existing service_account in the same name. Please see the module README for optional inputs.

  • Once the PR is merged, the IAM role and serviceaccount will be stored as a kubernetes_secret called irsa-output in your namespace.

2.Use the Serviceaccount to deploy your app

Decode the secret irsa-output to get the serviceaccount name and add it to your depolyment manifest as shown in example below:

  apiVersion: apps/v1
  kind: Deployment
  metadata:
    name: helloworld-rubyapp
  spec:
    replicas: 1
    selector:
      matchLabels:
        app: helloworld-rubyapp
    template:
      metadata:
        labels:
          app: helloworld-rubyapp
      spec:
        serviceAccountName: <serviceaccount>
        containers:
        - name: rubyapp
          image: ministryofjustice/cloud-platform-helloworld-ruby:1.1
          ports:
          - containerPort: 4567

3.Allow the service account IAM role to permit access in the target AWS account

You also need to update the AWS resource policy of the target AWS account to allow the service account IAM role to perform actions.

Here is an example s3 bucket policy to allow an service account IAM role to perform specific actions:

{
"Version": "2012-10-17",
"Statement": [
  {
    "Sid": "Cross IAM permissions",
    "Effect": "Allow",
    "Principal": {
      "AWS": "arn:aws:iam::11111111:role/my-service-account-role"
    },
    "Action": [
      "s3:PutObject",
      "s3:GetObject",
    ],
    "Resource": "arn:aws:s3:::target-s3-bucket/*"
      }
    ]
  }
This page was last reviewed on 19 July 2021. It needs to be reviewed again on 19 October 2021 .
This page was set to be reviewed before 19 October 2021. This might mean the content is out of date.