Skip to content

Shuffle Hands-on Labs

Choose the route that fits your available time and computing resources. Use the Interactive Lab to build and run a simple Wazuh alert-delivery workflow in this page, or use the Full Lab to build and validate a more advanced workflow in virtual machines.

Hands-on proof of concept

Build it. Test it. Recover it.

Start with a safe lab, build an observable suspicious-login workflow, require approval before containment, and prove that success, failure, and rollback are all recorded.

⏱ 4–6 hours core◆ Guided beginner✓ Evidence required
Self-hosted · Several hours

Shuffle Full Lab

Installation required

How to use this lab

This is a guided capstone rather than a click-by-click transcript. Complete the core route with the supplied mock API first. Product labels may differ by Shuffle version, but every checkpoint states the input and result you must verify.

Keep response actions reversible

Use only a disposable training identity, the reserved address 203.0.113.66, and a lab-only blocklist. Require approval before containment and never use production credentials.

Before you begin

You need: a working Shuffle installation, permission to create and run workflows, Python 3 on a lab host, connectivity from Shuffle to that host, and a clean recovery point.

How to progress

Complete one session at a time. Stop when a milestone fails. Fix that boundary before adding another node, integration, or test case.

Optional extension

Product Integration Challenge

After the core passes, replace one mock endpoint with Wazuh, TheHive, VirusTotal, or another dedicated training integration.

Expected time: one or more additional sessions.

  1. Session 1 · Activity 1Prepare and verify
  2. Session 2 · Activity 2Build and approve
  3. Session 3 · Activity 3Break and recover

Objective

Install Shuffle, send a synthetic suspicious-login alert, enrich and record the event, require approval before a reversible block, and prove that invalid input, connector failure, duplicate delivery, and rollback are handled safely.

The Guided Core Lab is the complete three-activity route on this page:

  1. Activity 1 — Prepare and verify: establish a safe, working foundation.
  2. Activity 2 — Build and approve: create and validate the response playbook.
  3. Activity 3 — Break and recover: test failure, duplication, and rollback.

Complete these activities in order. The Product Integration Challenge is an optional extension after Activity 3, not part of the Guided Core Lab.

Before Activity 1

Prepare these components for the Guided Core Lab:

Component Minimum requirement Purpose
Shuffle One supported Linux VM with Docker Compose Workflow editor, execution engine, and run history
Alert source Supplied synthetic JSON or an isolated Wazuh instance Sends a controlled suspicious-login event
Mock services Supplied Python API on a reachable lab host Identity lookup, case record, notification, temporary block, and failure controls
Test data lab-admin and 203.0.113.66 Reserved values that cannot target a real public system

Use mock endpoints for the guided baseline. Add a real product only after the baseline succeeds.

Start the mock API

  1. Download the lab-only mock API to a host reachable from the Shuffle worker.
  2. On an isolated lab network, replace <mock-host-address> with that host's lab address and run:
python3 mock_soar_api.py --host <mock-host-address> --port 8081
  1. From the Shuffle host, verify the service:
curl http://<mock-host-address>:8081/health
curl http://<mock-host-address>:8081/identity/lab-admin

Both requests must return JSON. The API stores state only in memory, refuses to block any address except 203.0.113.66, and resets when stopped.

Purpose Method and path Expected result
Identity GET /identity/lab-admin Training identity context
Case lookup GET /cases/CDK-SHUFFLE-001 404 before creation; the case after creation
Create or update POST /cases One case keyed by event_id
Notify POST /notify Accepted notification record
Block and verify POST /blocklist, then GET /blocklist/203.0.113.66 One expiring lab entry
Roll back DELETE /blocklist/203.0.113.66 Exact entry removed
Failure control POST /control/case-mode Case connector set to healthy, failed, or one-time fail_next_write

Starter alert

Save this as suspicious-login.json or send the same fields from your isolated alert source:

{
  "event_id": "CDK-SHUFFLE-001",
  "event_type": "suspicious_login",
  "user": "lab-admin",
  "source_ip": "203.0.113.66",
  "failed_attempts": 6,
  "successful_login": true,
  "confidence": 92,
  "environment": "training"
}

01

Activity 1 · Session 1: Prepare and verify

  1. Install Shuffle using the online or offline journey. Confirm its interface and workers are healthy before continuing.
  2. Record the repository revision, image tags, network boundary, permissions, and clean snapshot.
  3. Start the supplied mock API and verify its health and identity endpoints from the Shuffle host.
  4. Create Suspicious Login Response with a Webhook trigger. Copy its scoped URL into your notes; do not expose it publicly.
  5. Add one harmless HTTP action for GET /identity/lab-admin. Run it and inspect the returned user, role, and critical fields.
  6. Test block and unblock independently with 203.0.113.66. Verify the entry appears, then remove it and confirm blocked is false.
Milestone 1Safe foundation readyShuffle receives a webhook, reads identity context, and can add and remove only the reserved lab entry.

Expected result Shuffle and every required integration are healthy, least-privilege access is recorded, and the response can be safely reversed.

02

Activity 2 · Session 2: Build and approve

Build this visible node path. Use the HTTP action available in your installed Shuffle version and substitute your mock host address consistently:

1 Webhook2 Validate3 Enrich4 Case lookup5 Decide6 Approve7 Block & record
Node Input or request Check before continuing
Webhook Starter JSON All seven fields appear in execution data
Validate Required fields plus environment == training Missing fields and non-training data stop here
Enrich GET /identity/$user Returned identity belongs to the triggering user
Case lookup GET /cases/$event_id 404 selects create; an existing case selects update
Decide confidence >= 80 High confidence requests approval; lower confidence records only
Approve Shuffle approval or user-input action Rejection and timeout make no block request
Block POST /blocklist with IP, event ID, and expires_minutes: 10 Verification lookup returns one exact entry
Record POST /cases with evidence, approver, result, expiry, and rollback Case shows the final action and verification result
  1. Map event_id, event_type, user, source_ip, confidence, environment, and successful_login from the webhook body.
  2. Build and test each node in table order. Do not connect the Block node until Validate, Enrich, Case lookup, Decide, and Approve work independently.
  3. On the existing-case branch, update the matching case instead of creating a second record. This makes event_id the idempotency key.
  4. Configure approval using the approval or user-input capability available in your Shuffle version. Record the approver and ensure rejection or timeout follows the no-action branch.
  5. Send the starter alert, inspect every node result, approve the bounded response, and verify the case and blocklist directly through the mock API.
Milestone 2Approved workflow verifiedOne event produces one case and one ten-minute block only after approval; destination lookups confirm both outcomes.

Expected result The workflow pauses before containment, executes only after approval, records a time-bounded block, and preserves a complete audit trail.

03

Activity 3 · Session 3: Break and recover

Restore the working checkpoint from Activity 2 and confirm /health reports case_mode as healthy. Run and record this test matrix:

Test Change Safe expected result
Positive Use the complete starter alert with confidence 92 Approval is requested; one temporary block and one case record are created
Invalid input Remove source_ip Workflow stops before enrichment or response and records the validation error
Low confidence Set confidence to 12 Enrichment is recorded, but containment is not requested
Connector failure Disable the case endpoint after approval The completed block is not repeated; an owner is notified and the record step can be resumed
Duplicate delivery Send CDK-SHUFFLE-001 again The existing case is updated; no duplicate case or block is created
Rollback Run the exact-entry unblock action The address is absent from the blocklist and the recovery time is recorded

Use these controls for the failure and recovery tests:

# Fail the next case write once, after lookup and containment succeed
curl -X POST http://<mock-host-address>:8081/control/case-mode \
  -H "Content-Type: application/json" -d '{"mode":"fail_next_write"}'

# Restore the connector before resuming the Record step
curl -X POST http://<mock-host-address>:8081/control/case-mode \
  -H "Content-Type: application/json" -d '{"mode":"healthy"}'

# Inspect all destination state
curl http://<mock-host-address>:8081/state

Set fail_next_write before the connector-failure run. Case lookup remains healthy, Block succeeds, and the following case write fails once. Resume only the Record node; do not rerun Block. The separate notification endpoint remains available so an owner can still be notified.

Export the workflow and retain the execution history for all six tests. Do not claim success from a green workflow alone—verify the case, blocklist, expiry, notification, and rollback result in their destination systems.

Expected result The workflow remains observable and safe under success, invalid input, low confidence, partial failure, duplicate delivery, and rollback.

Milestone 3Failure handled safelyAll six tests have destination evidence, duplicate delivery causes no repeated impact, and rollback removes the exact entry.

Full Lab evidence checklist

This checklist applies to the VM-based Full Lab. If you completed the Interactive Lab, retain its downloaded evidence summary instead.

0 of 6 recorded Mark each item after saving the evidence.

Clean up

Delete the exact lab block first, then reset and stop the mock API:

curl -X DELETE http://<mock-host-address>:8081/blocklist/203.0.113.66
curl -X POST http://<mock-host-address>:8081/reset

Stop the webhook, revoke temporary credentials, and revert the training systems to their clean recovery points. Retain the exported workflow, test matrix, execution histories, and conclusion as your lab record.