-
Notifications
You must be signed in to change notification settings - Fork 18
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Still missing overview / introduction
- Loading branch information
Showing
6 changed files
with
397 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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>`_ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.