-
Notifications
You must be signed in to change notification settings - Fork 4
159 lines (145 loc) · 6.81 KB
/
Copy pathdestroy-fargate-dev.yml
File metadata and controls
159 lines (145 loc) · 6.81 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
# Destroy AWS Fargate Dev Resources (one-off)
#
# Destroys all Fargate dev resources tracked in the Terraform state.
# Run once to clean up the dev Fargate environment.
name: Destroy Fargate Dev
on:
workflow_dispatch:
inputs:
confirm:
description: 'Type "destroy" to confirm'
required: true
# Least privilege: `id-token: write` is granted per job, only to the job that
# assumes the AWS deploy role, and that job is bound to the `dev` deployment
# environment. `guard` authenticates to nothing and must not hold it.
#
# IMPORTANT — what the `environment:` binding does and does not buy. It scopes
# secrets/vars and sets the OIDC subject to `repo:<org/repo>:environment:dev`,
# which the AWS trust policy's sub allowlist accepts (role.tf:30).
#
# It is NOT a reviewer gate. GitHub only blocks a job once required-reviewer
# protection rules are configured on the environment, and at the time of writing
# no environment in this repo has any. Until that is configured out-of-band this
# destroy job still runs unapproved. See #1660 for the live state — deliberately
# not restated here, so this comment cannot rot into false reassurance.
#
# The environment subject is ref-agnostic, so the binding does not by itself keep
# this workflow on `main`. The `guard` job below checks the ref, but that check is
# defense-in-depth against ACCIDENTS ONLY and is NOT a security boundary:
# `workflow_dispatch` runs the workflow file as it exists on the dispatched ref, so
# anyone able to push a branch can delete the check and still present the
# `environment:dev` subject. The only control that survives that is a deployment
# branch policy, which GitHub evaluates before the job starts and before the token
# is minted. See #1660.
permissions:
contents: read
env:
TF_VERSION: '1.10.0'
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
jobs:
guard:
name: Confirm Destruction
runs-on: ubuntu-latest
permissions: {}
steps:
# Catches the accidental "dispatched from the wrong branch" case. It does
# NOT stop a deliberate one: this file is attacker-controlled on the ref
# being dispatched, so the step can simply be deleted on that branch. The
# server-side equivalent is a deployment branch policy on `dev`
# (custom_branch_policies + a `main` pattern) — which does NOT require
# `main` to be a protected branch — tracked in #1660.
- name: Restrict to main
env:
REF: ${{ github.ref }}
run: |
if [ "$REF" != "refs/heads/main" ]; then
echo "::error::Refusing to destroy from '$REF'; this workflow may only be dispatched from refs/heads/main"
exit 1
fi
- name: Check confirmation
env:
CONFIRM: ${{ inputs.confirm }}
run: |
if [ "$CONFIRM" != "destroy" ]; then
echo "You must type 'destroy' exactly to confirm. Got: '$CONFIRM'"
exit 1
fi
destroy:
name: Terraform Destroy (Fargate dev)
runs-on: ubuntu-24.04-arm
needs: guard
# Destroys s3://<bucket>/github-fargate-dev/terraform.tfstate, the same
# state object deploy-aws-fargate.yml and cleanup-staging.yml write, so it
# takes the same concurrency group: one writer per state file, whatever
# workflow or ref it came from (#1806). The suffix is a literal because this
# job's state key is too. `cancel-in-progress: false` because cancelling
# mid-`terraform destroy` leaves a half-destroyed stack and a stuck lock.
concurrency:
group: aws-fargate-tfstate-dev
cancel-in-progress: false
permissions:
id-token: write
contents: read
# Binds the OIDC subject to repo:<org/repo>:environment:dev, which the AWS
# trust policy matches on. Not a reviewer gate until protection rules exist
# on this environment -- see the note at the top of this file.
environment: dev
# Set at job level, not workflow level: workflow-level `env:` is resolved
# before this job's `dev` environment is in scope, so an environment-scoped
# AWS_REGION variable would be invisible there. Matches cleanup-staging.yml.
env:
AWS_REGION: ${{ vars.AWS_REGION || 'us-east-1' }}
steps:
- name: Checkout code
uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@d979d5b3a71173a29b74b5b88418bfda9437d885 # v6.1.1
with:
role-to-assume: ${{ vars.AWS_ROLE_TO_ASSUME }}
aws-region: ${{ env.AWS_REGION }}
- name: Setup Terraform
uses: hashicorp/setup-terraform@dfe3c3f87815947d99a8997f908cb6525fc44e9e # v4.0.1
with:
terraform_version: ${{ env.TF_VERSION }}
# This step used to `aws s3 rm` the state lock object before every init,
# unconditionally and with no check that the lock was stale or anyone
# else's, so it deleted a live lock held by a concurrent writer. Removed
# with #1806; the job-level `concurrency` group above is what keeps
# writers apart now, and a loud "Error acquiring the state lock" is the
# correct outcome if one ever slips through. Recovery from a genuinely
# stranded lock is `terraform force-unlock <ID>` -- see
# runbooks/terraform-stuck-lock.md.
- name: Terraform Init
env:
TF_BACKEND: ${{ secrets.TF_BACKEND_AWS }}
run: |
printf '%s\nkey = "github-fargate-dev/terraform.tfstate"\n' "$TF_BACKEND" > /tmp/backend.tfbackend
cd terraform/environments/aws
terraform init -backend-config=/tmp/backend.tfbackend
- name: Force-delete ECR repo
run: |
for REPO in $(aws ecr describe-repositories \
--query "repositories[?contains(repositoryName,'cudly-dev')].repositoryName" \
--output text 2>/dev/null); do
echo "Force-deleting ECR repo $REPO..."
aws ecr delete-repository --repository-name "$REPO" --force 2>/dev/null \
|| echo " Failed to delete $REPO (may already be gone)"
done
- name: Disable RDS deletion protection
run: |
for INSTANCE_ID in $(aws rds describe-db-instances \
--query "DBInstances[?starts_with(DBInstanceIdentifier,'cudly-dev')].DBInstanceIdentifier" \
--output text 2>/dev/null); do
echo "Disabling deletion protection on $INSTANCE_ID..."
aws rds modify-db-instance --db-instance-identifier "$INSTANCE_ID" \
--no-deletion-protection --apply-immediately 2>/dev/null || true
done
- name: Terraform Destroy
env:
TF_VAR_admin_email: ${{ secrets.ADMIN_EMAIL }}
run: |
cd terraform/environments/aws
terraform destroy \
-var-file="github-dev.tfvars" \
-var="compute_platform=fargate" \
-auto-approve