GitHub Action
CTFd-Setup
CTFd does not have the concept of configuration file, leading to deployment complications and the impossibility to version configurations. This is problematic for reproducibility or sharing configuration for debugging or replicating a CTF infrastructure.
Moreover, the setup API does not exist, so we had to map it to what the frontend calls in go-ctfd.
To fit those gaps, we built ctfd-setup
on top of the CTFd API. This utility helps setup a CTFd instance from a YAML configuration file, CLI flags and environment variables.
Thanks to this, you can integrate it using GitHub Actions, Drone CI or even as part of your IaC provisionning.
With ctfd-setup
you can setup your CTFd in a second.
You can use ctfd-setup
as a CLI tool and provision it a YAML configuration file.
appearance:
name: 'My CTF'
description: 'My CTF description'
admin:
name: 'admin'
email: '[email protected]'
password: 'admin_password'
mode: users
We encourage you to version this file such that re-deployment is easy (e.g., for test purposes, or in case of a catastrophic failure of the infra during the event).
Nevertheless, please do not commit the admin credentials ! Use from_env
objects instead (refer to the YAML Schema for more info).
It could also deploy custom pages (like the index) as follows. This feature is not available in CLI, GitHub Actions and Drone CI.
# ... other configuration attributes
pages:
additional:
- title: CTFer.io example index
route: index
format: markdown
content: |
<div>
<p>Some index page content</p>
</div>
For further configuration, please refer to the binary's specific API through ctfd-setup --help
.
To improve our own workflows and share knownledges and tooling, we built a GitHub Action: ctfer-io/ctfd-setup
.
You can use it given the following example.
name: 'My workflow'
on:
push:
branches:
- 'main'
jobs:
my-job:
runs-on: 'ubuntu-latest'
steps:
- name: 'Setup CTFd'
uses: 'ctfer-io/[email protected]'
with:
url: ${{ secrets.CTFD_URL }}
file: '.ctfd.yaml'
# or directly attributes
appearance_name: 'My CTF'
appearance_description: 'My CTF description'
admin_name: ${{ secrets.ADMIN_USERNAME }}
admin_email: ${{ secrets.ADMIN_EMAIL }}
admin_password: ${{ secrets.ADMIN_PASSWORD }}
# ... and so on (non-mandatory attributes)
This could also be used as part of a Drone CI use ctferio/ctfd-setup
.
kind: pipeline
type: docker
name: 'My pipeline'
trigger:
branch:
- main
event:
- push
steps:
# ...
- name: 'Setup CTFd'
image: 'ctferio/[email protected]'
settings:
url:
from_secret: CTFD_URL
file: '.ctfd.yaml'
# or directly attributes
appearance_name: 'My CTF'
appearance_description: 'My CTF description'
admin_name:
from_secret: ADMIN_USERNAME
admin_email:
from_secret: ADMIN_EMAIL
admin_password:
from_secret: ADMIN_PASSWORD
# ... and so on (non-mandatory attributes)
For ease of use, you can generate and use the ctfd-setup
YAML schema using ctfd-setup schema
.
In your .ctfd.yaml
file you could then prepend # yaml-language-server: $schema=file:///path/to/schema.json
.
For deployment purposes (and especially in the deployment case of Kubernetes), you may want to ensure the integrity of what you run.
The release assets are SLSA 3 and can be verified using slsa-verifier using the following.
slsa-verifier verify-artifact "<path/to/release_artifact>" \
--provenance-path "<path/to/release_intoto_attestation>" \
--source-uri "github.com/ctfer-io/ctfd-setup" \
--source-tag "<tag>"
The Docker image is SLSA 3 and can be verified using slsa-verifier using the following.
slsa-verifier slsa-verifier verify-image "ctferio/ctfd-setup:<tag>@sha256:<digest>" \
--source-uri "github.com/ctfer-io/ctfd-setup" \
--source-tag "<tag>"
Alternatives exist, like Kyverno for a Kubernetes-based deployment.
A SBOM for the whole repository is generated on each release and can be found in the assets of it. They are signed as SLSA 3 assets. Refer to Signature and Attestations to verify their integrity.
A SBOM is generated for the Docker image in its manifest, and can be inspected using the following.
docker buildx imagetools inspect "ctferio/ctfd-setup:<tag>" \
--format "{{ json .SBOM.SPDX }}"