jedevc / ctf-infra

Template infrastructure for CTFs :monkey:

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

CTF Infrastructure

This is my template infrastructure for Capture the Flag competitions.

Challenges

The challenges are managed using ctftool, a home-grown tool for managing challenge metadata and information. See the GitHub page for more documentation on the exact formats allowed.

Essentially, all challenges are placed into the challenges/ directory, and should contain either a challenge.yaml or challenge.json file.

Useful ctftool commands used in development include:

  • Listing:
    $ ./ctftool.py list
    
  • Validation:
    $ ./ctftool.py validate
    

Deployment

Deploying the CTF should be fairly simple once setup, but can be a little involved.

There are three options:

  • Docker (not recommended)
  • Docker Compose
  • Kubernetes

For all of them, you'll need to point your DNS records in the right place. It's recommended that if your challenges ues HTTP servers, you should access your challenges over a different domain name than the CTFd instance - otherwise, browsers will try and be "clever" and upgrade you to HTTPS for your challenges

Docker

The docker build steps contain basic primitives for building challenge images and containers. They probably shouldn't be used on their own, and are intended to be used in conjunction with either docker-compose or kubernetes.

Build the challenge images:

$ ./deploy/build.py

Build and push challenge images to a private registry:

$ export IMAGE_REPO=...
$ ./deploy/build.py --push

The next steps assume that you have configured your machines to automatically pull from this private registry.

Docker Compose

Deploying using docker-compose is a more lightweight alternative to building and maintaining an entire cluster. However, it will definitely be less flexible, so keep that in mind when making a decision.

Set PYTHONPATH to the directory containing ctftool.py so you can import it in other scripts:

$ export PYTHONPATH=$PWD

Copy the infrastructure code to a build directory:

$ mkdir -p build
$ cp -R deploy/docker-compose/ build/

Build the build step for the infrastructure:

$ ./build/docker-compose/generate.sh

Launch it!

$ cd build/docker-compose
$ docker-compose up

Kubernetes

To deploy using Kubernetes, you first need a cluster. Then, once you've installed the dependencies (listed below), you can install the entire infra.

Export required environment variables (see .env.sample for more info):

$ export DOMAIN=ctfd.example.com
$ export CTFD_MYSQL_DB=ctfd
$ export CTFD_MYSQL_USER=ctfd
$ export CTFD_MYSQL_PASSWORD=password
$ export CTFD_REDIS_PASSWORD=password
$ export CTFD_SECRET=ctfd

Install dependencies

Ingress

You need to install Nginx Ingress.

The following installs it without a LoadBalancer service, for lower costs.

$ helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
$ helm repo update
$ kubectl create namespace ingress-nginx
$ helm install ingress ingress-nginx/ingress-nginx \
    --namespace ingress-nginx \
    --set controller.hostNetwork=true \
    --set controller.kind=DaemonSet \
    --set controller.hostPort.enabled=true \
    --set controller.service.enabled=false \
    --set controller.publishService.enabled=false
Cert Manager

To handle TLS certificates, we use Cert Manager.

NOTE: Make sure that your DNS records are pointing to the right place!

First we install it:

$ helm repo add jetstack https://charts.jetstack.io
$ helm repo update
$ kubectl create namespace cert-manager
$ helm install cert-manager jetstack/cert-manager \
    --namespace cert-manager \
    --version v1.0.3 \
    --set installCRDs=true

Then we need to setup a couple LetsEncrypt issuers (one for staging, one for production):

apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: letsencrypt-staging
spec:
  acme:
    server: https://acme-staging-v02.api.letsencrypt.org/directory
    email: letsencrypt@example.com
    privateKeySecretRef:
      name: letsencrypt-staging
    solvers:
    - http01:
        ingress:
          class: nginx
---
apiVersion: cert-manager.io/v1alpha2
kind: ClusterIssuer
metadata:
  name: letsencrypt-prod
spec:
  acme:
    server: https://acme-v02.api.letsencrypt.org/directory
    email: letsencrypt@example.com
    privateKeySecretRef:
      name: letsencrypt-prod
    solvers:
    - http01:
        ingress:
          class: nginx

When you setup the ClusterIssuers, the CTFd instance should automatically be given a TLS certificate.

Build

Copy the infrastructure code to a build directory:

$ mkdir -p build
$ cp -R deploy/kube/ build/

Build the build step for the infrastructure:

$ ./build/kube/generate.sh

Apply the infrastructure to the cluster:

$ kubectl apply -k build/kube/

Notes

  • The kubernetes infra uses NodePort to expose services ports to the internet. By default this range is 30000-32767, but it's often nice to expose ports lower than that.

    You can modify this range by modifying apiserver.service-port-range. For kubeadm, edit /etc/kubernetes/manifests/kube-apiserver.yaml and add --service-node-port-range=<lower>-<upper> to spec.containers.command.

About

Template infrastructure for CTFs :monkey:


Languages

Language:Python 98.5%Language:Shell 1.0%Language:Dockerfile 0.5%