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