Skip to main content

Creating Your First Exercise

For this example, we will create an actual exercise defining VMs and network switches necessary for one participant. It will consist of a server VM that will be given to the participant, a scoring VM that will track the participants progress and a network switch that will connect the two. As well as Features that install the necessary components and Conditions that check if the participant has completed his tasks.

Now that we have a package, we can create an exercise that uses it. To do so, we need to login to the Ranger website and login.

After creating our new Exercise, we can start working on the SDL (Scenario Description Language) file. The SDL file is written in the YAML format that describes the exercise. Detailed information about the SDL file can be found in the SDL Reference Guide.

The YAML Syntax

A very quick overview of the basic YAML syntax used in the SDL:

# A key value pair
key: value

# A list - YAML uses indentation to define structure
key:
- value
- value2

# A map
key:
key2: value
key3: value2
key4:
- value3
- value4

Writing the SDL

We can write our SDL in the Ranger website in the Dashboard tab. It also provides a simple syntax checker to help us write the SDL.

We can start by giving our SDL a name:

name: "My First Exercise"

With the exclusion of pen and paper exercises, all exercises probably need a VM. For this example, we will use two VM packages, a pre-made package called debian-12-gui-docker as a base image for our WordPress server and debian11-network-manager for our scoring machine and a switch to connect the two. In the SDL all VM's and Switches belong under the nodes block. Following the reference guide, we can define our VM with its mandatory fields:

Nodes

nodes:
wordpress-server:
type: vm
source: debian-12-gui-docker
resources:
cpu: 2
ram: 4 GiB

scoring-machine:
type: vm
source: debian11-network-manager
resources:
cpu: 2
ram: 4 GiB

switch:
type: switch

To install additional packages like Features or Conditions we also need to give it roles so we have access to the VMs accounts and later connect a Participant entity to the VM itself. Roles reference the account names defined in the package. For this example, we will use the root account.

nodes:
wordpress-server:
type: vm
source: debian-12-gui-docker
resources:
cpu: 1
ram: 2 GiB
roles:
admin: root

Infrastructure

Infrastructure allows us to specify the number of nodes or network switches we want to create, as well as their interconnections and dependencies.

For our example we deploy one VM per node and link them to our switch:

infrastructure:
switch: 1

wordpress-server:
count: 1
links:
- switch

scoring-machine:
count: 1
links:
- switch

nodes:
wordpress-server:
type: vm
source: debian-12-gui-docker
resources:
cpu: 2
ram: 4 GiB
roles:
admin: root

scoring-machine:
type: vm
source: debian11-network-manager
resources:
cpu: 2
ram: 4 GiB

switch:
type: switch

Entities

Now that we have a VM, we can connect it to a Participant entity. An entity can be either an organization, a team or a person. Giving them a role is necessary for automatic and manual scoring purposes. For this example, we will create a Blue Team and give it one participant:

entities:
blue-team:
role: Blue
entities:
participant:
role: Blue

We're now prepared to update the admin role in our VM. The format for assigning child entities is <parent>.<child>.<grandchild> ... etc. At present, we're using the shorthand notation for our admin role. To add an entity, we must switch to the longhand notation:

nodes:
wordpress-server:
type: vm
source: debian-12-gui-docker
resources:
cpu: 2
ram: 4 GiB
roles:
admin:
username: root
entities:
- blue-team.participant

We have now successfully connected our VM to a participant. Later when connecting the participant entity to a real user's account, they can see the VMs credentials they were assigned in their dashboard.

Features

Features are used to copy files onto the VM and run arbitrary commands after it has been initialized. This gives us flexibility and modularity for using the same base VM packages for different purposes. For this example, we will install a WordPress server by using the wordpress-4-8-0-docker package from the Deputy Digital Library. To do so, we need to add a features block:

features:
wordpress:
type: service
source: wordpress-4-8-0-docker

Additionally, we need to give our VMs static IP addresses so this specific deployment may intercommunicate with each other as designed. For this example, we will use the debian-ip-setter package from the Deputy Digital Library. We will need to define two features, one for each VM:

features:
wordpress:
type: service
source: wordpress-4-8-0-docker

static-ip-1:
type: service
source: debian-ip-setter
environment:
- STATIC_IP=10.1.1.1/24

static-ip-2:
type: service
source: debian-ip-setter
environment:
- STATIC_IP=10.1.1.2/24

Now we need to add the feature to the VM and give it access to a role with which the service will be installed. For this example, we will use the admin role.

nodes:
wordpress-server:
type: vm
source: debian-12-gui-docker
resources:
cpu: 2
ram: 4 GiB
roles:
admin:
username: root
entities:
- blue-team.participant
features:
static-ip-1: admin
wordpress: admin

scoring-machine:
type: vm
source: debian11-network-manager
resources:
cpu: 2
ram: 4 GiB
roles:
admin: root
features:
static-ip-2: admin

Conditions

Conditions are arbitrary scripts that are installed onto and run on their assigned VM and periodically check the state of something. They are always installed after all Features have been installed. They return a value between 0..1 to the Ranger and are used for both scoring purposes in Metrics or as triggers for Events.

In short, Conditions are used to check if a participant has completed a task.

For our example we will use a condition to check if our WordPress server is still using its default insecure administrator credentials by using a pre-made package called wordpress-check-credentials. Defining them is similar to defining Features.

This condition also requires a WP_URL environment variable to be set, which points it at the target WordPress website.

The use of a scoring machine may not be necessary for all exercises as the conditions can run directly on the participants VM instead. Condition streams will also recover if participants shut down or reboot their VMs. However since conditions are just scripts that are run on the VMs, if the user has root access to the VM they could modify or disable the conditions.

conditions:
wordpress-check-credentials:
source: wordpress-check-credentials
environment:
- WP_URL=10.1.1.1:8000

# ...

nodes:
wordpress-server:
type: vm
source: debian-12-gui-docker
resources:
cpu: 2
ram: 4 GiB
roles:
admin:
username: root
entities:
- blue-team.participant
features:
wordpress: admin
conditions:
wordpress-check-credentials: admin

Now we are checking the state of our WordPress server. However to make use of the Condition in our scoring system we need to define the scoring related blocks Metrics, Evaluations and TLOs (Training Learning Objectives).

Metrics

Metrics are used to quantify a specific condition. They can be either conditional where they are connected to a Condition or manual where the participant manually submits a value or file for the Ranger manager to evaluate.

In our example we will connect the metric to our existing condition and give it an arbitrary max-score of 100 points.

metrics:
wordpress-credentials-metric:
type: conditional
max-score: 100
condition: wordpress-check-credentials

Evaluations

Evaluations are used to gauge if a metric or group of metrics have been sufficiently completed by comparing the metric's score to a defined minimum score threshold. The min-score threshold can be either an absolute value or a percentage of the combined maximum score of its assigned metrics.

For our example we will use the shorthand version of the min-score threshold and set it to 100 percent.

evaluations:
wordpress-credentials-evaluation:
min-score: 100
metrics:
- wordpress-credentials-metric

Training and Learning Objectives (TLOs)

Training and Learning Objectives (TLOs) are used to describe the learning objectives of an exercise. By connecting it to our Evaluation, we can define the TLOs that are achieved by completing the exercise.

tlos:
wordpress-credentials-tlo:
evaluation: wordpress-credentials-evaluation

To connect the TLO to the participant, we need to add it to the participants entity:

tlos:
wordpress-credentials-tlo:
evaluation: wordpress-credentials-evaluation

entities:
blue-team:
role: Blue
entities:
participant:
role: Blue
tlos:
- wordpress-credentials-tlo

Injects

Injects are next in our chain. They define a source which is an Inject type package that will be deployed once the Event has been triggered. It is similar to a Feature except Injects can be deployed at any point during the exercise's runtime.

injects:
demo_inject:
source: flag-generator

Let us also add the Inject to our Node so we will know with which roles and to which VM it will be deployed to:

nodes:
wordpress-server:
type: vm
source: debian-12-gui-docker
resources:
cpu: 2
ram: 4 GiB
roles:
admin:
username: root
entities:
- blue-team.participant
features:
wordpress: admin
conditions:
wordpress-check-credentials: admin
injects:
demo_inject: admin

Events

Events are used to trigger the installation of Injects and show additional information to the participant. Optionally, events can also hold a source field that references an Event type package which contains a markdown file that will be shown to the participant when the Event is triggered in their Events tab.

In the following example we define a conditional event which will only be deployed if the condition returns a 1.0 value during the events deployment window, which we will define in the coming scripts block. It is also possible to omit the conditions entirely and have the event always be deployed once its deployment window opens.

Each event is unique per deployment, meaning:

  • Conditions and injects do not need to be on the same VM.
  • If multiple VMs have the same events conditions, they must all be at a success (1.0) state for the event to be deployed.
  • If multiple VMs have the same events injects they will all deployed once the event is triggered.
events:
example-event:
name: Demo Event
source: demo-event-info
conditions:
- wordpress-check-credentials
injects:
- demo_inject

For our participant to be able to see the event in their Events tab after it has triggered, we need to add it to the entities block. Events defined under entities are inherited to all of its children. In our example, if we were to define it under blue-team it would be inherited by participant as well.

entities:
blue-team:
role: Blue
entities:
participant:
role: Blue
tlos:
- wordpress-credentials-tlo
events:
- example-event

Scripts

Scripts define the time window during which the Events connected to it can be triggered. Events additionally have a time field indicating when the Event will become eligible to be triggered.

scripts:
demo_script:
start-time: 0
end-time: 2h
speed: 1
events:
example-event: 5m

In the above example, we have set our scripts start-time to 0 which will start it at the beginning of the deployment and end after 2 hours have passed. The speed field is used to speed up or slow down the time during which the Events can be triggered. The default value is 1, meaning the Events will be triggered at the same rate as the deployment time. A value of 2 will trigger the Events twice as fast and a value of 0.5 will trigger them half as fast.

The events time field is used to define when the Event will become eligible to be triggered during the scripts deployment window. In our example, the example-event will be eligible to be triggered after 5 minutes have passed since the start of the deployment. The events time value must be equal or greater than the scripts start-time and less or equal than the scripts end-time.

Stories

Stories are used to group Scripts together and additionally control the rate at which Scripts are triggered. As with Scripts, the speed variable is a time multiplier, setting it to 2 will cause its Scripts to start and end twice as fast.

stories:
demo_story:
speed: 1
scripts:
- demo_script

Putting it all together

In this example SDL we have created a simple exercise that deploys a WordPress server and a scoring machine which are connected over a switch. We have also defined a condition that checks over the network if the WordPress server is still using its default insecure administrator credentials and a metric that shows us the result of that check as a score. Our evaluation sets the minimum score threshold to 100 percent and our TLO is connected to the participant entity. If the condition passes the event will be triggered and the inject will be deployed and our participant will be able to see it in their Events tab if their entity is connected to their Ranger user by the manager.

In the end our SDL file should look something like this:

name: "My First Exercise"

stories:
demo_story:
speed: 1
scripts:
- demo_script

scripts:
demo_script:
start-time: 0
end-time: 2h
speed: 1
events:
example-event: 5m

events:
example-event:
name: Bonus Tasks
source: demo-event-info
conditions:
- wordpress-check-credentials
injects:
- demo_inject

injects:
demo_inject:
source: flag-generator

conditions:
wordpress-check-credentials:
source: wordpress-check-credentials
environment:
- WP_URL=10.1.1.1:8000

features:
wordpress:
type: service
source: wordpress-4-8-0-docker
static-ip-1:
type: service
source: debian-ip-setter
environment:
- STATIC_IP=10.1.1.1/24
static-ip-2:
type: service
source: debian-ip-setter
environment:
- STATIC_IP=10.1.1.2/24

nodes:
wordpress-server:
type: vm
source: debian-12-gui-docker
resources:
cpu: 2
ram: 4 GiB
roles:
admin:
username: root
entities:
- blue-team.participant
features:
static-ip-1: admin
wordpress: admin
injects:
demo_inject: admin

scoring-machine:
type: vm
source: debian11-network-manager
resources:
cpu: 2
ram: 4 GiB
roles:
admin: root
features:
static-ip-2: admin
conditions:
wordpress-check-credentials: admin

switch:
type: switch

infrastructure:
switch: 1
wordpress-server:
count: 1
links:
- switch
scoring-machine:
count: 1
links:
- switch

metrics:
wordpress-credentials-metric:
type: conditional
max-score: 100
condition: wordpress-check-credentials

evaluations:
wordpress-credentials-evaluation:
min-score: 100
metrics:
- wordpress-credentials-metric

tlos:
wordpress-credentials-tlo:
evaluation: wordpress-credentials-evaluation

entities:
blue-team:
role: Blue
entities:
participant:
role: Blue
tlos:
- wordpress-credentials-tlo
events:
- example-event