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
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 first define all of the containers that your challenge needs to run, and then declare how you want them exposed 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. 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
.
Whether a container needs to be rebuilt is determined by looking at every file
in the Docker build context. Thus, it is very important that you include only
what is necessary in the build context by using a .dockerignore
file; at
minimum, challenge.yaml
should be excluded to prevent needing to rebuild the
container when the challenge’s description is updated.
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).
Expose
The top-level expose
key defines all of the ports on 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:
# 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 }}
.
Reference
.. jsonschema:: ../rcds/challenge/challenge.schema.yaml
Raw schema:
.. literalinclude:: ../rcds/challenge/challenge.schema.yaml
:language: yaml