@@ -12,6 +12,66 @@ locals {
1212 }
1313}
1414
15+ # S3 bucket for CodeBuild artifacts (terraform outputs)
16+ module "codebuild_artifacts" {
17+ source = " ../../../modules/secure-bucket"
18+
19+ name = " forms-review-codebuild-artifacts"
20+ versioning_enabled = false
21+ access_logging_enabled = false
22+ }
23+
24+ resource "aws_s3_bucket_lifecycle_configuration" "codebuild_artifacts" {
25+ bucket = module. codebuild_artifacts . name
26+
27+ rule {
28+ id = " expire-old-artifacts"
29+ status = " Enabled"
30+
31+ filter {}
32+
33+ expiration {
34+ days = 1
35+ }
36+ }
37+ }
38+
39+ # CodeBuild projects for each app
40+ module "codebuild_deploy" {
41+ for_each = local. github_actions_apps
42+ source = " ./review-app-codebuild"
43+
44+ application_name = each. key
45+ action = " deploy"
46+ github_repository = " https://github.com/alphagov/${ each . key } "
47+ codeconnection_arn = data. terraform_remote_state . account . outputs . codeconnection_arn
48+ artifacts_bucket_name = module. codebuild_artifacts . name
49+ ecs_cluster_arn = aws_ecs_cluster. review . arn
50+ ecs_cluster_name = aws_ecs_cluster. review . name
51+ ecr_repository_arn = each. value . ecr_repository_arn
52+ task_execution_role_arn = aws_iam_role. ecs_execution . arn
53+ autoscaling_role_arn = aws_iam_service_linked_role. app_autoscaling . arn
54+ deploy_account_id = var. deploy_account_id
55+ }
56+
57+ module "codebuild_destroy" {
58+ for_each = local. github_actions_apps
59+ source = " ./review-app-codebuild"
60+
61+ application_name = each. key
62+ action = " destroy"
63+ github_repository = " https://github.com/alphagov/${ each . key } "
64+ codeconnection_arn = data. terraform_remote_state . account . outputs . codeconnection_arn
65+ artifacts_bucket_name = module. codebuild_artifacts . name
66+ ecs_cluster_arn = aws_ecs_cluster. review . arn
67+ ecs_cluster_name = aws_ecs_cluster. review . name
68+ ecr_repository_arn = each. value . ecr_repository_arn
69+ task_execution_role_arn = aws_iam_role. ecs_execution . arn
70+ autoscaling_role_arn = aws_iam_service_linked_role. app_autoscaling . arn
71+ deploy_account_id = var. deploy_account_id
72+ }
73+
74+ # OIDC roles with minimal permissions (trigger CodeBuild + push to ECR)
1575resource "aws_iam_role" "github_actions" {
1676 for_each = local. github_actions_apps
1777
@@ -20,23 +80,21 @@ resource "aws_iam_role" "github_actions" {
2080
2181 assume_role_policy = jsonencode ({
2282 Version = " 2012-10-17"
23- Statement = [
24- {
25- Effect = " Allow"
26- Action = " sts:AssumeRoleWithWebIdentity"
27- Principal = {
28- Federated = data.terraform_remote_state.account.outputs.github_oidc_provider_arn
83+ Statement = [{
84+ Effect = " Allow"
85+ Action = " sts:AssumeRoleWithWebIdentity"
86+ Principal = {
87+ Federated = data.terraform_remote_state.account.outputs.github_oidc_provider_arn
88+ }
89+ Condition = {
90+ StringEquals = {
91+ " token.actions.githubusercontent.com:aud" = " sts.amazonaws.com"
2992 }
30- Condition = {
31- StringEquals = {
32- " token.actions.githubusercontent.com:aud" = " sts.amazonaws.com"
33- }
34- StringLike = {
35- " token.actions.githubusercontent.com:sub" = " repo:alphagov/${ each . key } :pull_request"
36- }
93+ StringLike = {
94+ " token.actions.githubusercontent.com:sub" = " repo:alphagov/${ each . key } :pull_request"
3795 }
3896 }
39- ]
97+ } ]
4098 })
4199}
42100
@@ -50,164 +108,60 @@ resource "aws_iam_role_policy" "github_actions" {
50108data "aws_iam_policy_document" "github_actions" {
51109 for_each = local. github_actions_apps
52110
111+ # Trigger CodeBuild projects
53112 statement {
54- sid = " UseECSServices"
55- effect = " Allow"
56- actions = [
57- " ecs:*Service" ,
58- " ecs:*Services" ,
59- " ecs:TagResource"
60- ]
113+ sid = " TriggerCodeBuild"
114+ actions = [" codebuild:StartBuild" , " codebuild:BatchGetBuilds" ]
61115 resources = [
62- aws_ecs_cluster . review . arn ,
63- " arn:aws:ecs:eu-west-2: ${ data . aws_caller_identity . current . account_id } :service/ ${ aws_ecs_cluster . review . name } / ${ each . key } -pr-* "
116+ module . codebuild_deploy [ each . key ] . project_arn ,
117+ module . codebuild_destroy [ each . key ] . project_arn
64118 ]
65119 }
66120
121+ # Read CodeBuild logs
67122 statement {
68- sid = " UseECSTaskDefinitions"
69- effect = " Allow"
70- actions = [
71- " ecs:*TaskDefinition" ,
72- " ecs:*TaskDefinitions" ,
73- " ecs:TagResource"
74- ]
123+ sid = " ReadCodeBuildLogs"
124+ actions = [" logs:GetLogEvents" ]
75125 resources = [
76- " arn:aws:ecs:eu-west-2:${ data . aws_caller_identity . current . account_id } :task-definition/${ each . key } -pr-*"
77- ]
78- }
79-
80- statement {
81- sid = " AllowTaskDefinitionsNeedingStar"
82- effect = " Allow"
83- actions = [
84- " ecs:DeregisterTaskDefinition" ,
85- " ecs:DescribeTaskDefinition"
126+ module . codebuild_deploy [each . key ]. log_group_arn ,
127+ module . codebuild_destroy [each . key ]. log_group_arn
86128 ]
87- resources = [" *" ]
88129 }
89130
131+ # Push container images to ECR
90132 statement {
91- sid = " ReadTerraformStateFiles"
92- effect = " Allow"
93- actions = [
94- " s3:GetObject" ,
95- " s3:GetObjectVersion" ,
96- " s3:HeadObject" ,
97- " s3:ListBucket"
98- ]
99- resources = [
100- " arn:aws:s3:::gds-forms-integration-tfstate" ,
101- " arn:aws:s3:::gds-forms-integration-tfstate/review.tfstate" ,
102- " arn:aws:s3:::gds-forms-integration-tfstate/review-apps/${ each . key } /pr-*.tfstate"
103- ]
104- }
105-
106- statement {
107- sid = " WriteTerraformStateFiles"
108- effect = " Allow"
109- actions = [
110- " s3:PutObject" ,
111- " s3:PutObjectVersion"
112- ]
113- resources = [
114- " arn:aws:s3:::gds-forms-integration-tfstate/review-apps/${ each . key } /pr-*.tfstate"
115- ]
116- }
117-
118- statement {
119- sid = " ReleaseTerraformStateLock"
120- actions = [
121- " s3:DeleteObject" ,
122- ]
123- resources = [
124- " arn:aws:s3:::gds-forms-integration-tfstate/review-apps/${ each . key } /pr-*.tflock"
125- ]
126- effect = " Allow"
127- }
128-
129- statement {
130- sid = " UseLocalECR"
131- effect = " Allow"
133+ sid = " PushToECR"
132134 actions = [
133135 " ecr:BatchCheckLayerAvailability" ,
134- " ecr:BatchGetImage" ,
135136 " ecr:CompleteLayerUpload" ,
136- " ecr:GetDownloadUrlForLayer" ,
137137 " ecr:InitiateLayerUpload" ,
138138 " ecr:PutImage" ,
139- " ecr:UploadLayerPart" ,
140- ]
141- resources = [
142- each . value . ecr_repository_arn
143- ]
144- }
145-
146- statement {
147- sid = " LogIntoLocalECR"
148- effect = " Allow"
149- actions = [
150- " ecr:GetAuthorizationToken" ,
151- ]
152- resources = [
153- " *"
154- ]
155- }
156-
157- statement {
158- sid = " UseDeployECR"
159- effect = " Allow"
160- actions = [
161- " ecr:BatchCheckLayerAvailability" ,
162- " ecr:BatchGetImage" ,
163- " ecr:GetDownloadUrlForLayer"
164- ]
165- resources = [
166- " arn:aws:ecr:eu-west-2:${ var . deploy_account_id } :repository/*"
139+ " ecr:UploadLayerPart"
167140 ]
141+ resources = [each . value . ecr_repository_arn ]
168142 }
169143
170144 statement {
171- sid = " AllowIAMPassRole"
172- effect = " Allow"
173- actions = [
174- " iam:PassRole"
175- ]
176- resources = [
177- aws_iam_role . ecs_execution . arn ,
178- aws_iam_service_linked_role . app_autoscaling . arn ,
179- ]
145+ sid = " ECRLogin"
146+ actions = [" ecr:GetAuthorizationToken" ]
147+ resources = [" *" ]
180148 }
181149
150+ # Wait for ECS service stability (read-only)
182151 statement {
183- sid = " UseAppAutoscaling"
184- effect = " Allow"
185- actions = [
186- " application-autoscaling:*ScalableTarget" ,
187- " application-autoscaling:*ScalableTargets" ,
188- " application-autoscaling:*ScheduledAction" ,
189- " application-autoscaling:*ScheduledActions" ,
190- " application-autoscaling:*ScalingPolicy" ,
191- " application-autoscaling:*ScalingPolicies" ,
192- " application-autoscaling:ListTagsForResource" ,
193- " application-autoscaling:TagResource" ,
194- " application-autoscaling:UntagResource"
195- ]
152+ sid = " WaitForECSStability"
153+ actions = [" ecs:DescribeServices" ]
196154 resources = [
197- " arn:aws:application-autoscaling :eu-west-2:${ data . aws_caller_identity . current . account_id } :scalable-target/ *"
155+ " arn:aws:ecs :eu-west-2:${ data . aws_caller_identity . current . account_id } :service/ ${ aws_ecs_cluster . review . name } / ${ each . key } -pr- *"
198156 ]
199157 }
200158
159+ # Read and delete CodeBuild artifacts (terraform outputs)
201160 statement {
202- sid = " UseAppAutoscalingNeedingStar"
203- effect = " Allow"
204- actions = [
205- " application-autoscaling:DescribeScalableTargets" ,
206- " application-autoscaling:DescribeScalingPolicies" ,
207- " application-autoscaling:DescribeScheduledActions" ,
208- ]
161+ sid = " ReadArtifacts"
162+ actions = [" s3:GetObject" , " s3:DeleteObject" ]
209163 resources = [
210- " * "
164+ " ${ module . codebuild_artifacts . arn } /*/review- ${ each . key } -deploy/outputs.json "
211165 ]
212166 }
213167}
0 commit comments