Repository: ministryofjustice/analytical-platform
Pull request #7135: DE Sandbox - GiHub Actions Role
Author: login: zerj9
Created: 2025-03-07T11:51:36Z | Merged: 2025-03-24T15:59:39Z

# Pull Request Objective

Create roles for GitHub Actions runners. These will be used for integrations tests in the create-a-derived-table repo that target the analytical-platform-data-engineering-sandbox-a account. New runners will need to be created.

<!-- Please describe the purpose of this pull request.
Detail the problem it addresses or the functionality it adds.
Highlight how this contributes to the project goals,
improves performance, or solves a specific issue. -->

## Checklist

> [!NOTE]
> Each items should be checked. Skipping below checks could delay your PR review!

- [x] I have reviewed the [style guide](https://docs.analytical-platform.service.justice.gov.uk/documentation/platform/infrastructure/terraform.html#terraform)
and ensured that my code complies with it
- [x] All checks have passed (or override label applied, if I've
used the `override-static-analysis` label, I've explained why)
- [x] I have self-reviewed my code
- [x] I have reviewed the checks and can attest they're as expected

### Additional Comments
The runners have not been created yet



Diff:
diff --git a/.github/dependabot.yml b/.github/dependabot.yml
index 49b81a5dac..0cf0aa50a6 100644
--- a/.github/dependabot.yml
+++ b/.github/dependabot.yml
@@ -47,6 +47,7 @@ updates:
       - "terraform/aws/analytical-platform-data-engineering-production/10ds"
       - "terraform/aws/analytical-platform-data-engineering-production/ppud-dev"
       - "terraform/aws/analytical-platform-data-engineering-sandbox-a/airflow-create-a-pipeline"
+      - "terraform/aws/analytical-platform-data-engineering-sandbox-a/github-actions-roles"
       - "terraform/aws/analytical-platform-data-production/airflow"
       - "terraform/aws/analytical-platform-data-production/airflow-service"
       - "terraform/aws/analytical-platform-data-production/artifact-repos"
diff --git a/terraform/aws/analytical-platform-data-engineering-sandbox-a/github-actions-roles/.terraform.lock.hcl b/terraform/aws/analytical-platform-data-engineering-sandbox-a/github-actions-roles/.terraform.lock.hcl
new file mode 100644
index 0000000000..b596d33039
--- /dev/null
+++ b/terraform/aws/analytical-platform-data-engineering-sandbox-a/github-actions-roles/.terraform.lock.hcl
@@ -0,0 +1,25 @@
+# This file is maintained automatically by "terraform init".
+# Manual edits may be lost in future updates.
+
+provider "registry.terraform.io/hashicorp/aws" {
+  version     = "5.92.0"
+  constraints = ">= 4.0.0, 5.92.0"
+  hashes = [
+    "h1:ZnpTxMfg5PThZc5WZCsZELinsR0gPhdTpNmXjVcf7aE=",
+    "zh:1d3a0b40831360e8e988aee74a9ff3d69d95cb541c2eae5cb843c64303a091ba",
+    "zh:3d29cbced6c708be2041a708d25c7c0fc22d09e4d0b174360ed113bfae786137",
+    "zh:4341a203cf5820a0ca18bb514ae10a6c113bc6a728fb432acbf817d232e8eff4",
+    "zh:4a49e2d91e4d92b6b93ccbcbdcfa2d67935ce62e33b939656766bb81b3fd9a2c",
+    "zh:54c7189358b37fd895dedbabf84e509c1980a8c404a1ee5b29b06e40497b8655",
+    "zh:5d8bb1ff089c37cb65c83b4647f1981fded993e87d8132915d92d79f29e2fcd8",
+    "zh:618f2eb87cd65b245aefba03991ad714a51ff3b841016ef68e2da2b85d0b2325",
+    "zh:7bce07bc542d0588ca42bac5098dd4f8af715417cd30166b4fb97cedd44ab109",
+    "zh:81419eab2d8810beb114b1ff5cbb592d21edc21b809dc12bb066e4b88fdd184a",
+    "zh:9b12af85486a96aedd8d7984b0ff811a4b42e3d88dad1a3fb4c0b580d04fa425",
+    "zh:9dea39d4748eeeebe2e76ca59bca4ccd161c2687050878c47289a98407a23372",
+    "zh:d692fc33b67ac89e916c8f9233d39eacab8c438fe10172990ee9d94fba5ca372",
+    "zh:d9075c7da48947c029ba47d5985e1e8e3bf92367bfee8ca1ff0e747765e779a1",
+    "zh:e81c62db317f3b640b2e04eba0ada8aa606bcbae0152c09f6242e86b86ef5889",
+    "zh:f68562e073722c378d2f3529eb80ad463f12c44aa5523d558ae3b69f4de5ca1f",
+  ]
+}
diff --git a/terraform/aws/analytical-platform-data-engineering-sandbox-a/github-actions-roles/data.tf b/terraform/aws/analytical-platform-data-engineering-sandbox-a/github-actions-roles/data.tf
new file mode 100644
index 0000000000..60d4c0ea03
--- /dev/null
+++ b/terraform/aws/analytical-platform-data-engineering-sandbox-a/github-actions-roles/data.tf
@@ -0,0 +1,15 @@
+data "aws_caller_identity" "session" {
+  provider = aws.session
+}
+
+data "aws_iam_session_context" "session" {
+  provider = aws.session
+
+  arn = data.aws_caller_identity.session.arn
+}
+
+data "aws_secretsmanager_secret_version" "analytical_platform_compute_cluster_data" {
+  provider = aws.analytical-platform-management-production
+
+  secret_id = "analytical-platform-compute/cluster-data"
+}
diff --git a/terraform/aws/analytical-platform-data-engineering-sandbox-a/github-actions-roles/mojas-create-a-derived-table.tf b/terraform/aws/analytical-platform-data-engineering-sandbox-a/github-actions-roles/mojas-create-a-derived-table.tf
new file mode 100644
index 0000000000..19dde6390a
--- /dev/null
+++ b/terraform/aws/analytical-platform-data-engineering-sandbox-a/github-actions-roles/mojas-create-a-derived-table.tf
@@ -0,0 +1,111 @@
+data "aws_iam_policy_document" "create_a_derived_table" {
+  statement {
+    sid    = "BucketAccess"
+    effect = "Allow"
+    actions = [
+      "s3:List*",
+      "s3:GetObject*",
+      "s3:GetBucket*",
+      "s3:DeleteObject*",
+      "s3:PutObject*"
+    ]
+    resources = [
+      "arn:aws:s3:::dbt-tables-sandbox/*",
+      "arn:aws:s3:::dbt-tables-sandbox",
+      "arn:aws:s3:::dbt-query-dump-sandbox/*",
+      "arn:aws:s3:::dbt-query-dump-sandbox",
+    ]
+  }
+  statement {
+    sid    = "DataAccess"
+    effect = "Allow"
+    actions = [
+      "s3:List*",
+      "s3:GetObject*",
+      "s3:GetBucket*"
+    ]
+    resources = [
+      "arn:aws:s3:::*",
+      "arn:aws:s3:::*/*"
+    ]
+  }
+  statement {
+    sid    = "AthenaAccess"
+    effect = "Allow"
+    actions = [
+      "athena:List*",
+      "athena:Get*",
+      "athena:StartQueryExecution",
+      "athena:StopQueryExecution"
+    ]
+    resources = [
+      "arn:aws:athena:*:${var.account_ids["analytical-platform-data-engineering-sandbox-a"]}:datacatalog/*",
+      "arn:aws:athena:*:${var.account_ids["analytical-platform-data-engineering-sandbox-a"]}:workgroup/*"
+    ]
+  }
+  statement {
+    sid    = "GlueAccess"
+    effect = "Allow"
+    actions = [
+      "glue:Get*",
+      "glue:DeleteTable",
+      "glue:DeleteTableVersion",
+      "glue:DeleteSchema",
+      "glue:DeletePartition",
+      "glue:DeleteDatabase",
+      "glue:UpdateTable",
+      "glue:UpdateSchema",
+      "glue:UpdatePartition",
+      "glue:UpdateDatabase",
+      "glue:CreateTable",
+      "glue:CreateSchema",
+      "glue:CreatePartition",
+      "glue:CreatePartitionIndex",
+      "glue:BatchCreatePartition",
+      "glue:CreateDatabase"
+    ]
+    resources = [
+      "arn:aws:glue:*:${var.account_ids["analytical-platform-data-engineering-sandbox-a"]}:schema/*",
+      "arn:aws:glue:*:${var.account_ids["analytical-platform-data-engineering-sandbox-a"]}:database/*",
+      "arn:aws:glue:*:${var.account_ids["analytical-platform-data-engineering-sandbox-a"]}:table/*/*",
+      "arn:aws:glue:*:${var.account_ids["analytical-platform-data-engineering-sandbox-a"]}:catalog"
+    ]
+  }
+}
+
+module "create_a_derived_table_iam_policy" {
+  #checkov:skip=CKV_TF_1:Module registry does not support commit hashes for versions
+
+  source  = "terraform-aws-modules/iam/aws//modules/iam-policy"
+  version = "5.54.0"
+
+  name_prefix = "create-a-derived-table"
+  policy      = data.aws_iam_policy_document.create_a_derived_table.json
+}
+
+module "create_a_derived_table_iam_role" {
+  #checkov:skip=CKV_TF_1:Module registry does not support commit hashes for versions
+
+  source  = "terraform-aws-modules/iam/aws//modules/iam-role-for-service-accounts-eks"
+  version = "5.54.0"
+
+  role_name            = "create-a-derived-table"
+  max_session_duration = 10800
+
+  role_policy_arns = {
+    policy = module.create_a_derived_table_iam_policy.arn
+  }
+
+  oidc_providers = {
+    analytical-platform-compute-production = {
+      provider_arn = format(
+        "arn:aws:iam::${var.account_ids["analytical-platform-management-production"]}:oidc-provider/%s",
+        trimprefix(jsondecode(data.aws_secretsmanager_secret_version.analytical_platform_compute_cluster_data.secret_string)["analytical-platform-compute-production-oidc-endpoint"], "https://")
+      )
+      namespace_service_accounts = [
+        "actions-runners:actions-runner-mojas-cadt-sandbox-a",
+        "actions-runners:actions-runner-mojas-cadt-sandbox-a-non-spot"
+      ]
+    }
+  }
+}
diff --git a/terraform/aws/analytical-platform-data-engineering-sandbox-a/github-actions-roles/terraform.tf b/terraform/aws/analytical-platform-data-engineering-sandbox-a/github-actions-roles/terraform.tf
new file mode 100644
index 0000000000..f924f0ea1e
--- /dev/null
+++ b/terraform/aws/analytical-platform-data-engineering-sandbox-a/github-actions-roles/terraform.tf
@@ -0,0 +1,42 @@
+terraform {
+  backend "s3" {
+    acl            = "private"
+    bucket         = "global-tf-state-aqsvzyd5u9"
+    encrypt        = true
+    key            = "aws/analytical-platform-data-engineering-sandbox-a/github-actions-roles/terraform.tfstate"
+    region         = "eu-west-2"
+    dynamodb_table = "global-tf-state-aqsvzyd5u9-locks"
+  }
+  required_providers {
+    aws = {
+      source  = "hashicorp/aws"
+      version = "5.92.0"
+    }
+  }
+  required_version = "~> 1.5"
+}
+
+provider "aws" {
+  alias = "session"
+}
+
+provider "aws" {
+  region = "eu-west-2"
+  assume_role {
+    role_arn = "arn:aws:iam::${var.account_ids["analytical-platform-data-engineering-sandbox-a"]}:role/GlobalGitHubActionAdmin"
+  }
+  default_tags {
+    tags = var.tags
+  }
+}
+
+provider "aws" {
+  alias  = "analytical-platform-management-production"
+  region = "eu-west-2"
+  assume_role {
+    role_arn = can(regex("AdministratorAccess", data.aws_iam_session_context.session.issuer_arn)) ? null : "arn:aws:iam::${var.account_ids["analytical-platform-management-production"]}:role/GlobalGitHubActionAdmin"
+  }
+  default_tags {
+    tags = var.tags
+  }
+}
diff --git a/terraform/aws/analytical-platform-data-engineering-sandbox-a/github-actions-roles/terraform.tfvars b/terraform/aws/analytical-platform-data-engineering-sandbox-a/github-actions-roles/terraform.tfvars
new file mode 100644
index 0000000000..e131d6dce5
--- /dev/null
+++ b/terraform/aws/analytical-platform-data-engineering-sandbox-a/github-actions-roles/terraform.tfvars
@@ -0,0 +1,21 @@
+##################################################
+# General
+##################################################
+
+account_ids = {
+  analytical-platform-data-engineering-sandbox-a = "684969100054"
+  analytical-platform-management-production      = "042130406152"
+  analytical-platform-compute-production         = "992382429243"
+
+}
+
+tags = {
+  business-unit          = "Central Digital"
+  application            = "Analytical Platform"
+  component              = "GitHub Actions Roles"
+  environment            = "sandbox"
+  is-production          = "false"
+  owner                  = "analytical-platform:analytical-platform@digital.justice.gov.uk"
+  infrastructure-support = "analytical-platform:analytical-platform@digital.justice.gov.uk"
+  source-code            = "github.com/ministryofjustice/analytical-platform/tree/main/terraform/aws/analytical-platform-data-engineering-sandbox-a/github-actions-roles"
+}
diff --git a/terraform/aws/analytical-platform-data-engineering-sandbox-a/github-actions-roles/variables.tf b/terraform/aws/analytical-platform-data-engineering-sandbox-a/github-actions-roles/variables.tf
new file mode 100644
index 0000000000..3a33530903
--- /dev/null
+++ b/terraform/aws/analytical-platform-data-engineering-sandbox-a/github-actions-roles/variables.tf
@@ -0,0 +1,13 @@
+##################################################
+# General
+##################################################
+
+variable "account_ids" {
+  type        = map(string)
+  description = "Map of account names to account IDs"
+}
+
+variable "tags" {
+  type        = map(string)
+  description = "Map of tags to apply to resources"
+}


Reviews:
user: login: jhpyke
body: Hi,

I've made some suggestions on general terraform, but this kind of functionality should ideally be going in as a feature request via [issues on Analytical Platform](https://github.com/ministryofjustice/analytical-platform/issues). If you can raise a feature request, given that this is blocking work we can ensure it's taken to one of the slots we're running next week for them, and taken on properly by the AP team accordingly.

Thanks,
Jake
state: DISMISSED
author_association: CONTRIBUTOR
submitted_at: 2025-03-14T10:24:53Z
user: login: jhpyke
body: Big day for 🏃 🏃 🏃 
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-03-24T15:59:22Z

Review comments:
diff_hunk: @@ -0,0 +1,21 @@
+locals {
+  eks_oidc_id  = "801920EDEF91E3CAB03E04C03A2DE2BB" # AP Compute Production
+  eks_oidc_url = "https://oidc.eks.eu-west-2.amazonaws.com/id/${local.eks_oidc_id}"
+  account_ids = {
path: terraform/aws/analytical-platform-data-engineering-sandbox-a/github-actions-roles/locals.tf
user: login: jhpyke
body: Can I ask you to move account IDs and Tags into a `variables.tf` + `terraform.tfvars` setup so that we can easily vary these if we have a number of different users on this in future - This will help standardise this with the rest of our repo
created_at: 2025-03-14T10:19:01Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,112 @@
+# OIDC Provider for the EKS cluster in AP account
+resource "aws_iam_openid_connect_provider" "ap_compute_production" {
+  client_id_list = ["sts.amazonaws.com"]
+  url            = local.eks_oidc_url
+}
+
+# Permissions for the GitHub Actions runner
+data "aws_iam_policy_document" "create_a_derived_table" {
+  statement {
+    sid    = "BucketAccess"
+    effect = "Allow"
+    actions = [
+      "s3:List*",
+      "s3:GetObject*",
+      "s3:GetBucket*",
+      "s3:DeleteObject*",
+      "s3:PutObject*"
+    ]
+    resources = [
+      "arn:aws:s3:::dbt-tables-sandbox/*",
+      "arn:aws:s3:::dbt-tables-sandbox",
+      "arn:aws:s3:::dbt-query-dump-sandbox/*",
+      "arn:aws:s3:::dbt-query-dump-sandbox",
+    ]
+  }
+  statement {
+    sid    = "DataAccess"
+    effect = "Allow"
+    actions = [
+      "s3:List*",
+      "s3:GetObject*",
+      "s3:GetBucket*"
+    ]
+    resources = [
+      "arn:aws:s3:::*",
+      "arn:aws:s3:::*/*"
+    ]
+  }
+  statement {
+    sid    = "AthenaAccess"
+    effect = "Allow"
+    actions = [
+      "athena:List*",
+      "athena:Get*",
+      "athena:StartQueryExecution",
+      "athena:StopQueryExecution"
+    ]
+    resources = [
+      "arn:aws:athena:*:${local.account_ids["analytical-platform-data-engineering-sandbox-a"]}:datacatalog/*",
+      "arn:aws:athena:*:${local.account_ids["analytical-platform-data-engineering-sandbox-a"]}:workgroup/*"
+    ]
+  }
+  statement {
+    sid    = "GlueAccess"
+    effect = "Allow"
+    actions = [
+      "glue:Get*",
+      "glue:DeleteTable",
+      "glue:DeleteTableVersion",
+      "glue:DeleteSchema",
+      "glue:DeletePartition",
+      "glue:DeleteDatabase",
+      "glue:UpdateTable",
+      "glue:UpdateSchema",
+      "glue:UpdatePartition",
+      "glue:UpdateDatabase",
+      "glue:CreateTable",
+      "glue:CreateSchema",
+      "glue:CreatePartition",
+      "glue:CreatePartitionIndex",
+      "glue:BatchCreatePartition",
+      "glue:CreateDatabase"
+    ]
+    resources = [
+      "arn:aws:glue:*:${local.account_ids["analytical-platform-data-engineering-sandbox-a"]}:schema/*",
+      "arn:aws:glue:*:${local.account_ids["analytical-platform-data-engineering-sandbox-a"]}:database/*",
+      "arn:aws:glue:*:${local.account_ids["analytical-platform-data-engineering-sandbox-a"]}:table/*/*",
+      "arn:aws:glue:*:${local.account_ids["analytical-platform-data-engineering-sandbox-a"]}:catalog"
+    ]
+  }
+}
+
+module "create_a_derived_table_iam_policy" {
+  # Commit hash for v5.52.2 - (prevents supply chain attacks)
+  source = "github.com/terraform-aws-modules/terraform-aws-iam//modules/iam-policy?ref=e803e25"
+
+  name_prefix = "create-a-derived-table"
+  policy      = data.aws_iam_policy_document.create_a_derived_table.json
+}
+
+# Role for the GitHub Actions runner to assume using the OIDC provider
+module "create_a_derived_table_iam_role" {
+  # Commit hash for v5.52.2
+  source = "github.com/terraform-aws-modules/terraform-aws-iam//modules/iam-role-for-service-accounts-eks?ref=e803e25"
path: terraform/aws/analytical-platform-data-engineering-sandbox-a/github-actions-roles/mojas-create-a-derived-table.tf
user: login: jhpyke
body: ```suggestion
  source = "terraform-aws-modules/iam/aws//modules/iam-role-for-service-accounts-eks"
  version = "5.52.2"
```
created_at: 2025-03-14T10:22:51Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,112 @@
+# OIDC Provider for the EKS cluster in AP account
+resource "aws_iam_openid_connect_provider" "ap_compute_production" {
+  client_id_list = ["sts.amazonaws.com"]
+  url            = local.eks_oidc_url
+}
+
+# Permissions for the GitHub Actions runner
+data "aws_iam_policy_document" "create_a_derived_table" {
+  statement {
+    sid    = "BucketAccess"
+    effect = "Allow"
+    actions = [
+      "s3:List*",
+      "s3:GetObject*",
+      "s3:GetBucket*",
+      "s3:DeleteObject*",
+      "s3:PutObject*"
+    ]
+    resources = [
+      "arn:aws:s3:::dbt-tables-sandbox/*",
+      "arn:aws:s3:::dbt-tables-sandbox",
+      "arn:aws:s3:::dbt-query-dump-sandbox/*",
+      "arn:aws:s3:::dbt-query-dump-sandbox",
+    ]
+  }
+  statement {
+    sid    = "DataAccess"
+    effect = "Allow"
+    actions = [
+      "s3:List*",
+      "s3:GetObject*",
+      "s3:GetBucket*"
+    ]
+    resources = [
+      "arn:aws:s3:::*",
+      "arn:aws:s3:::*/*"
+    ]
+  }
+  statement {
+    sid    = "AthenaAccess"
+    effect = "Allow"
+    actions = [
+      "athena:List*",
+      "athena:Get*",
+      "athena:StartQueryExecution",
+      "athena:StopQueryExecution"
+    ]
+    resources = [
+      "arn:aws:athena:*:${local.account_ids["analytical-platform-data-engineering-sandbox-a"]}:datacatalog/*",
+      "arn:aws:athena:*:${local.account_ids["analytical-platform-data-engineering-sandbox-a"]}:workgroup/*"
+    ]
+  }
+  statement {
+    sid    = "GlueAccess"
+    effect = "Allow"
+    actions = [
+      "glue:Get*",
+      "glue:DeleteTable",
+      "glue:DeleteTableVersion",
+      "glue:DeleteSchema",
+      "glue:DeletePartition",
+      "glue:DeleteDatabase",
+      "glue:UpdateTable",
+      "glue:UpdateSchema",
+      "glue:UpdatePartition",
+      "glue:UpdateDatabase",
+      "glue:CreateTable",
+      "glue:CreateSchema",
+      "glue:CreatePartition",
+      "glue:CreatePartitionIndex",
+      "glue:BatchCreatePartition",
+      "glue:CreateDatabase"
+    ]
+    resources = [
+      "arn:aws:glue:*:${local.account_ids["analytical-platform-data-engineering-sandbox-a"]}:schema/*",
+      "arn:aws:glue:*:${local.account_ids["analytical-platform-data-engineering-sandbox-a"]}:database/*",
+      "arn:aws:glue:*:${local.account_ids["analytical-platform-data-engineering-sandbox-a"]}:table/*/*",
+      "arn:aws:glue:*:${local.account_ids["analytical-platform-data-engineering-sandbox-a"]}:catalog"
+    ]
+  }
+}
+
+module "create_a_derived_table_iam_policy" {
+  # Commit hash for v5.52.2 - (prevents supply chain attacks)
+  source = "github.com/terraform-aws-modules/terraform-aws-iam//modules/iam-policy?ref=e803e25"
+
+  name_prefix = "create-a-derived-table"
+  policy      = data.aws_iam_policy_document.create_a_derived_table.json
+}
+
+# Role for the GitHub Actions runner to assume using the OIDC provider
+module "create_a_derived_table_iam_role" {
+  # Commit hash for v5.52.2
+  source = "github.com/terraform-aws-modules/terraform-aws-iam//modules/iam-role-for-service-accounts-eks?ref=e803e25"
path: terraform/aws/analytical-platform-data-engineering-sandbox-a/github-actions-roles/mojas-create-a-derived-table.tf
user: login: jhpyke
body: Brings this in line with how we handle sources across the repo
created_at: 2025-03-14T10:23:05Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,112 @@
+# OIDC Provider for the EKS cluster in AP account
+resource "aws_iam_openid_connect_provider" "ap_compute_production" {
+  client_id_list = ["sts.amazonaws.com"]
+  url            = local.eks_oidc_url
+}
+
+# Permissions for the GitHub Actions runner
+data "aws_iam_policy_document" "create_a_derived_table" {
+  statement {
+    sid    = "BucketAccess"
+    effect = "Allow"
+    actions = [
+      "s3:List*",
+      "s3:GetObject*",
+      "s3:GetBucket*",
+      "s3:DeleteObject*",
+      "s3:PutObject*"
+    ]
+    resources = [
+      "arn:aws:s3:::dbt-tables-sandbox/*",
+      "arn:aws:s3:::dbt-tables-sandbox",
+      "arn:aws:s3:::dbt-query-dump-sandbox/*",
+      "arn:aws:s3:::dbt-query-dump-sandbox",
+    ]
+  }
+  statement {
+    sid    = "DataAccess"
+    effect = "Allow"
+    actions = [
+      "s3:List*",
+      "s3:GetObject*",
+      "s3:GetBucket*"
+    ]
+    resources = [
+      "arn:aws:s3:::*",
+      "arn:aws:s3:::*/*"
+    ]
+  }
+  statement {
+    sid    = "AthenaAccess"
+    effect = "Allow"
+    actions = [
+      "athena:List*",
+      "athena:Get*",
+      "athena:StartQueryExecution",
+      "athena:StopQueryExecution"
+    ]
+    resources = [
+      "arn:aws:athena:*:${local.account_ids["analytical-platform-data-engineering-sandbox-a"]}:datacatalog/*",
+      "arn:aws:athena:*:${local.account_ids["analytical-platform-data-engineering-sandbox-a"]}:workgroup/*"
+    ]
+  }
+  statement {
+    sid    = "GlueAccess"
+    effect = "Allow"
+    actions = [
+      "glue:Get*",
+      "glue:DeleteTable",
+      "glue:DeleteTableVersion",
+      "glue:DeleteSchema",
+      "glue:DeletePartition",
+      "glue:DeleteDatabase",
+      "glue:UpdateTable",
+      "glue:UpdateSchema",
+      "glue:UpdatePartition",
+      "glue:UpdateDatabase",
+      "glue:CreateTable",
+      "glue:CreateSchema",
+      "glue:CreatePartition",
+      "glue:CreatePartitionIndex",
+      "glue:BatchCreatePartition",
+      "glue:CreateDatabase"
+    ]
+    resources = [
+      "arn:aws:glue:*:${local.account_ids["analytical-platform-data-engineering-sandbox-a"]}:schema/*",
+      "arn:aws:glue:*:${local.account_ids["analytical-platform-data-engineering-sandbox-a"]}:database/*",
+      "arn:aws:glue:*:${local.account_ids["analytical-platform-data-engineering-sandbox-a"]}:table/*/*",
+      "arn:aws:glue:*:${local.account_ids["analytical-platform-data-engineering-sandbox-a"]}:catalog"
+    ]
+  }
+}
+
+module "create_a_derived_table_iam_policy" {
+  # Commit hash for v5.52.2 - (prevents supply chain attacks)
+  source = "github.com/terraform-aws-modules/terraform-aws-iam//modules/iam-policy?ref=e803e25"
path: terraform/aws/analytical-platform-data-engineering-sandbox-a/github-actions-roles/mojas-create-a-derived-table.tf
user: login: jhpyke
body: ```suggestion
  source = "terraform-aws-modules/iam/aws//modules/iam-policy"
  version = "5.52.2"
```
created_at: 2025-03-14T10:23:56Z
author_association: CONTRIBUTOR

PR comments:
user: login: github-actions[bot]
created_at: 2025-03-07T11:52:30Z
body: ### Terraform Component 🧱: `aws-analytical-platform-data-engineering-sandbox-a-github-actions-roles`
#### Checkov 🛂: `success`
#### Trivy 🛂: `success`
#### Static Analysis Override Label 🏷️: `false`

*Pusher: @jacobwoffenden, Action: `pull_request`, Working Directory: `terraform/aws/analytical-platform-data-engineering-sandbox-a/github-actions-roles`, Workflow: `Terraform`, Marker: `aws-analytical-platform-data-engineering-sandbox-a-github-actions-roles_static_analysis`*
author_association: CONTRIBUTOR
user: login: github-actions[bot]
created_at: 2025-03-07T11:52:40Z
body: ### Terraform Component 🧱: `aws-analytical-platform-data-engineering-sandbox-a-github-actions-roles`
#### Terraform Initialization ⚙️: `success`
#### Terraform Validation 🤖: `success`
#### Terraform Plan 🛠️: `success`

*Pusher: @jacobwoffenden, Action: `pull_request`, Working Directory: `terraform/aws/analytical-platform-data-engineering-sandbox-a/github-actions-roles`, Workflow: `Terraform`, Marker: `aws-analytical-platform-data-engineering-sandbox-a-github-actions-roles_plan`*
author_association: CONTRIBUTOR