Skip to main content

Sharing AWS resources across namespaces using SSM and IRSA

This article explains how to access a resource in one Kubernetes namespace from another using IAM, IRSA and SSM:

For example, namespace-one needs to read from an S3 bucket in namespace-two

This can be done by hard-coding the resource. This guide explains how to avoid hard-coding the resource by using SSM to share the resource name and ARN.

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

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

Required Configuration:

1.Add the resource name and ARN to AWS SSM in namespace-two

Here is an example of how to add an S3 bucket ARN and name as SSM parameters:


  resource "aws_ssm_parameter" "s3-bucket-name" {
    type        = "String"
    # this will be namespace-two
    name        = "/${var.namespace}/s3-bucket-name"
    # specify the module of an existing resource here
    value       = module.s3-bucket.bucket_name
    description = "Name of Bucket to be accessed from namespace-one"
    tags = {
        business-unit          = var.business_unit
        application            = var.application
        is-production          = var.is_production
        owner                  = var.team_name
        environment-name       = var.environment-name
        infrastructure-support = var.infrastructure_support
        namespace              = var.namespace
    }
  }

resource "aws_ssm_parameter" "s3-bucket-arn" { type = "String" # this will be namespace-two name = "/${var.namespace}/s3-bucket-arn" # specify the module of an existing resource here value = module.s3-bucket.bucket_arn description = "ARN of Bucket to be accessed from namespace-one" tags = { business-unit = var.business_unit application = var.application is-production = var.is_production owner = var.team_name environment-name = var.environment-name infrastructure-support = var.infrastructure_support namespace = var.namespace } }

2.Create the IAM role for service accounts config

Create a file (cross-namespace-role-sa.tf) inside the namespace-one 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=2.0.0"
        eks_cluster_name      = "var.eks_cluster_name"
        namespace             = "<namespace>"
        service_account_name  = "<service_account_name>"
        role_policy_arns = ["<aws_iam_policy.<namespace>_<policy_name>.arn>"]
    }
    data "aws_iam_policy_document" "<namespace>_<policy_name>" {
        # Provide list of permissions and target AWS account resources to allow access to
        statement {
        actions = [
            "s3:PutObject",
            "s3:PutObjectAcl",
        ]
        resources = [
            "<ARN of resource in target AWS account>/*",
        ]
        }
    }
    resource "aws_iam_policy" "<namespace>_<policy_name>" {
        name   = "<namespace>-<policy-name>"
        policy = data.aws_iam_policy_document.<namespace>_<policy_name>.json

        tags = {
        business-unit          = "<Which part of the MoJ is responsible for this service? (e.g HMPPS, Legal Aid Agency)>"
        application            = "<Application name>"
        is-production          = "<true/false>"
        environment-name       = "<dev/test/staging/prod>"
        owner                  = "<team responsible for this application>"
        infrastructure-support = "<Email address for contact/support>"
        }
    }
    resource "kubernetes_secret" "irsa" {
        metadata {
        name      = "irsa-output"
        namespace = "<namespace>"
        }
        data = {
        role = module.irsa.aws_iam_role_name
        serviceaccount = module.irsa.service_account_name.name
        }
    }



Here is an example using the template above, with typical values provided. It also includes the data references to the SSM parameters in namespace-two

    module "irsa" {
        source = "github.com/ministryofjustice/cloud-platform-terraform-irsa?ref=2.0.0"
        eks_cluster_name      = "var.eks_cluster_name"
        namespace             = "<namespace>"
        service_account_name  = "<service_account_name>"
        role_policy_arns = ["<aws_iam_policy.<namespace>_<policy_name>.arn>"]
    }
    data "aws_iam_policy_document" "<namespace>_<policy_name>" {
        # Provide list of permissions and target AWS account resources to allow access to
        statement {
        actions = [
            "s3:GetObject",
            
        ]
        resources = [
            # refer to the ssm parameter containing the arn of the resource you want to access
            "${data.aws_ssm_parameter.namespace-two-s3-bucket-arn.value}/*",
        ]
        }
    }
    resource "aws_iam_policy" "<namespace>_<policy_name>" {
        name   = "<namespace>-<policy-name>"
        policy = data.aws_iam_policy_document.<namespace>_<policy_name>.json

        tags = {
        business-unit          = "<Which part of the MoJ is responsible for this service? (e.g HMPPS, Legal Aid Agency)>"
        application            = "<Application name>"
        is-production          = "<true/false>"
        environment-name       = "<dev/test/staging/prod>"
        owner                  = "<team responsible for this application>"
        infrastructure-support = "<Email address for contact/support>"
        }
    }
    resource "kubernetes_secret" "irsa" {
        metadata {
        name      = "irsa-output"
        namespace = "<namespace>"
        }
        data = {
        role = module.irsa.aws_iam_role_name
        serviceaccount = module.irsa.service_account_name.name
        }
    }

    # this is the ssm parameter used to supply the application with the S3 bucket name in a k8s secret
    data "aws_ssm_parameter" "s3-bucket-name" {
        name = "/namespace-two/s3-bucket-name"
    }

    # this is the ssm parameter which the aws_iam_policy_document refers to
    data "aws_ssm_parameter" "s3-bucket-arn" {
        name = "/namespace-two/s3-bucket-arn"
    }

    # this is for the application to read from the S3 bucket
    resource "kubernetes_secret" "s3-bucket-secret" {
        
        metadata {
            name = "s3-bucket-secret"
            namespace = var.namespace
        }

        data = {
            # reads the S3 bucket name from an SSM parameter
            bucket_name = data.aws_ssm_parameter.s3-bucket-name.value
        }
    }

}

  • 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.

3.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
This page was last reviewed on 5 February 2025. It needs to be reviewed again on 5 August 2025 by the page owner #cloud-platform .
This page was set to be reviewed before 5 August 2025 by the page owner #cloud-platform. This might mean the content is out of date.