ctfup — Our Challenge-Deployer

Rohan Mukherjee
csictf
Published in
3 min readAug 2, 2020

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!

Links

--

--