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.
Shuffle Full Lab
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.
Recommended first
Guided Core Lab¶
Use the supplied synthetic alert and local mock API. This route teaches the SOAR workflow without requiring external product accounts.
Expected time: 4–6 hours across three sessions.
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.
- Session 1 · Activity 1Prepare and verify
- Session 2 · Activity 2Build and approve
- 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:
- Activity 1 — Prepare and verify: establish a safe, working foundation.
- Activity 2 — Build and approve: create and validate the response playbook.
- 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¶
- Download the lab-only mock API to a host reachable from the Shuffle worker.
- On an isolated lab network, replace
<mock-host-address>with that host's lab address and run:
- From the Shuffle host, verify the service:
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¶
- Install Shuffle using the online or offline journey. Confirm its interface and workers are healthy before continuing.
- Record the repository revision, image tags, network boundary, permissions, and clean snapshot.
- Start the supplied mock API and verify its health and identity endpoints from the Shuffle host.
- Create
Suspicious Login Responsewith a Webhook trigger. Copy its scoped URL into your notes; do not expose it publicly. - Add one harmless HTTP action for
GET /identity/lab-admin. Run it and inspect the returneduser,role, andcriticalfields. - Test block and unblock independently with
203.0.113.66. Verify the entry appears, then remove it and confirmblockedisfalse.
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:
| 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 |
- Map
event_id,event_type,user,source_ip,confidence,environment, andsuccessful_loginfrom the webhook body. - Build and test each node in table order. Do not connect the Block node until Validate, Enrich, Case lookup, Decide, and Approve work independently.
- On the existing-case branch, update the matching case instead of creating a
second record. This makes
event_idthe idempotency key. - 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.
- Send the starter alert, inspect every node result, approve the bounded response, and verify the case and blocklist directly through the mock API.
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.
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.
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.