Skip to content

Commit

Permalink
docs: add user docs
Browse files Browse the repository at this point in the history
Still missing overview / introduction
  • Loading branch information
ethanwu10 committed Jul 4, 2020
1 parent e0809e4 commit 9aab5ce
Show file tree
Hide file tree
Showing 6 changed files with 397 additions and 0 deletions.
43 changes: 43 additions & 0 deletions docs/backends/index.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
Deployment Backends
===================

rCDS uses a pluggable backend model for the task of actually deploying
challenges to infrastructure. rCDS contains a few built-in backends, and
third-party backends may be loaded by specifying their module name.

Backends are specified in the top-level configuration :file:`rcds.yaml`:

.. code-block:: yaml
backends:
- resolve: name
options:
key: value
The top-level key ``backends`` is an array of backend objects, which consist of
their name (``resolve``) and the options for the backend (``options``).
``resolve`` first attempts to load a built-in backend of the corresponding name,
and, if it does not exist, then interprets the name as a package name and loads
from it.

Each backend may also modify the ``challenge.yaml`` schema---be sure to read
the docs for the backends you are using to understand challenge options specific
to that backend.

Scoreboard Backends
-------------------

These are responsible for displaying the challenge to competitors; they handle
uploading the challenge's metadata (description, flags, point value, etc) and
any assets that are served to competitors.

- `rCTF <rctf/index.html>`_

Container Runtime Backends
--------------------------

These are responsible for running the built challenge containers. By design,
none of the built-in backends will start containers on the machine that rCDS is
being run from.

- `Kubernetes <k8s/index.html>`_
77 changes: 77 additions & 0 deletions docs/backends/k8s/index.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
``k8s`` --- Kubernetes
======================

This backend deploys challenges to a Kubernetes cluster. Each challenge is
deployed under its own namespace, and exposed via either a NodePort service or
an Ingress object, depending on the protocol specified by the challenge. No
accommodations are currently being made in case of NodePort conflicts---it is
recommended that challenges are deployed to an isolated cluster (you should be
doing this anyways since Kubernetes currently does not have hard multi-tenancy).
A NetworkPolicy is also created to prevent network traffic from outside a
challenge's namespace reaching any containers which are not explicitly exposed.

Configuration
-------------

The only required option is ``domain``---NodePort services must be reachable on
this domain, and the cluster's ingress controller must be reachable on its
subdomains. For example, if ``domain`` is set as ``example.com``, then
``example.com`` must accept incoming TCP connections to NodePort services, and
``chall.example.com`` must be routed through the cluster's ingress controller.
It is your responsibility to set up the ingress controller.

Additional annotations on ingress and service objects can be specified through
the ``annotations`` key, and affinity and tolerations on pods can be set through
``affinity`` and ``tolerations``, respectively.

See the `Options Reference`_ for more details.

Recommended Cluster Configuration
---------------------------------

RBAC
~~~~

As always, we recommend running rCDS from a CI service; thus, rCDS will need to
authorize with your Kubernetes cluster. We have provided a ClusterRole which
grants the minimum privileges required by the Kubernetes backend (also
accessible here__):

.. __: https://github.com/redpwn/rcds/blob/master/docs/content/backends/k8s/cluster-role.yaml

.. literalinclude:: ./cluster-role.yaml
:language: yaml

Cluster Operator
~~~~~~~~~~~~~~~~

We recommend `Google Kubernetes Engine`_, because it supports restricting of the
metadata server by Kubernetes service account, a feature called `Workload
Identity`_. This prevents SSRF from escalating into takeover of compute
resources.

.. _Google Kubernetes Engine: https://cloud.google.com/kubernetes-engine
.. _Workload Identity: https://cloud.google.com/kubernetes-engine/docs/how-to/workload-identity

Ingress
~~~~~~~

Traefik_ is recommended as an ingress controller, since it is very configurable
and supports JSON access logging for easy visibility into your challenges with
your cluster operator's logging solution. Consider manually issuing a wildcard
LetsEncrypt certificate and setting it as the default. Then, set annotations on
ingresses to use TLS, and configure Traefik to upgrade HTTP to HTTPS for full
HTTPS on challenges.

.. note::

By default, Traefik will attempt to auto-detect Content-Type; apply the
``contentType`` middleware to disable this behavior if it breaks your
challenges.

.. _Traefik: https://traefik.io/

Options Reference
-----------------

.. jsonschema:: ../../../rcds/backends/k8s/options.schema.yaml
36 changes: 36 additions & 0 deletions docs/backends/rctf/index.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
``rctf`` --- rCTF
=================

This backend deploys challenges to rCTF_. The options ``url`` and ``token``
specify the URL of the rCTF instance and the token of the admin account to use,
respectively. Both of these will be set from the environment variables
``RCDS_RCTF_URL`` and ``RCDS_RCTF_TOKEN`` respectively, if they exist.
Challenges with a ``value`` set are assumed to be statically-scored; all other
challenges are dynamically-scored according to the global ``scoring`` config
(between ``scoring.minPoints`` and ``scoring.maxPoints``). rCTF does not support
regex flags.

.. _rCTF: https://rctf.redpwn.net/

The ``sortOrder`` option allows you to automatically set the ``sortWeight``
fields on challenges based on an ordering provided in this key. Listed
challenges are assigned a ``sortWeight`` equal to its index in the array
multiplied by -1. This means that if all the challenges have the same score and
solve count, they will be displayed with the first element of the array at the
top.

Additional Challenge Properties
-------------------------------

``author`` and ``category`` are required.

``tiebreakEligible`` (bool): whether or not this challenge factors into time-based
tiebreakers. Defaults to ``true``.

``sortWeight`` (number): rCTF sort weight parameter. Ignored if the challenge is
listed in the global ``sortOrder`` option. Defaults to ``0``.

Options Reference
-----------------

.. jsonschema:: ../../../rcds/backends/rctf/options.schema.yaml
177 changes: 177 additions & 0 deletions docs/challenge.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
``challenge.yaml`` --- Challenge Config
=======================================

The file ``challenge.yaml`` defines the configuration for a challenge within an
rCDS project. ``.yml`` and ``.json`` files are also supported.

Basics
------

``id`` --- the identifier for this challenge. Must be unique project wide. This
key is set automatically from the name of the directory the challenge is in;
unless you have a very good reason to, don't set this in ``challenge.yaml``.

``author`` -- a string or list of strings containing the authors for this
challenge.

``description`` -- self-explanatory. It is in Markdown format and will be
processed with Jinja_. See Templating_ for more details.

``category`` -- self-explanatory. If the challenge directory is exactly two
directories deep (for example, ``/pwn/chall``, where ``/`` is the project root),
this is set from the parent directory of the challenge's directory ("pwn" in the
previous example). We recommend organizing your challenges in a
:samp:`{category}/{chall}` structure.

``flag`` --- the flag for the challenge. If it is a string, then the flag is set
to the string verbatim. Otherwise, if ``flag.file`` is set, the flag is loaded
from the specified file (relative to the challenge root), and stripped of
leading and trailing whitespace. If ``flag.regex`` is set, the flag is anything
matching the given regex. A warning is emitted if the flag contains multiple
lines (usually this is from an improperly configured flag file).

``provide`` --- an array of files to provide to competitors as downloads. The
files can either be a string, in which case they are interpreted as the path to
the file, or an object with the ``file`` and ``as`` properties; these properties
define the path and the displayed name of the file, respectively.

``value`` --- point value of this challenge. Meaning is defined by the
scoreboard backend.

``visible`` --- if set to ``false``, the scoreboard backend will act as if this
challenge does not exist.

.. warning::

Most scoreboard backends will delete any challenges that were created by
rCDS but now no longer exist---switching ``visible`` to ``false`` after the
challenge has already been deployed may cause solves to be lost.

Deployment
----------

In rCDS, you define first define all of the `containers <#containers>`_ that
your challenge needs to run, and then declare how you want them `exposed
<#expose>`_ to the world.

``deployed`` --- whether or not this challenge's containers should be deployed.
Defaults to ``true``.

Containers
~~~~~~~~~~

The ``containers`` key is an object whose keys are the names of the containers
this challenge creates. These containers can either use an existing image, or
specify a path to a Dockerfile to build from. Each container must declare all
ports that need to be connected to, both from other containers and by
competitors; which ports are exposed to competitors are specified `separately
<#expose>`_. Containers from the same challenge can connect to each other via a
DNS lookup of their names; for example, if a container ``app`` is defined,
another container can connect to any of ``app``'s declared ports by looking up
the name ``app``.

``image`` --- the tag of an existing image to run

``build`` --- settings for building this container. If it is a string, then it
is the path to the Docker build context (the directory where a Dockerfile is).
It can also be an object for advanced configuration:

``build.context`` --- path to the Docker build context.

``build.dockerfile`` --- path to the Dockerfile, relative to the build context
root.

``build.args`` --- Docker build args to set when building the container.
Key-value object.

``ports`` --- a list of integers of the port numbers this container listens on.
If anything needs to connect to a port on the container, list it here.

``replicas`` --- number of replicas of this container to run (on backends that
support it). Defaults to 1. Leave at 1 for stateful containers.

``environment`` --- key-value object of environment variables to set.

``resources`` --- resource limits on the container. See `Kubernetes's
documentation`__ on the format of this value (only ``cpu`` and ``memory`` are
implemented).

.. __: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/

Expose
~~~~~~

The top-level ``expose`` key defines all of the ports on `containers
<#containers>`_ that should be exposed to competitors. It is an object whose
keys correspond to the names of defined containers, and whose values are arrays
of port objects. These objects each describe how one port should be exposed.

``target`` --- the port on the container that this rule is targeting.

``tcp`` --- if specified, this port should be treated as TCP. The value is the
port at which it is exposed on, on the challenge host.

``http`` --- if specified, this port should be treated as HTTP, and will be
reverse proxied with TLS termination. The value is a string, the subdomain name
on which the challenge will be hosted. Alternatively, it can be an object with a
``raw`` key, in which case ``http.raw`` contains the FQDN that the challenge
will be served on. When using ``http.raw``, rCDS will handle the virtual
hosting, however as a challenge author, you will need to coordinate with your
infrastructure admin on setting up TLS and DNS records.

Templating
----------

Challenge descriptions are rendered using Jinja_. The contents of the
challenge's config is available on the ``challenge`` object in the Jinja
environment. Some fields are altered with more concrete versions of their
contents---for example, the ``http`` key on ``expose`` port objects will contain
the fully-qualified domain name, instead of just the prefix. Container backends
will also add a ``host`` key to a TCP ``expose`` port, which contains the host at
which that port will be accessible.

.. note::

An example configuration:

.. code-block:: yaml
# challenge.yaml
...
description: |
1: {{ challenge.expose.main[0].http }}
2: {{ challenge.expose.main[1].host }}:{{ challenge.expose.main[1].tcp }}
containers:
main:
ports: [1337, 1338]
expose:
main:
- target: 1337
http: leet
- target: 1338
tcp: 31253
Assuming the container backend is hosted on example.com, the description
would render as:

1: leet.example.com

2: example.com:31253

There are also shortcuts available for the most common use-case: a single
exposed port. ``host`` is the hostname under which the port is accessible.
``link`` will automatically create a Markdown link to the exposed port, and
``url`` will create just the URL without the accompanying Markdown. This works
for both HTTP and TCP ports, since you may want to expose a challenge which
breaks behind a reverse proxy as TCP. For TCP ports, there is also ``port``,
which is the exposed port number of the port, and ``nc``, which
will create a ``nc`` command to connect to the challenge---it is equivalent to
``nc {{ host }} {{ port }}``.

.. _Jinja: https://jinja.palletsprojects.com

Reference
---------

.. jsonschema:: ../rcds/challenge/challenge.schema.yaml
10 changes: 10 additions & 0 deletions docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,18 @@ rCDS - A CTF Challenge Deployment Tool
:maxdepth: 1
:caption: Contents

project
challenge
backends/index
contributing

.. toctree::
:maxdepth: 1
:caption: Backends

backends/rctf/index
backends/k8s/index

.. toctree::
:maxdepth: 2
:caption: API Reference
Expand Down
Loading

0 comments on commit 9aab5ce

Please sign in to comment.