Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
f452368
Update main.tf
florianamette Jul 23, 2025
2a94a19
Update main.tf
florianamette Jul 23, 2025
b0b598f
init
florianamette Feb 17, 2026
1516a77
init
florianamette Feb 17, 2026
2ebdf8b
init
florianamette Feb 17, 2026
519bcc2
init
florianamette Feb 17, 2026
4dcc825
init
florianamette Feb 17, 2026
30d2d51
init
florianamette Feb 17, 2026
eb16712
init
florianamette Feb 17, 2026
3b5a427
init
florianamette Feb 17, 2026
b7028ce
init
florianamette Feb 17, 2026
93ab268
init
florianamette Feb 17, 2026
0866679
init
florianamette Feb 17, 2026
e6ed403
init
florianamette Feb 17, 2026
2ce1719
fix tags
florianamette Feb 18, 2026
7003532
fix tags
florianamette Feb 18, 2026
8c4d857
fix tags
florianamette Feb 18, 2026
5753f0e
fix tags
florianamette Feb 18, 2026
e6b1511
fix tags
florianamette Feb 18, 2026
8d71387
fix tags
florianamette Feb 18, 2026
24b1141
fix tag
florianamette Feb 20, 2026
1b141d5
fix tag
florianamette Feb 20, 2026
682f806
fix tag
florianamette Feb 20, 2026
0c3d848
fix tag
florianamette Feb 20, 2026
9e816a6
fix tag
florianamette Feb 20, 2026
c151989
fix tag
florianamette Feb 20, 2026
65dd80b
fix tag
florianamette Feb 20, 2026
b90d74f
fix tag
florianamette Feb 20, 2026
5a0587d
fix tag
florianamette Feb 20, 2026
29ae0e0
fix tag
florianamette Feb 20, 2026
ec3ed25
fix tag
florianamette Feb 20, 2026
d9bec9b
fix tag
florianamette Feb 20, 2026
52f408e
fix tag
florianamette Feb 20, 2026
1ca67e5
fix tag
florianamette Feb 20, 2026
0990887
fix tag
florianamette Feb 20, 2026
ed64c00
fix tag
florianamette Feb 20, 2026
3b551c5
fix tag
florianamette Feb 20, 2026
c479629
fix tag
florianamette Feb 20, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
174 changes: 174 additions & 0 deletions .github/workflows/tf-apply-bulk.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
name: 'Terraform Apply (Bulk)'

on:
workflow_dispatch:
inputs:
number_of_instances:
description: "Number of lab instances to launch (e.g. 5 for student-01 through student-05)"
required: true
type: number
module:
type: choice
description: "Module to deploy for each instance"
options:
- module-1
- module-2
required: true
region:
description: "AWS region. Leave empty for eu-west-3 (Paris)."
required: false
type: string

permissions: write-all

jobs:
generate-ids:
name: 'Generate student IDs'
runs-on: ubuntu-latest
outputs:
student_ids: ${{ steps.ids.outputs.student_ids }}
steps:
- name: Build student IDs array
id: ids
run: |
n="${{ github.event.inputs.number_of_instances }}"
[ -z "$n" ] || [ "$n" -lt 1 ] && n=1
[ "$n" -gt 50 ] && n=50
arr="["
for i in $(seq 1 "$n"); do
[ $i -gt 1 ] && arr+=","
arr+="\"$(printf '%02d' $i)\""
done
arr+="]"
echo "student_ids=$arr" >> $GITHUB_OUTPUT
echo "Generated: $arr"

bootstrap:
name: 'Ensure state bucket exists'
needs: generate-ids
runs-on: ubuntu-latest
environment: production
env:
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
AWS_REGION: "eu-west-3"
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Set up Terraform
uses: hashicorp/setup-terraform@v2
with:
terraform_version: 1.10.5
- name: Set Account ID and Region
run: |
echo "ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text)" >> $GITHUB_ENV
REGION="${{ github.event.inputs.region || env.AWS_REGION || 'eu-west-3' }}"
echo "AWS_REGION=$REGION" >> $GITHUB_ENV
aws configure set region "$REGION"
- name: Create state bucket if missing
run: |
REGION="${{ github.event.inputs.region || env.AWS_REGION || 'eu-west-3' }}"
BUCKET="do-not-delete-awsgoat-state-files-${{ env.ACCOUNT_ID }}-${REGION}"
if aws s3api head-bucket --bucket "$BUCKET" 2>/dev/null; then
echo "State bucket already exists: $BUCKET (region $REGION)"
else
cd backend-bootstrap
terraform init -input=false
terraform apply -auto-approve -input=false -var="region=$REGION"
echo "State bucket created: $BUCKET in region $REGION"
fi

terraform:
name: 'Apply (${{ matrix.student_id }})'
needs: [generate-ids, bootstrap]
runs-on: ubuntu-latest
environment: production
strategy:
fail-fast: false
max-parallel: 5
matrix:
student_id: ${{ fromJson(needs.generate-ids.outputs.student_ids) }}
env:
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
AWS_REGION: "eu-west-3"

defaults:
run:
shell: bash

steps:
- name: Checkout
uses: actions/checkout@v4

- name: Set up Terraform
uses: hashicorp/setup-terraform@v2
with:
terraform_version: 1.10.5

- name: Set Account ID and Region
id: account
run: |
echo "ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text)" >> $GITHUB_ENV
REGION="${{ github.event.inputs.region || env.AWS_REGION || 'eu-west-3' }}"
echo "AWS_REGION=$REGION" >> $GITHUB_ENV
aws configure set region "$REGION"

- name: Ensure state bucket exists
run: |
REGION="${{ github.event.inputs.region || env.AWS_REGION || 'eu-west-3' }}"
BUCKET="do-not-delete-awsgoat-state-files-${{ env.ACCOUNT_ID }}-${REGION}"
if ! aws s3api head-bucket --bucket "$BUCKET" 2>/dev/null; then
cd backend-bootstrap
terraform init -input=false
terraform apply -auto-approve -input=false -var="region=$REGION"
fi

- name: Terraform Init (S3 backend)
run: |
cd modules/${{ github.event.inputs.module }}
terraform init -reconfigure -input=false \
-backend-config="bucket=do-not-delete-awsgoat-state-files-${{ env.ACCOUNT_ID }}-${{ env.AWS_REGION }}" \
-backend-config="key=terraform.tfstate" \
-backend-config="region=${{ env.AWS_REGION }}" \
-backend-config="workspace_key_prefix=${{ github.event.inputs.module }}"

- name: Terraform Workspace
run: |
cd modules/${{ github.event.inputs.module }}
terraform workspace select ${{ matrix.student_id }} 2>/dev/null || terraform workspace new ${{ matrix.student_id }}

- name: Import existing resources (once, before plan)
run: |
cd modules/${{ github.event.inputs.module }}
terraform workspace select ${{ matrix.student_id }} 2>/dev/null || terraform workspace new ${{ matrix.student_id }}
chmod +x ../../scripts/import-existing-resources.sh
ACCOUNT_ID=${{ env.ACCOUNT_ID }} AWS_REGION=${{ env.AWS_REGION }} bash ../../scripts/import-existing-resources.sh ${{ github.event.inputs.module }} ${{ matrix.student_id }}
continue-on-error: true

- uses: actions/setup-python@v5
with:
python-version: 3
- name: Install boto3
run: pip install boto3

- name: Terraform Plan
run: |
cd modules/${{ github.event.inputs.module }}
terraform workspace select ${{ matrix.student_id }} 2>/dev/null || terraform workspace new ${{ matrix.student_id }}
terraform plan -input=false -var="student_id=${{ matrix.student_id }}" -var="region=${{ env.AWS_REGION }}"
continue-on-error: false

- name: Terraform Apply
run: |
cd modules/${{ github.event.inputs.module }}
terraform workspace select ${{ matrix.student_id }} 2>/dev/null || terraform workspace new ${{ matrix.student_id }}
terraform apply -auto-approve -input=false -var="student_id=${{ matrix.student_id }}" -var="region=${{ env.AWS_REGION }}"
continue-on-error: false

- name: Outputs
if: success()
run: |
cd modules/${{ github.event.inputs.module }}
terraform workspace select ${{ matrix.student_id }} 2>/dev/null || true
terraform output
74 changes: 49 additions & 25 deletions .github/workflows/tf-apply-main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,14 @@ on:
- module-1
- module-2
required: true
student_id:
description: "Student/lab instance ID for multi-student deployment (e.g. student-01). Leave empty for single default deployment."
required: false
type: string
region:
description: "AWS region for deployment (e.g. eu-west-1). Leave empty to use AWS_REGION env or eu-west-3 (Paris)."
required: false
type: string

permissions: write-all

Expand All @@ -22,7 +30,7 @@ jobs:
env:
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
AWS_REGION: "us-east-1"
AWS_REGION: "eu-west-3"

defaults:
run:
Expand All @@ -37,30 +45,45 @@ jobs:
with:
terraform_version: 1.10.5

- name: Set Account ID
- name: Set Account ID, Student ID and Region
id: account
run: |
echo "ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text)" >> $GITHUB_ENV
echo "STUDENT_ID=${{ github.event.inputs.student_id || 'default' }}" >> $GITHUB_ENV
REGION="${{ github.event.inputs.region || env.AWS_REGION || 'eu-west-3' }}"
echo "AWS_REGION=$REGION" >> $GITHUB_ENV
aws configure set region "$REGION"

- name: Check previous AWSGoat Deployment
id: check
- name: Ensure state bucket exists
run: |
echo ${{ env.ACCOUNT_ID }}
aws s3api head-object --bucket do-not-delete-awsgoat-state-files-${{ env.ACCOUNT_ID }} --key terraform.tfstate
continue-on-error: true
BUCKET="do-not-delete-awsgoat-state-files-${{ env.ACCOUNT_ID }}-${{ env.AWS_REGION }}"
if ! aws s3api head-bucket --bucket "$BUCKET" 2>/dev/null; then
cd backend-bootstrap
terraform init -input=false
terraform apply -auto-approve -input=false -var="region=${{ env.AWS_REGION }}"
fi

- name: Exit if previous deployment exists
if: steps.check.outcome == 'success'
- name: Terraform Init (S3 backend)
run: |
echo "A Previous AWSGoat deployment exists, run the Terraform Destroy Action"
exit 1
cd modules/${{ github.event.inputs.module }}
terraform init -reconfigure -input=false \
-backend-config="bucket=do-not-delete-awsgoat-state-files-${{ env.ACCOUNT_ID }}-${{ env.AWS_REGION }}" \
-backend-config="key=terraform.tfstate" \
-backend-config="region=${{ env.AWS_REGION }}" \
-backend-config="workspace_key_prefix=${{ github.event.inputs.module }}"

# Initialize a new or existing Terraform working directory
- name: Terraform Init
run: |
- name: Terraform Workspace (multi-student)
if: env.STUDENT_ID != 'default'
run: |
cd modules/${{ github.event.inputs.module }}
terraform init

terraform workspace select ${{ env.STUDENT_ID }} 2>/dev/null || terraform workspace new ${{ env.STUDENT_ID }}

- name: Import existing resources (if any)
run: |
chmod +x scripts/import-existing-resources.sh
ACCOUNT_ID=${{ env.ACCOUNT_ID }} AWS_REGION=${{ env.AWS_REGION }} ./scripts/import-existing-resources.sh ${{ github.event.inputs.module }} ${{ env.STUDENT_ID }}
continue-on-error: true

# Installs boto3
- uses: actions/setup-python@v5
with:
Expand All @@ -73,25 +96,26 @@ jobs:
id: plan
run: |
cd modules/${{ github.event.inputs.module }}
terraform plan -input=false
if [ "${{ env.STUDENT_ID }}" != "default" ]; then
terraform workspace select ${{ env.STUDENT_ID }} 2>/dev/null || terraform workspace new ${{ env.STUDENT_ID }}
fi
terraform plan -input=false -var="student_id=${{ env.STUDENT_ID }}" -var="region=${{ env.AWS_REGION }}"
continue-on-error: false

- name: Terraform Plan Status
if: steps.plan.outcome == 'failure'
run: exit 1

- name: Terraform Apply
run: |
run: |
cd modules/${{ github.event.inputs.module }}
terraform apply -auto-approve -input=false
if [ "${{ env.STUDENT_ID }}" != "default" ]; then
terraform workspace select ${{ env.STUDENT_ID }} 2>/dev/null || terraform workspace new ${{ env.STUDENT_ID }}
fi
terraform apply -auto-approve -input=false -var="student_id=${{ env.STUDENT_ID }}" -var="region=${{ env.AWS_REGION }}"
continue-on-error: false

# Copy tfstate file to s3 bucket
- name: Copy terraform.tfstate file to s3bucket
if: always()
run: |
cd modules/${{ github.event.inputs.module }}
aws s3 cp ./terraform.tfstate s3://do-not-delete-awsgoat-state-files-${{ env.ACCOUNT_ID }}/terraform.tfstate
# State is stored in S3 by the backend; no manual copy needed.

# Terraform Output the API Gateway url
- name: Application URL
Expand Down
Loading