Skip to content

Commit bb38dae

Browse files
ELI-545 - service account creation
1 parent e2493b7 commit bb38dae

4 files changed

Lines changed: 216 additions & 0 deletions

File tree

infrastructure/stacks/api-layer/s3_buckets.tf

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,3 +57,12 @@ module "s3_dq_metrics_bucket" {
5757
stack_name = local.stack_name
5858
workspace = terraform.workspace
5959
}
60+
61+
module "s3_athena_dq_query_bucket" {
62+
source = "../../modules/s3"
63+
bucket_name = "athena-stage"
64+
environment = var.environment
65+
project_name = var.project_name
66+
stack_name = local.stack_name
67+
workspace = terraform.workspace
68+
}
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
resource "aws_iam_user" "tableau_service" {
2+
name = "tableau-athena-service-account"
3+
}
4+
5+
resource "time_rotating" "athena_key_rotation" {
6+
rotation_days = 90
7+
}
8+
9+
resource "aws_iam_access_key" "tableau_key" {
10+
user = aws_iam_user.tableau_service.name
11+
12+
lifecycle {
13+
replace_triggered_by = [time_rotating.athena_key_rotation]
14+
}
15+
}
16+
17+
resource "aws_iam_user_policy" "tableau_athena_policy" {
18+
name = "TableauAthenaAccess"
19+
user = aws_iam_user.tableau_service.name
20+
21+
policy = jsonencode({
22+
Version = "2012-10-17"
23+
Statement = [
24+
{
25+
# Athena Query Actions
26+
Effect = "Allow"
27+
Action = [
28+
"athena:GetQueryExecution",
29+
"athena:GetQueryResults",
30+
"athena:StartQueryExecution",
31+
"athena:GetWorkGroup",
32+
"athena:StopQueryExecution",
33+
"athena:GetDataCatalog"
34+
]
35+
Resource = [
36+
"arn:aws:athena:${var.default_aws_region}:${data.aws_caller_identity.current.account_id}:workgroup/primary"
37+
]
38+
},
39+
{
40+
# Metadata Discovery
41+
Effect = "Allow"
42+
Action = [
43+
"glue:GetDatabase",
44+
"glue:GetTable",
45+
"glue:GetTables",
46+
"glue:GetDatabases"
47+
]
48+
Resource = [
49+
"arn:aws:glue:${var.default_aws_region}:${data.aws_caller_identity.current.account_id}:catalog",
50+
"arn:aws:glue:${var.default_aws_region}:${data.aws_caller_identity.current.account_id}:database/elid_dq",
51+
"arn:aws:glue:${var.default_aws_region}:${data.aws_caller_identity.current.account_id}:table/elid_dq/cohort_metrics"
52+
]
53+
},
54+
{
55+
# 3. Data Access (Your specific S3 bucket)
56+
Effect = "Allow"
57+
Action = [
58+
"s3:GetBucketLocation",
59+
"s3:GetObject",
60+
"s3:ListBucket"
61+
]
62+
Resource = [
63+
"arn:aws:s3:::${module.s3_dq_metrics_bucket.storage_bucket_name}",
64+
"arn:aws:s3:::${module.s3_dq_metrics_bucket.storage_bucket_name}/*"
65+
]
66+
},
67+
{
68+
# Athena Results - Staging Directory
69+
Effect = "Allow"
70+
Action = [
71+
"s3:GetBucketLocation",
72+
"s3:GetObject",
73+
"s3:ListBucket",
74+
"s3:PutObject"
75+
]
76+
Resource = [
77+
"arn:aws:s3:::${module.s3_athena_dq_query_bucket.storage_bucket_name}",
78+
"arn:aws:s3:::${module.s3_athena_dq_query_bucket.storage_bucket_name}/*"
79+
]
80+
}
81+
]
82+
})
83+
}

infrastructure/stacks/iams-developer-roles/github_actions_policies.tf

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,10 @@ resource "aws_iam_policy" "s3_management" {
235235
"arn:aws:s3:::*eligibility-signposting-api-${var.environment}-dq-metrics/*",
236236
"arn:aws:s3:::*eligibility-signposting-api-${var.environment}-dq-metrics-access-logs",
237237
"arn:aws:s3:::*eligibility-signposting-api-${var.environment}-dq-metrics-access-logs/*",
238+
"arn:aws:s3:::*eligibility-signposting-api-${var.environment}-athena-stage",
239+
"arn:aws:s3:::*eligibility-signposting-api-${var.environment}-athena-stage/*",
240+
"arn:aws:s3:::*eligibility-signposting-api-${var.environment}-athena-stage-access-logs",
241+
"arn:aws:s3:::*eligibility-signposting-api-${var.environment}-athena-stage-access-logs/*",
238242
]
239243
}
240244
]
@@ -607,6 +611,25 @@ resource "aws_iam_policy" "iam_management" {
607611
"arn:aws:iam::*:role/secret_rotation_lambda_role",
608612
"arn:aws:iam::*:role/secret_rotation_workflow_role"
609613
]
614+
},
615+
# Scoped User management for Tableau
616+
{
617+
Effect = "Allow",
618+
Action = [
619+
"iam:CreateUser",
620+
"iam:DeleteUser",
621+
"iam:UpdateUser",
622+
"iam:TagUser",
623+
"iam:CreateAccessKey",
624+
"iam:DeleteAccessKey",
625+
"iam:UpdateAccessKey",
626+
"iam:PutUserPolicy",
627+
"iam:DeleteUserPolicy",
628+
"iam:GetUser"
629+
],
630+
Resource = [
631+
"arn:aws:iam::${data.aws_caller_identity.current.account_id}:user/tableau-athena-service-account"
632+
]
610633
}
611634
]
612635
})
@@ -743,6 +766,65 @@ resource "aws_iam_policy" "cloudwatch_management" {
743766
tags = merge(local.tags, { Name = "cloudwatch-management" })
744767
}
745768

769+
# Athena/Glue Infrastructure Management Policy for GitHub Actions
770+
resource "aws_iam_policy" "athena_glue_management" {
771+
name = "athena-glue-management"
772+
description = "Allows GitHub Actions to create and manage Athena/Glue resources"
773+
path = "/service-policies/"
774+
775+
policy = jsonencode({
776+
Version = "2012-10-17",
777+
Statement = [
778+
{
779+
# 1. Permission to manage the Glue Metadata (The "Athena Database/Table")
780+
Effect = "Allow",
781+
Action = [
782+
"glue:CreateDatabase",
783+
"glue:DeleteDatabase",
784+
"glue:GetDatabase",
785+
"glue:UpdateDatabase",
786+
"glue:CreateTable",
787+
"glue:DeleteTable",
788+
"glue:UpdateTable",
789+
"glue:GetTable",
790+
"glue:GetTables",
791+
"glue:BatchCreatePartition",
792+
"glue:CreatePartition",
793+
"glue:DeletePartition",
794+
"glue:GetPartitions"
795+
],
796+
Resource = [
797+
"arn:aws:glue:${var.default_aws_region}:${data.aws_caller_identity.current.account_id}:catalog",
798+
"arn:aws:glue:${var.default_aws_region}:${data.aws_caller_identity.current.account_id}:database/elid_dq",
799+
"arn:aws:glue:${var.default_aws_region}:${data.aws_caller_identity.current.account_id}:table/elid_dq/*"
800+
]
801+
},
802+
{
803+
# 2. Permission to manage Athena Workgroups or Named Queries
804+
Effect = "Allow",
805+
Action = [
806+
"athena:CreateWorkGroup",
807+
"athena:DeleteWorkGroup",
808+
"athena:UpdateWorkGroup",
809+
"athena:GetWorkGroup",
810+
"athena:CreateNamedQuery",
811+
"athena:DeleteNamedQuery",
812+
"athena:GetNamedQuery",
813+
"athena:ListDataCatalogs",
814+
"athena:CreateDataCatalog",
815+
"athena:DeleteDataCatalog"
816+
],
817+
Resource = [
818+
"arn:aws:athena:${var.default_aws_region}:${data.aws_caller_identity.current.account_id}:workgroup/*",
819+
"arn:aws:athena:${var.default_aws_region}:${data.aws_caller_identity.current.account_id}:datacatalog/*"
820+
]
821+
}
822+
]
823+
})
824+
825+
tags = merge(local.tags, { Name = "athena-glue-management" })
826+
}
827+
746828
# Attach the policies to the role
747829
resource "aws_iam_role_policy_attachment" "terraform_state" {
748830
role = aws_iam_role.github_actions.name
@@ -788,3 +870,8 @@ resource "aws_iam_role_policy_attachment" "cloudwatch_management" {
788870
role = aws_iam_role.github_actions.name
789871
policy_arn = aws_iam_policy.cloudwatch_management.arn
790872
}
873+
874+
resource "aws_iam_role_policy_attachment" "athena_glue_management" {
875+
role = aws_iam_role.github_actions.name
876+
policy_arn = aws_iam_policy.athena_glue_management.arn
877+
}

infrastructure/stacks/iams-developer-roles/iams_permissions_boundary.tf

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,23 @@ data "aws_iam_policy_document" "permissions_boundary" {
221221
"states:CreateStateMachine",
222222
"states:TagResource",
223223
"states:UpdateStateMachine",
224+
225+
# Athena
226+
"athena:CreateWorkGroup",
227+
"athena:UpdateWorkGroup",
228+
"athena:GetQueryExecution",
229+
"athena:GetQueryResults",
230+
"athena:StartQueryExecution",
231+
"athena:GetWorkGroup",
232+
"athena:StopQueryExecution",
233+
"athena:GetDataCatalog",
234+
235+
# Glue
236+
"glue:CreateDatabase",
237+
"glue:GetDatabase",
238+
"glue:GetTable",
239+
"glue:GetTables",
240+
"glue:GetDatabases"
224241
]
225242

226243
resources = ["*"]
@@ -349,6 +366,26 @@ data "aws_iam_policy_document" "iam_bootstrap_permissions_boundary" {
349366
]
350367
}
351368

369+
# Specific management for Tableau Athena Service Account
370+
statement {
371+
sid = "AllowTableauServiceAccountManagement"
372+
effect = "Allow"
373+
actions = [
374+
"iam:CreateAccessKey",
375+
"iam:DeleteAccessKey",
376+
"iam:UpdateAccessKey",
377+
"iam:PutUserPolicy",
378+
"iam:DeleteUserPolicy",
379+
"iam:GetUserPolicy",
380+
"iam:TagUser",
381+
"iam:UntagUser",
382+
"iam:GetUser"
383+
]
384+
resources = [
385+
"arn:aws:iam::${data.aws_caller_identity.current.account_id}:user/tableau-athena-service-account"
386+
]
387+
}
388+
352389
# Allow read-only IAM access for Terraform plan/state discovery
353390
statement {
354391
sid = "AllowIamReadAccess"

0 commit comments

Comments
 (0)