ctfup — Our Challenge-Deployer
Introducing ctfup
ctfup is an npm package developed to streamline the deployment of CTF challenges to a kubernetes cluster.
Manually building and deploying containers onto Kubernetes clusters is a slow and tiresome process. If a challenge were to go down during the CTF, it would waste a lot of time having to re-deploy the containers manually. We automated this process with the help of ctfup.
Built with
- Node.js
- Typescript
- Google Kubernetes
Note: ctfup is designed to work on the repository structure specified in this article: Structuring your Repository for CTF challenges.
TL;DR
With the help of ctfup, you can deploy your challenges to your Kubernetes cluster with the help of GitHub Actions! You can check out the action here.
Usage
You can add a configuration file in the root directory of your repository called ctfup.yml
(you could call it anything, but for the sake of convenience we’ll call itctfup.yml
). Through this, you can define the categories, registry, and default resources.
This is a sample configuration file for ctfup. If you leave out the resources
section, it will use the defaults from ctfup.yml
in the root directory of your repository.
The challenge.yml
files inside the challenge folders can be used to override these defaults. In csictf 2020, we used the same challenge.yml
for ctfcli
(for adding challenges to CTFd) and ctfup
.
Note: The containers
section must be present for ctfup to be able to treat it as a hosted challenge. If you want to use default resources as specified in ctfup.yml
, you can leave out the resources
.
Now, you can run the following command to deploy your challenges to your Kubernetes cluster! (We assume you have gcloud
and kubectl
set up. If not, refer to this article!)
ctfup -c ctfup.yml .
Here, -c
points to your config file ctfup.yml
and .
is the path to your challenge repository.
You can optionally add the -d
option. This option takes a commit hash and deploys only those challenges which changed since that commit hash. This reduces the build time manifold.
ctfup -c ctfup.yml -d f244820d5d87913a2b936ca91c87d5775c545ba1
ctfup with GitHub Actions
You can use GitHub Actions as CI/CD to run ctfup and deploy your containers to the registry. Using the following CI/CD config, every time you push to master, ctfup will push the latest changes to your registry.
You need to have a tag named latest
on your repository for this action to work properly. Besides, you need to set up 2 secrets on the repository, namely GKE_SA_KEY
and GKE_PROJECT
.
How it Works
Note: By this point, you already know how to configure and use ctfup. You may read this section if you want a brief explanation of how ctfup works.
There are 2 important classes in ctfup, namely Challenges
and Deployer
.
Challenges
This class consists of a static memberparse
, which looks inside every challenge folder in each category and parses the challenge.yml
file. If the containers
key is set in the config, it classifies the challenge as hosted
, otherwise, it is set to non-hosted
. The remaining configuration for eachhosted
challenge is parsed and an array of Challenge
objects is returned.
Deployer
First, an object of this Deployer
class is created, which sets up Kubernetes using the @kubernetes/client-node
library. Then, for each challenge in the challenges
array (which was returned by the Challenges
class), we run Deployer.buildChallenge(challenge)
, followed by deployer.deployChallenge(challenge)
. The buildChallenge
method, as the name suggests, is responsible for building the docker container, and the deployChallenge
class pushes the built container onto the registry.
You can find the source code for ctfup in the Links section below.
Learn more…
If you played csictf 2020, you would have heard about Kuwu, right? Find out more about Kuwu in the next article!