Skip to content

Getting Started

This guide covers installation, configuration, and running your first NetSecGame session.

Installation

The easiest way to run the NetSecGame server is via the official Docker image:

docker pull stratosphereips/netsecgame

Building the image locally

docker build -t netsecgame:local .

To build the experimental Whitebox variant (agents receive the full action list upon registration):

docker build --build-arg GAME_MODULE="netsecgame.game.worlds.WhiteBoxNetSecGame" -t netsecgame:local-whitebox .

Warning

The Whitebox variant is currently experimental.

pip install (agent development)

To install the package for developing agents:

pip install netsecgame

To include dependencies for running the game server locally:

pip install netsecgame[server]

Installing from source

For modifying the environment itself, install in a virtual environment:

=== "Python venv"

python -m venv <venv-name>
source <venv-name>/bin/activate
pip install -e .

=== "Conda"

conda create --name aidojo python==3.12
conda activate aidojo
pip install -e .

Task Configuration

A YAML configuration file defines the task for the NetSecGame. It specifies starting positions, goals, rewards, and environment properties.

Example Configuration

# The objective of the Attacker in this task is to locate specific data
# and exfiltrate it to a remote C&C server.
# The scenario starts AFTER the initial breach of the local network
# (the attacker controls 1 local device + the remote C&C server).

coordinator: 
  agents: 
    Attacker: # Configuration of 'Attacker' agents
      max_steps: 25 # timeout set for the role `Attacker`
      goal: # Definition of the goal state
        description: "Exfiltrate data from Samba server to remote C&C server."
        known_networks: []
        known_hosts: []
        controlled_hosts: []
        known_services: {}
        known_data: {213.47.23.195: [[User1,DataFromServer1]]} # winning condition
        known_blocks: {}
      start_position: # Definition of the starting state
        known_networks: []
        known_hosts: []
        controlled_hosts: [213.47.23.195, random] # 'random' is replaced during init
        known_services: {}
        known_data: {}
        known_blocks: {}

    Defender:
      goal:
        description: "Block all attackers"
        known_networks: []
        known_hosts: []
        controlled_hosts: []
        known_services: {}
        known_data: {}
        known_blocks: {213.47.23.195: 'all_attackers'}

      start_position:
        known_networks: []
        known_hosts: []
        controlled_hosts: []
        known_services: {}
        known_data: {}
        blocked_ips: {}
        known_blocks: {}

env: # Environment configuration
  scenario: 'two_networks_tiny' # use the smallest topology
  use_global_defender: False
  use_dynamic_addresses: False
  use_firewall: True
  save_trajectories: False
  required_players: 1
  rewards:
    success: 100
    step: -1
    fail: -10
    false_positive: -5

For a full reference of all configuration options, see the Configuration Documentation.

Running the Game Server

In Docker

docker run -d --rm --name nsg-server \
  -v $(pwd)/examples/example_task_configuration.yaml:/netsecgame/netsecenv_conf.yaml \
  -v $(pwd)/logs:/netsecgame/logs \
  -p 9000:9000 stratosphereips/netsecgame \
  --debug_level="INFO"
Flag Description
--name nsg-server Name of the container
-v <config>:/netsecgame/netsecenv_conf.yaml Mount your configuration file
-v $(pwd)/logs:/netsecgame/logs Mount logs directory
-p <port>:9000 Expose the game server port
--debug_level Logging level: DEBUG, INFO, WARNING, CRITICAL (default: INFO)

Running on Windows (Docker Desktop)

docker run -d --rm --name nsg-server ^
  -p 9000:9000 ^
  -v "%cd%\examples\example_task_configuration.yaml:/netsecgame/netsecenv_conf.yaml" ^
  -v "%cd%\logs:/netsecgame/logs" ^
  stratosphereips/netsecgame:latest ^
  --debug_level="INFO"

Locally

python3 -m netsecgame.game.worlds.NetSecGame \
  --task_config=./examples/example_task_configuration.yaml \
  --game_port=9000 \
  --debug_level="INFO"

The game server will start on localhost:9000.

Creating Your First Agent

Agents connect to the game server and interact using the standard RL loop: submit an Action, receive an Observation.

All agents should extend the BaseAgent class:

from netsecgame import BaseAgent, Action, GameState, Observation, AgentRole

class MyAgent(BaseAgent):
    def __init__(self, host, port, role: str):
        super().__init__(host, port, role)

    def choose_action(self, observation: Observation) -> Action:
        # Define your logic here based on observation.state
        pass

def main():
    agent = MyAgent(host="localhost", port=9000, role=AgentRole.Attacker)
    observation = agent.register()

    while not observation.end:
        action = agent.choose_action(observation)
        observation = agent.make_step(action)

    agent.terminate_connection()

For full agent implementations, see the NetSecGameAgents repository.

Interaction Flow

sequenceDiagram
    participant Agent
    participant Server as NetSecGame Server

    Agent->>Server: JoinGame (register)
    Server-->>Agent: Initial Observation (state, reward, end, info)

    loop Until end == True
        Agent->>Server: Action (e.g., ScanNetwork, ExploitService)
        Server-->>Agent: Observation (next_state, reward, end, info)
    end

    Agent->>Server: ResetGame (optional)
    Server-->>Agent: Initial Observation (new episode)

    Agent->>Server: QuitGame