Automatically deploy your CTF challenges from GitHub to CTFd. Also supports containerised challenges on managed CTFd, Kubernetes, Microsoft Azure, or Google's kCTF.
- A managed or self-hosted CTFd instance
- An education discount is available for managed instances. Contact support for more details.
- GitHub account for each challenge author. Consider GitHub Education if you're eligible
- Click here to create a repository for your CTF. Select "Private" to prevent public access
- Allow GitHub Actions to create pull requests
- Create the following secrets
Name | Value |
---|---|
CTFD_TOKEN |
CTFd admin access token |
CTFD_SITE_PASSWORD (optional) |
CTFd site password, if enabled |
Name | Value |
---|---|
CTFD_DOMAIN |
CTFd domain, eg example.ctfd.io |
FLAG_PREFIX (optional) |
Flag prefix for linting, eg ctf{ |
- See containers for more options
- Invite your team members to access the repo
- Create GitHub issues for each challenge. Send a link like this to your challenge authors: [your-repo-url]/issues/new/choose
- Consider using GitHub Codespaces for challenge development
- Add CTFd pages to the
pages
folder, and they'll automatically be deployed
Get the latest updates with the following commands. You may need to resolve merge conflicts.
git pull https://github.com/pl4nty/auto-CTFd --allow-unrelated-histories --rebase=false --squash -X theirs
git commit -m "chore: update repo template"
git push
Some challenges, like pwn or web, may need to run services in containers. These can be deployed to several platforms. To disable a platform, disable its GitHub workflow.
Note that managed CTFd has certain Dockerfile requirements and limitations. Please see the CTFd documentation for more details.
Create the following variables
Name | Value |
---|---|
REGISTRY |
Managed CTFd registry, eg registry.ctfd.io/example |
- Add a Compose file like
docker-compose.yml
to each of your challenge(s) - Ensure TCP challenges have unique ports
- Create the following variables
Name | Value |
---|---|
REGISTRY |
A container registry accessible by the Kubernetes cluster |
KUBE_HOST |
Hostname for challenges. HTTP challenges will be available via ingress on example.KUBE_HOST , and TCP challenges via load balancer service on KUBE_HOST:port |
- Create the following secrets
Name | Value |
---|---|
REGISTRY_USERNAME |
Container registry username |
REGISTRY_PASSWORD |
Container registry password |
KUBE_CONFIG |
A static kubeconfig file. To use a dynamic file instead, modify the workflow to retrieve its own kubeconfig eg using azure/aks-set-context |
- Deploy the challenges
- Create an ingress controller in the cluster
- Create a public DNS record for
*.KUBE_HOST
to the controller's IP address - Create a public DNS record for
KUBE_HOST
to the load balancer IP address
- Create an Azure app registration and federated credentials
- Create an Azure Container Apps environment. Note that a custom vnet is required for TCP ports.
- Delete the quickstart Container App, and assign the
Contributor
role on its resource group to the app registration - Create a user-assigned managed identity and
- Create an Azure Container Registry and assign the
AcrPull
role on it to the managed identity - (Optional) Add a custom DNS suffix to the Container Apps environment
- Create the following variables
Name | Value |
---|---|
REGISTRY |
A container registry accessible by the Container Apps environment |
AZURE_TENANT_ID |
App registration tenant ID |
AZURE_CLIENT_ID |
App registration client ID |
AZURE_CONTAINER_ENV |
Container Apps environment resource ID |
AZURE_CONTAINER_IDENTITY |
Managed identity resource ID |
AZURE_CONTAINER_SUFFIX |
Container Apps environment DNS suffix, eg chals.example.com |
- Set up kCTF infrastructure
- Create a Docker Artefact Registry with the same name as the GKE cluster (pending google/kctf#406)
- Create a Workload Identity Pool and Provider
- Grant Kubernetes Engine Developer and Artifact Registry Writer roles to the Pool
# TODO: replace ${PROJECT_ID}, ${WORKLOAD_IDENTITY_POOL_ID}, and ${REPO}
# with your values below.
#
# ${REPO} is the full repo name including the parent GitHub organization,
# such as "my-org/my-repo".
#
# ${WORKLOAD_IDENTITY_POOL_ID} is the full pool id, such as
# "projects/123456789/locations/global/workloadIdentityPools/github".
gcloud projects add-iam-policy-binding "${PROJECT_ID}" \
--role="roles/container.developer" \
--member="principalSet://iam.googleapis.com/${WORKLOAD_IDENTITY_POOL_ID}/attribute.repository/${REPO}"
gcloud projects add-iam-policy-binding "${PROJECT_ID}" \
--role="roles/artifactregistry.writer" \
--member="principalSet://iam.googleapis.com/${WORKLOAD_IDENTITY_POOL_ID}/attribute.repository/${REPO}"
- Create the following variables
Name | Value |
---|---|
KCTF_CONFIG |
Contents of the kCTF config file kctf/config/.lastconfig |
KCTF_IDENTITY |
Workload Identity Provider resource name |