diff --git a/README.md b/README.md index 5ce8353..6b5afbb 100644 --- a/README.md +++ b/README.md @@ -1,121 +1,131 @@ -# SimRun +

+ SimRun +

-SimRun is an **Attack Simulation Platform (ASP)** for detection testing. It **detonates** -attack simulations and verifies that the security alerts you expect fire in your SIEM -(currently only Elastic Security is supported). +

SimRun

-It ships as a single Go binary serving a REST API + WebSocket interface backed by -PostgreSQL, with an embedded SvelteKit frontend. +

+ An Attack Simulation Platform for detection engineering.
+ Detonate attacks, verify the alerts fire, and measure exactly which detections you're testing โ€” across multiple clouds. +

-## Getting Started +

+ License + Release + Go + Docker +

-### Prerequisites +--- -- [mise](https://mise.jdx.dev/) โ€” manages the Go 1.25 and Node 22 toolchains (or install them yourself) -- PostgreSQL +## Why SimRun -### Build +Detection rules rot silently. A field gets renamed, a log source drifts, an index mapping changes โ€” and the alert you were counting on simply stops firing. You don't find out until the breach. -```bash -mise build # builds the SvelteKit frontend and the simrun binary into dist/simrun -``` +SimRun closes that gap. It runs real attack techniques against your environment, confirms the detections you expect actually fire in your SIEM, and tracks **which of your rules are tested and which are blind spots**. -### Run +It's not a script you wire into CI and forget. It's a platform: -simrun requires a PostgreSQL database; schema migrations run automatically on startup. +- **๐ŸŽฏ Coverage you can see.** SimRun joins your live Elastic detection rules against your scenarios and their latest pass/fail result, then reports a coverage percentage. You learn what you *aren't* testing โ€” not just whether one test passed. โ†’ [Rule Coverage](#rule-coverage) +- **โ˜๏ธ Multiple clouds, multiple accounts.** First-class connectors for AWS, GCP, Azure, and Kubernetes, each backed by managed, encrypted secret groups and selectable per scenario. +- **๐Ÿงช Three ways to exercise a detection.** **Detonate** a real attack, **inject** a crafted log to confirm a rule is wired up without touching infrastructure, or **collect** the raw logs an attack produced to build the next rule. +- **๐Ÿ“ฆ A pack ecosystem.** Simulations ship as versioned, shareable bundles with a clean Go SDK. Use the first-party packs, wrap [Stratus Red Team](https://github.com/DataDog/stratus-red-team), or author your own. โ†’ [Ecosystem](docs/ecosystem.md) +- **๐Ÿ–ฅ๏ธ Built to operate.** Web UI, REST API, and WebSocket interface; PostgreSQL persistence; scheduled runs; optional multi-user OAuth. It all ships as a single Go binary with the SvelteKit UI embedded. -```bash -export SR_DATABASE_URL="postgres://user:pass@localhost:5432/simrun?sslmode=disable" -./dist/simrun -``` +> SimRun is **primarily focused on Elastic Security** โ€” that's where coverage analysis, injection, and log collection are richest. Datadog security signals are supported as a matching backend. -The UI and API are then served on http://localhost:8080. +## How it works -> Authentication is optional. Without `SR_GOOGLE_CLIENT_ID`/`SR_GOOGLE_CLIENT_SECRET`, -> login is disabled and the app runs unauthenticated +An **Assessment** is a saved set of **scenarios**. Running it creates a **Run**, which executes every scenario in parallel. Each scenario triggers some activity and then asserts that an expected alert appears in your SIEM before a timeout. -## Configuration +```mermaid +flowchart LR + A[Assessment
scenarios] -->|run| B(Run) + B --> S1[Scenario 1] + B --> S2[Scenario 2] + B --> S3[Scenario N] + S1 --> D{Trigger} + D -->|detonate| E[Real attack
from SimRun pack] + D -->|inject| F[Crafted log
into Elasticsearch] + E --> M[Matcher polls SIEM
until alert fires or timeout] + F --> M + M --> R[(Results + Coverage
Postgres)] + E -.optional.-> C[Collector
gathers related logs] + C --> R +``` -Deploy-time configuration is read from environment variables โ€” the only `SR_*` env -surface. Everything else (connectors, secrets, packs, schedules, scenarios, app -defaults) lives in the database and is managed through the web UI. +Every detonation gets a UUID that SimRun reflects into the generated activity wherever possible (user-agent strings), so an alert maps unambiguously back to the exact attack that caused it. -| Variable | Required | Default | Description | -|---|---|---|---| -| `SR_DATABASE_URL` | yes | โ€” | PostgreSQL connection string | -| `SR_WEB_PORT` | no | `8080` | HTTP listen port | -| `SR_DATA_DIR` | no | `~/.simrun` | Local data dir (encryption key, SSH logs) | -| `SR_ENCRYPTION_KEY_FILE` | no | `$SR_DATA_DIR/encryption.key` | Key file for encrypting stored secrets | -| `SR_DEBUG` | no | off | Verbose logging when set to a non-zero value | -| `SR_WEB_URL` | no | โ€” | External base URL (used for OAuth redirects) | -| `SR_GOOGLE_CLIENT_ID` / `SR_GOOGLE_CLIENT_SECRET` | no | โ€” | Google OAuth credentials (enables login) | -| `SR_GOOGLE_ALLOWED_DOMAIN` | no | โ€” | Restrict OAuth login to a Google Workspace domain | -| `SR_AUTH_SESSION_TTL_HOURS` | no | `168` | Session lifetime in hours | +โ†’ Full vocabulary in [Concepts](docs/concepts.md). -### Run with Docker +## A scenario, end to end -```bash -docker build -t simrun . -docker run -p 8080:8080 \ - -e SR_DATABASE_URL="postgres://..." \ - -v simrun-data:/home/nonroot/.simrun \ - simrun +Build scenarios visually in the assessment editor, or write the YAML directly โ€” the editor toggles between a forms-based **Builder** and raw **YAML**. This scenario detonates a pack simulation in AWS and asserts the matching Elastic Security rule fires: + +```yaml +targets: + aws: prod-aws # an AWS connector you configured in the UI + +scenarios: + - name: S3 public access block disabled + detonate: + simrunDetonator: + pack: simrun-base-pack + simulation: aws.s3-disable-public-access-block + expectations: + - timeout: 5m + elasticSecurityAlert: + name: "S3 Public Access Block Disabled" ``` -The image bundles the `aws`, `gcloud`, and `az` CLIs used by detonators. Persist -`SR_DATA_DIR` (the volume above) so the secret-encryption key survives restarts. +Swap `detonate` for `inject` to test a rule without running an attack, or add a `collect` block to capture the raw logs the attack produced. -## Architecture +โ†’ [Scenarios reference](docs/scenarios.md). -A single Go binary handles: -- Simulation detonation and orchestration -- Alert matching and verification -- Log collection from security platforms -- Scenario parsing and execution +## Quickstart (60 seconds) -### Simulation Packs +**Prerequisites:** [mise](https://mise.jdx.dev/) (manages Go 1.25 and Node 22), PostgreSQL. -Simulations are distributed as external packs, installed and managed via the web UI: +```bash +# Build the frontend + binary โ†’ dist/simrun +mise run build -- simrun-base-pack โ€” custom simulations (AWS, Azure, GCP) -- simrun-stratus-pack โ€” [Stratus Red Team](https://github.com/DataDog/stratus-red-team) simulations +# Point it at Postgres and run +export SR_DATABASE_URL="postgres://user:pass@localhost:5432/simrun?sslmode=disable" +./dist/simrun # serves UI + API on http://localhost:8080 +``` + +Schema migrations run automatically on startup. Authentication is optional โ€” without Google OAuth credentials, SimRun runs unauthenticated. + +โ†’ Then follow the [Walkthrough](docs/walkthrough.md) to run your first detection test. + +## Rule Coverage -## Concepts +The Coverage view (`/rules/coverage`) pulls every detection rule from your Elastic deployment and answers the question CI never could: **which of these rules does a SimRun scenario actually exercise, and did it pass last time?** Rules with no scenario are flagged as blind spots; the summary reports an overall covered-rules percentage. -### Detonators -A **detonator** describes how and where an attack technique is executed. -* Simrun detonator โ€” runs a simulation pack (Terraform-based; packs can themselves - execute locally or over SSH) -* AWS CLI detonator โ€” runs AWS CLI commands +## The pack ecosystem -### Injectors -An **injector** is an alternative to detonators: instead of executing the end-to-end -attack it takes a generated log message and injects it directly into the SIEM. This -covers cases where end-to-end simulation isn't feasible but you still want to confirm -the detection is operational. -* Elastic Injector +Simulations are distributed as **packs** โ€” versioned bundles of Terraform modules, scenario definitions, and a manifest. Two first-party packs are maintained alongside SimRun: -### Alert Matchers -An **alert matcher** is a platform-specific integration that checks whether an expected -alert was triggered. -* Elastic Security alerts -* Datadog security signals +| Pack | What it is | +|---|---| +| [**simrun-pack**](https://github.com/confluentinc/simrun-pack) | The reference pack and a worked example of authoring simulations in Go (AWS, Kubernetes, Okta injections). | +| [**simrun-stratus-adapter**](https://github.com/confluentinc/simrun-stratus-adapter) | Plug-and-play wrapper that exposes the entire [Stratus Red Team](https://github.com/DataDog/stratus-red-team) technique registry as a SimRun pack. | -### Collectors -A **collector** retrieves logs from security platforms after detonation for analysis and -rule generation. -* Elastic Collector โ€” collects related logs from Elasticsearch by execution ID or - user-agent correlation -### Detonation and Alert Correlation -Each detonation is assigned a UUID, reflected in the detonation where possible and used -to ensure the matched alert corresponds exactly to that detonation. If the detonator -cannot reflect the UUID, the matcher can correlate using indicators the user provides -(static indicators) or terraform output (dynamic indicators). +โ†’ [Ecosystem & authoring guide](docs/ecosystem.md). -### Simulations -A **simulation** is a reusable module describing how to perform a specific attack. -Simulations are distributed as [packs](#simulation-packs) and installed via the web UI. +## Documentation + +- [Getting Started](docs/getting-started.md) โ€” prerequisites, build, first run +- [Concepts](docs/concepts.md) โ€” assessments, runs, detonators, matchers, collectors +- [Walkthrough](docs/walkthrough.md) โ€” end-to-end tutorial +- [Scenarios](docs/scenarios.md) โ€” YAML schema reference +- [Connectors & Secrets](docs/connectors-and-secrets.md) โ€” SIEM and cloud integrations +- [Packs](docs/packs.md) โ€” install and configure simulation packs +- [Ecosystem](docs/ecosystem.md) โ€” the pack ecosystem and writing your own +- [Configuration](docs/configuration.md) โ€” environment variables reference +- [Deployment](docs/deployment.md) โ€” Docker, production notes, OAuth setup ## Development @@ -127,6 +137,13 @@ go generate ./... # regenerate mocks (mockery) mise run parser # regenerate parser from JSON schemas ``` +## Acknowledgments + +SimRun stands on excellent prior work in the detection-engineering community: + +- [**Threatest**](https://github.com/DataDog/threatest) by Datadog pioneered the detonate-and-verify model for detection testing and shaped how we think about correlating attacks to alerts. +- [**Stratus Red Team**](https://github.com/DataDog/stratus-red-team), also by Datadog, provides the MITRE ATT&CKโ€“mapped cloud attack techniques that SimRun exposes through [simrun-stratus-adapter](https://github.com/confluentinc/simrun-stratus-adapter). + ## Contributing Issues and pull requests are welcome. diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 0000000..4629a29 --- /dev/null +++ b/docs/README.md @@ -0,0 +1,29 @@ +# SimRun Documentation + +Learn how to set up, configure, and run detection tests against your SIEM. + +## Suggested Reading Order + +Start with **Getting Started** to install SimRun, then read **Concepts** to understand the vocabulary. Follow with the **Walkthrough** to execute your first test, then dive into the reference docs as needed. + +--- + +## Documentation Index + +- **[Getting Started](getting-started.md)** โ€” Install SimRun and reach the dashboard. + +- **[Concepts](concepts.md)** โ€” Vocabulary and core components: assessments, runs, scenarios, detonators, matchers, and injectors. + +- **[Walkthrough](walkthrough.md)** โ€” Step-by-step guide to your first detection test with AWS and Elastic Security. + +- **[Scenarios YAML Reference](scenarios.md)** โ€” Complete reference for the YAML format that defines assessments and scenarios. + +- **[Connectors and Secrets](connectors-and-secrets.md)** โ€” Configure endpoints and store credentials for your SIEM and cloud platforms. + +- **[Packs](packs.md)** โ€” Install and manage external attack simulation bundles and tune their parameters. + +- **[Ecosystem](ecosystem.md)** โ€” The pack ecosystem, the maintained satellite packs, and how to write your own. + +- **[Configuration](configuration.md)** โ€” All deploy-time environment variables and operational defaults. + +- **[Deployment](deployment.md)** โ€” Run SimRun in production with Docker and optional Google OAuth. diff --git a/docs/assets/simrun-icon-rounded.png b/docs/assets/simrun-icon-rounded.png new file mode 100644 index 0000000..f8eddf6 Binary files /dev/null and b/docs/assets/simrun-icon-rounded.png differ diff --git a/docs/assets/simrun-icon.png b/docs/assets/simrun-icon.png new file mode 100644 index 0000000..e0a3472 Binary files /dev/null and b/docs/assets/simrun-icon.png differ diff --git a/docs/concepts.md b/docs/concepts.md new file mode 100644 index 0000000..b27767c --- /dev/null +++ b/docs/concepts.md @@ -0,0 +1,66 @@ +# Concepts + +An **Assessment** defines scenarios. Running it creates a **Run**. The run **executes each scenario** (in parallel, like jobs), and each scenario checks its **expectations** via **matchers**. + +## Vocabulary + +**Assessment** +: A saved collection of scenarios that describes what to detonate and what alerts to expect. Managed on the Assessments page (`/assessments`). + +**Run** +: A single execution of an Assessment. Persists results to the database and is viewable on the Runs page (`/runs`). + +**Scenario** +: One unit of work inside an Assessment: a detonation or injection step, plus one or more expectations. Scenarios in a run execute in parallel. + +**Expectation** +: A declared assertion that a specific alert or signal must appear in the target platform after detonation. Expectations are defined per-scenario in the YAML file. + +**Matcher** +: The component that checks whether an expectation was satisfied by polling the target platform until the alert appears or the timeout expires. + +## Detonators + +Detonators execute the attack simulation. + +**SimRun detonator** โ€” runs a pack simulation using Terraform. The pack can execute locally (on the SimRun host) or over SSH on a remote target. This is the primary detonation method and requires a pack to be installed. + +## Injectors + +Injectors skip the attack execution and push a document directly into the SIEM. + +**Elastic Injector** โ€” writes a log document into Elasticsearch. Use this to confirm that a detection rule is operational without actually running an attack: if the matcher finds the expected alert after injection, the rule is wired up correctly. + +## Matchers + +Matchers verify that an expectation fired after detonation or injection. + +**Elastic Security alert matcher** โ€” polls Kibana for a Detection Engine alert whose `kibana.alert.rule.name` matches the expected rule name. + +## Collectors + +Collectors retrieve related logs after detonation for post-hoc analysis and rule development. + +**Elastic Collector** โ€” queries Elasticsearch for log events correlated to the detonation, either by the execution UUID (when it was reflected into the activity) or by a user-agent string. The collected logs are stored with the run result and can be used to understand what raw data a detection rule would have to match. + +## Correlation + +Every detonation is assigned a UUID (nanoid) at execution time. Where possible, SimRun reflects that UUID into the generated activity by injecting it into the user-agent string โ€” so that the resulting alert maps unambiguously to exactly one detonation event. + +When the UUID cannot be reflected into the activity (for example, in a managed AWS API call), SimRun uses **indicators** for correlation: + +- `static` โ€” a fixed string you provide (e.g. a known username or resource name) that will appear in the alert or log. +- `terraformOutput` โ€” a value extracted dynamically from a Terraform output after the simulation completes (e.g. a generated resource ARN). + +## Packs, Connectors, Secrets + +**Packs** distribute simulations as versioned bundles. A pack contains Terraform modules, scenario definitions, and a manifest. Install packs from the UI and reference them by name in your scenario YAML. See [packs.md](packs.md) for installation and configuration. + +**Connectors** point SimRun at an external platform โ€” Elastic, AWS, GCP, Azure, Kubernetes, or SSH. Each connector stores the endpoint and non-secret configuration needed to reach that platform. Connectors are managed on the Connectors page (`/connectors`). See [connectors-and-secrets.md](connectors-and-secrets.md) for setup. + +**Secret groups** hold the credentials (API keys, passwords, certificates) that a connector uses. A connector links to at most one secret group. Secrets are managed on the Secrets page (`/secrets`) and are never returned in plaintext after saving. + +## See also + +- [walkthrough.md](walkthrough.md) โ€” run your first detection test end to end +- [scenarios.md](scenarios.md) โ€” full YAML reference for scenario files diff --git a/docs/configuration.md b/docs/configuration.md new file mode 100644 index 0000000..7490850 --- /dev/null +++ b/docs/configuration.md @@ -0,0 +1,40 @@ +# Configuration + +Every deploy-time setting SimRun reads. + +## Overview + +Deploy-time configuration is environment-only. The `SR_*` environment variables below are the only settings SimRun reads at startup. Everything else โ€” connectors, secrets, packs, schedules, assessments, and app-level operational defaults โ€” lives in the database and is managed through the UI. + +## Environment variables + +| Variable | Required | Default | Description | +|---|---|---|---| +| `SR_DATABASE_URL` | yes | โ€” | PostgreSQL connection string | +| `SR_WEB_PORT` | no | `8080` | HTTP listen port | +| `SR_DATA_DIR` | no | `~/.simrun` | Local data dir (encryption key, SSH logs) | +| `SR_ENCRYPTION_KEY_FILE` | no | `$SR_DATA_DIR/encryption.key` | Key file for encrypting stored secrets | +| `SR_DEBUG` | no | off | Verbose logging when set to a non-zero/non-`false` value | +| `SR_WEB_DEV` | no | off | Dev mode when set to `1` | +| `SR_WEB_URL` | no | โ€” | External base URL (used for OAuth redirects) | +| `SR_GOOGLE_CLIENT_ID` / `SR_GOOGLE_CLIENT_SECRET` | no | โ€” | Google OAuth credentials (enables login) | +| `SR_GOOGLE_ALLOWED_DOMAIN` | no | โ€” | Restrict OAuth login to a Google Workspace domain | +| `SR_AUTH_SESSION_TTL_HOURS` | no | `168` | Session lifetime in hours | + +## App config defaults + +Operational defaults that admins tune through the UI at `/config`. These are stored in the database (the `app_config` table) and take effect without a restart. + +Confirmed fields include: + +- **Parallelism** (default `5`) โ€” number of scenarios that run concurrently within a single run. +- **Terraform version** โ€” pin the Terraform binary version used by pack detonations. +- **Pack logs** โ€” toggle capture of Terraform output in run logs (enabled by default). +- **SSH logging** โ€” toggle SSH session logging (disabled by default). +- **Run log retention** โ€” automatically purge run logs after a configurable number of days (default 7 days, enabled by default). +- **Run retention** โ€” automatically purge run records after a configurable number of days (default 30 days, disabled by default). + +## See also + +- [deployment.md](deployment.md) โ€” production deploy checklist, OAuth setup, Docker +- [getting-started.md](getting-started.md) โ€” build SimRun and reach the dashboard for the first time diff --git a/docs/connectors-and-secrets.md b/docs/connectors-and-secrets.md new file mode 100644 index 0000000..c1cb656 --- /dev/null +++ b/docs/connectors-and-secrets.md @@ -0,0 +1,122 @@ +# Connectors and Secrets + +Point SimRun at your platforms and store the credentials securely. + +## Connectors vs secret groups + +A **connector** (`/connectors`) stores the endpoint and non-secret configuration needed to reach a target platform โ€” for example, a Kibana URL or an AWS role ARN. Connector records are stored in the database and are referenced by name in scenario targets and run defaults. + +A **secret group** (`/secrets`) holds the credentials (API keys, passwords, private keys) that a connector uses. A connector links to at most one secret group. Secrets are encrypted at rest using the key in `SR_DATA_DIR` (default `~/.simrun`). See [configuration.md](configuration.md) for how `SR_DATA_DIR` is set. + +The split keeps non-sensitive config โ€” URLs, region names, cluster identifiers โ€” visible in the UI while keeping credentials out of plain sight. Secret values are never returned in plaintext after saving. + +## SIEM connectors + +### Elastic + +The `elastic` connector type points SimRun at an Elastic Security deployment. It is the primary SIEM: the Elastic Security alert matcher polls Kibana for detection alerts, and the Elastic Injector writes documents into Elasticsearch. + +**Config fields (confirmed in `connector_handlers.go`):** + +| Field | Required | Description | +|---|---|---| +| `kibana_url` | Yes | Base URL of your Kibana instance (e.g. `https://kibana.example.com`). | +| `cloud_id` | No | Elastic Cloud ID. Alternative to explicit URLs for Elastic Cloud deployments. | +| `elasticsearch_url` | No | Explicit Elasticsearch URL when not derived from `cloud_id`. | +| `export_enabled` | No | When `true`, run results are exported to Elasticsearch after completion. | +| `export_datastream` | No | Data stream name for result export. | + +**Secret group:** Link a secret group that contains `SR_ELASTIC_API_KEY` (the Elasticsearch API key used for all Kibana and Elasticsearch calls). + +When no target overrides are specified, SimRun uses the first enabled Elastic connector as the active SIEM connection. + + +## Cloud connectors + +Cloud connectors supply credentials to detonators that execute attack simulations in cloud environments. They are referenced from a scenario's `targets` block by connector name. + +### AWS + +The `aws` connector resolves credentials for the AWS CLI detonator and Terraform-based simulations that target AWS. + +**Config fields:** + +| Field | Description | +|---|---| +| `role_arn` | IAM role ARN to assume before running the simulation. When set, SimRun calls `sts:AssumeRole` and passes the resulting temporary credentials to the subprocess. | + +**Secret group:** Optionally store `SR_AWS_EXTERNAL_ID` (the external ID required when assuming the role) and any additional AWS credential env vars (`AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, etc.) for static-key auth. + +### GCP + +The `gcp` connector resolves credentials for Terraform simulations that target GCP. + +**Config fields:** + +| Field | Description | +|---|---| +| `auth_type` | Set to `workload_identity_federation` for WIF auth, or leave empty for legacy service account auth. | +| `project_id` | GCP project ID, injected as `GOOGLE_CLOUD_PROJECT`. | +| `project_number` | GCP project number (WIF only). | +| `pool_id` | Workload Identity Pool ID (WIF only). | +| `provider_id` | Workload Identity Provider ID (WIF only). | +| `service_account_email` | Target service account to impersonate (WIF only). | +| `credentials_file` | Path to a service account JSON file (legacy auth only). | + +**Secret group:** For legacy auth, store `SR_GCP_CREDENTIALS` (inline service account JSON). + +### Azure + +The `azure` connector resolves credentials for Terraform simulations that target Azure. + +**Config fields:** + +| Field | Description | +|---|---| +| `auth_type` | Set to `workload_identity_federation` for WIF auth, or leave empty for legacy service principal auth. | +| `tenant_id` | Azure AD tenant ID. | +| `subscription_id` | Azure subscription ID. | +| `client_id` | Azure AD application (client) ID. | +| `token_file` | OIDC token file path (WIF only; defaults to the EKS IRSA path). | + +**Secret group:** For legacy auth, store `ARM_CLIENT_SECRET` (the service principal client secret). + +## Other connectors + +### Kubernetes + +The `kubernetes` connector resolves a kubeconfig for simulations that run Kubernetes-native attack steps. The cloud provider (EKS, GKE, AKS) is auto-detected from the referenced cloud connector type. + +**Config fields (all required):** + +| Field | Description | +|---|---| +| `cluster_name` | Name of the target cluster. | +| `region` | Cloud region where the cluster is deployed. | +| `cloud_connector` | Name of the AWS, GCP, or Azure connector that provides cloud credentials for fetching the kubeconfig. | +| `resource_group` | Azure resource group (AKS only). | +| `project` | GCP project ID (GKE only; falls back to the linked GCP connector's `project_id`). | + +`cluster_name`, `region`, and `cloud_connector` are required. The Kubernetes connector does not have a dedicated secret group; it inherits credentials from the referenced cloud connector. + +### SSH + +The `ssh` connector is used by the SimRun detonator to execute Terraform simulations on a remote host over SSH. + +> โš ๏ธ **Not yet in the UI.** The SSH connector is hidden from the connector picker while its consumption path is finalised, so it can't be created from the Connectors page yet. SSH-based detonation isn't configurable through the UI in the meantime. + +**Config fields:** + +| Field | Required | Description | +|---|---|---| +| `host` | Yes | Hostname or IP address of the remote target. | +| `username` | Yes | SSH username. | +| `port` | No | SSH port (default: 22). | + +**Secret group:** Store `SR_SSH_KEY` (the PEM-encoded private key). The key is written to a temporary file and passed to the SSH client at runtime. + +## See also + +- [walkthrough.md](walkthrough.md) โ€” end-to-end example including connector setup +- [packs.md](packs.md) โ€” install and configure simulation packs +- [scenarios.md](scenarios.md) โ€” reference connector names in scenario targets diff --git a/docs/deployment.md b/docs/deployment.md new file mode 100644 index 0000000..bae9041 --- /dev/null +++ b/docs/deployment.md @@ -0,0 +1,48 @@ +# Deployment + +Run SimRun in production with Docker and optional auth. + +## Docker + +Pull the image or build it from the repository root: + +```bash +docker pull ghcr.io/ibm/simrun:latest +``` + +Run the container, mounting a volume so state persists across restarts: + +```bash +docker run -p 8080:8080 \ + -e SR_DATABASE_URL="postgres://..." \ + -v simrun-data:/home/nonroot/.simrun \ + ghcr.io/ibm/simrun +``` + +The image bundles `aws`, `gcloud`, and `az` CLIs โ€” the tools used by detonators when executing cloud attack simulations. + +The volume mounted at `/home/nonroot/.simrun` is the default `SR_DATA_DIR`. It stores the secret-encryption key. If the key is lost, stored connector credentials become unreadable. + +## Authentication (Google OAuth) + +By default, SimRun runs without authentication. To enable login: + +| Variable | Description | +|---|---| +| `SR_GOOGLE_CLIENT_ID` / `SR_GOOGLE_CLIENT_SECRET` | Google OAuth credentials โ€” setting both enables login | +| `SR_WEB_URL` | External base URL used to construct the OAuth redirect URI (e.g. `https://simrun.example.com`) | +| `SR_GOOGLE_ALLOWED_DOMAIN` | Restrict login to a single Google Workspace domain (e.g. `example.com`) | +| `SR_AUTH_SESSION_TTL_HOURS` | Session lifetime in hours (default `168`, i.e. 7 days) | + +See [configuration.md](configuration.md) for the full list of environment variables. + +## Data persistence + +The encryption key written to `SR_DATA_DIR` protects all secrets stored in the database (connector credentials, secret group values). If the data directory is not persisted โ€” for example, because a container restarts without a volume โ€” the key is regenerated and previously stored secrets become unreadable. + +Always mount `SR_DATA_DIR` to durable storage in production. + +## See also + +- [configuration.md](configuration.md) โ€” all environment variables and app config defaults +- [getting-started.md](getting-started.md) โ€” build SimRun and reach the dashboard for the first time diff --git a/docs/ecosystem.md b/docs/ecosystem.md new file mode 100644 index 0000000..53fe22d --- /dev/null +++ b/docs/ecosystem.md @@ -0,0 +1,175 @@ +# Ecosystem & Writing Packs + +SimRun's simulations live outside the core binary, in **packs**. This keeps the platform stable while the catalogue of attack techniques grows independently โ€” maintained by us, by the community, or by you for your own environment. + +This page covers the maintained satellite projects and how to author a pack of your own. For installing and configuring packs from the UI, see [packs.md](packs.md). + +## The satellite projects + +### simrun-pack โ€” the reference pack + +[**confluentinc/simrun-pack**](https://github.com/confluentinc/simrun-pack) is the first-party `simrun-base-pack` and doubles as the canonical example of how a pack is written. It ships real simulations across AWS and Kubernetes, plus an Okta log injection, organised by MITRE tactic: + +``` +simulations/ + aws/ + credential-access/credential-scanner-tools/ main.tf + simulation.go + discovery/s3-list-objects/ main.tf + simulation.go + k8s/ + credential-access/eks-web-identity-token-theft/ + privilege-escalation/create-clusterrolebinding/ + shared/ reusable Go helpers +injections/ + okta/api-token-create/ injection.go + injection.tpl +main.go registers everything +``` + +Each simulation is a directory with a Terraform module (`main.tf`) that stands up the infrastructure and a Go file (`simulation.go`) that registers the simulation and runs the detonation. Read it as a template for the patterns below. + +### simrun-stratus-adapter โ€” plug-and-play Stratus Red Team + +[**confluentinc/simrun-stratus-adapter**](https://github.com/confluentinc/simrun-stratus-adapter) exposes the entire [Stratus Red Team](https://github.com/DataDog/stratus-red-team) attack-technique registry as a single SimRun pack. Rather than re-implementing techniques, it adapts each one โ€” preserving its MITRE ATT&CK mapping โ€” into the SimRun pack format. Its `main()` is essentially: + +```go +func main() { + pack.SetPackInfo("stratus", Version, "3.0.0") + + for _, technique := range stratus.GetRegistry().ListAttackTechniques() { + pack.Register(adapter.AdaptTechnique(technique)) + } + + pack.Run() +} +``` + +Install it like any other pack to get Stratus's cloud attack coverage in SimRun with no per-technique work. + +## Writing your own pack + +A pack is a small Go program built against the [`github.com/IBM/simrun/pack`](https://github.com/IBM/simrun/tree/main/pack) SDK. At a high level you: + +1. Register one or more simulations (and any log-injection templates). +2. Declare the pack's name, version, and the minimum SimRun version it needs. +3. Declare any pack-level parameters. +4. Call `pack.Run()`. + +### The entrypoint + +`main.go` wires the pack together. Importing each simulation package for its side effect (`_ "..."`) triggers the `init()` that registers it: + +```go +package main + +import ( + "github.com/IBM/simrun/pack" + + _ "github.com/your-org/your-pack/simulations/aws/discovery/s3-list-objects" + // ...more simulations +) + +// Version is set via ldflags at build time. +var Version = "dev" + +func main() { + pack.SetPackInfo("your-pack", Version, "0.4.0") // name, version, min SimRun version + + pack.RegisterPackParams( + pack.PackParam{ + Name: "resource_prefix", + Type: pack.PackParamTypeString, + Description: "Prefix applied to every resource the pack creates.", + Default: "simrun", + }, + ) + + pack.Run() +} +``` + +Pack-level parameters appear on the Packs page once installed and are passed to every simulation's Terraform. The SDK always provides the built-in parameters (`default_tags`, `aws_region`, `gcp_region`, `azure_location`) โ€” declare only the extras you need. See [packs.md](packs.md#pack-parameters) for precedence rules. + +### A simulation + +Each simulation embeds its Terraform module and registers itself in `init()`: + +```go +package simulations + +import ( + "context" + _ "embed" + + "github.com/IBM/simrun/pack" + packaws "github.com/IBM/simrun/pack/aws" + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/s3" +) + +//go:embed main.tf +var terraform string + +func init() { + pack.Register(pack.Simulation{ + ID: "s3-list-objects", + Name: "S3 Bucket Object Listing", + Description: "Lists objects in an S3 bucket to simulate cloud storage discovery.", + MITRE: pack.MITREMapping{Tactics: []string{"TA0007"}, Techniques: []string{"T1619"}}, + Scope: "aws", + Terraform: terraform, + Detonate: Detonate, + }) +} + +// Detonate runs the attack after Terraform has applied the warm-up infrastructure. +func Detonate(ctx context.Context, input pack.DetonateInput) (*pack.Result, error) { + log := pack.Logger(input) + + cfg, err := packaws.AWSConfig(ctx) + if err != nil { + return nil, err + } + + bucketName := input.TerraformOutputs["bucket_name"] + + s3Client := s3.NewFromConfig(cfg) + if _, err := s3Client.ListObjectsV2(ctx, &s3.ListObjectsV2Input{ + Bucket: aws.String(bucketName), + }); err != nil { + return pack.ErrorResult(pack.ErrCodeInternalError, "failed to list objects: "+err.Error()), nil + } + + return pack.SuccessResult(map[string]any{"bucket_name": bucketName}), nil +} +``` + +The flow at run time: + +1. SimRun applies the simulation's `main.tf` โ€” the **warm-up** that creates the infrastructure the attack needs. +2. Terraform outputs are handed to `Detonate` via `input.TerraformOutputs`. +3. `Detonate` performs the attack and returns a `Result`. Indicators returned in a `SuccessResult` are surfaced for log correlation; SimRun then tears the infrastructure back down. + +### The SDK surface + +| Function | Purpose | +|---|---| +| `pack.SetPackInfo(name, version, minSimrun)` | Identify the pack and the minimum SimRun version it requires. | +| `pack.RegisterPackParams(...PackParam)` | Declare pack-level parameters beyond the built-ins. | +| `pack.Register(Simulation)` | Register a simulation (call from the package's `init()`). | +| `pack.RegisterTemplate(Template)` | Register a log-injection template (for `inject` scenarios). | +| `pack.Run()` | Hand control to the SDK โ€” must be the last call in `main()`. | +| `pack.SuccessResult(indicators)` / `pack.ErrorResult(code, msg)` | Build the `Result` a `Detonate` returns. | +| `pack.Logger(input)` | Structured logger whose output is captured in the run logs. | + +Cloud credential helpers live in `pack/aws`, `pack/gcp`, and `pack/azure`; SSH execution helpers in `pack/ssh`. The credentials come from the connector named in the scenario's `targets` block. + +### Building and distributing + +Packs are compiled binaries. Both reference repos use [GoReleaser](https://goreleaser.com/) driven from CI to cut versioned releases, injecting `Version` via `ldflags`. To install a published pack, point the Packs page at its source. + +While developing, you don't need to publish at all: `go build` your pack and install the binary directly through the Packs page's **Upload** tab. That tightens the author โ†’ install โ†’ test loop to seconds and lets you run packs that never leave your environment. See [packs.md](packs.md#installing-a-pack) for both methods. + +## See also + +- [packs.md](packs.md) โ€” installing and configuring packs from the UI +- [scenarios.md](scenarios.md) โ€” referencing pack simulations and templates in scenario YAML +- [concepts.md](concepts.md) โ€” where packs sit in the overall model diff --git a/docs/getting-started.md b/docs/getting-started.md new file mode 100644 index 0000000..be995cb --- /dev/null +++ b/docs/getting-started.md @@ -0,0 +1,39 @@ +# Getting Started + +Install SimRun and reach the dashboard. + +## Prerequisites + +- **[mise](https://mise.jdx.dev/)** โ€” manages Go 1.25 and Node 22 automatically. Alternatively, install Go 1.25 and Node 22 yourself. +- **PostgreSQL** โ€” a running instance accessible from the host where SimRun will run. + +## Build + +Clone the repository, then run: + +```bash +mise run build +``` + +This builds the SvelteKit frontend and compiles the `simrun` binary, placing it at `dist/simrun`. + +## Run + +Database migrations run automatically on startup. Set the database URL and start the server: + +```bash +export SR_DATABASE_URL="postgres://user:pass@localhost:5432/simrun?sslmode=disable" +./dist/simrun +``` + +The UI and API are served on http://localhost:8080. + +## Authentication is optional + +Without `SR_GOOGLE_CLIENT_ID` and `SR_GOOGLE_CLIENT_SECRET` set, login is disabled and the app runs unauthenticated. See [deployment.md](deployment.md) for OAuth setup. + +## Next steps + +- [concepts.md](concepts.md) โ€” understand scenarios, detonators, matchers, and collectors +- [walkthrough.md](walkthrough.md) โ€” run your first detection test end to end +- [configuration.md](configuration.md) โ€” configure connectors, app defaults, and environment variables diff --git a/docs/packs.md b/docs/packs.md new file mode 100644 index 0000000..a064826 --- /dev/null +++ b/docs/packs.md @@ -0,0 +1,76 @@ +# Packs + +Install simulations and tune their parameters. + +## What a pack is + +A **pack** is an external, versioned bundle of attack simulations. Each pack ships Terraform modules, scenario definitions, and a manifest that describes the simulations it contains and the parameters it accepts. + +Packs are installed and managed from the **Packs page** (`/packs`). Once a pack is installed, its simulations are available for use in scenario YAML files via the `simrunDetonator.pack` and `simrunDetonator.simulation` fields. + +## Shipped packs + +Two first-party packs are available: + +| Pack | Contents | +|---|---| +| `simrun-base-pack` | Custom simulations targeting AWS, Azure, and GCP. | +| `simrun-stratus-pack` | Wraps [Stratus Red Team](https://github.com/DataDog/stratus-red-team) attack techniques. | + +## Installing a pack + +A pack is a compiled binary. There are two ways to install one from the **Packs** page (`/packs`), shown as **Remote** and **Upload** tabs in the install dialog. + +### Remote โ€” pull a published pack + +Use this for shipped or published packs. + +1. Open the **Packs** page (`/packs`) and start a new install. +2. Choose **Remote**, then enter the pack name, its source (the release location), and optionally a version. +3. Click **Install**. SimRun fetches the pack, validates its manifest, and stores it in the database. + +To move a remote pack to a newer version later, use the **Update** action on the same page. + +### Upload โ€” install a local build + +Use this to install a pack binary you built yourself โ€” ideal for **rapid development and testing of simulations**, or when publishing a pack isn't appropriate for your environment. + +1. Build the pack binary locally (e.g. `go build`, or `mise run build` in the pack repo). +2. On the **Packs** page, start a new install and choose **Upload**. +3. Enter the pack name and select the compiled binary, then install. SimRun stores the binary, runs it to read its manifest, and lists its simulations โ€” exactly as for a remote pack. + +After installation โ€” by either method โ€” the pack appears in the list with its available simulations and declared parameters. + +## Pack parameters + +Parameters let you tune pack-wide settings โ€” cloud regions, tag values, project identifiers โ€” without editing individual scenario files. + +### Built-in parameters + +Every pack automatically includes these built-in parameters (defined in the SimRun SDK): + +| Parameter | Description | +|---|---| +| `default_tags` | Map of tags applied to every resource created by the pack (e.g. `{"env": "security-test"}`). | +| `aws_region` | AWS region used as the default for all simulations in the pack. | +| `gcp_region` | GCP region used as the default for all simulations in the pack. | +| `azure_location` | Azure location used as the default for all simulations in the pack. | + +### Custom parameters + +Pack authors declare additional parameters in the pack's `main()` function using `pack.RegisterPackParams(...pack.PackParam)`. These appear alongside the built-ins in the pack's manifest `params_schema` and are available for configuration on the Packs page once the pack is installed. + +## Parameter precedence + +When a simulation runs, Terraform variable values are resolved in this order (last write wins): + +1. **Terraform variable default** โ€” the `default` value declared inside the module's `variable` block. +2. **Pack-level value** โ€” set via the Packs page; applies to every simulation in the pack. +3. **Per-simulation scenario value** โ€” the `params` map in the scenario YAML for a specific simulation; overrides the pack-level value for that run only. + +Map and array parameter values are JSON-encoded before being passed to Terraform as `TF_VAR_`. + +## See also + +- [walkthrough.md](walkthrough.md) โ€” run your first detection test end to end +- [scenarios.md](scenarios.md) โ€” reference pack simulations in scenario YAML diff --git a/docs/scenarios.md b/docs/scenarios.md new file mode 100644 index 0000000..e8f50ee --- /dev/null +++ b/docs/scenarios.md @@ -0,0 +1,208 @@ +# Scenarios YAML reference + +The YAML shape behind every assessment. + +> You don't have to write this by hand. The assessment editor has a visual **Builder** mode โ€” add scenarios, detonators, and expectations with forms โ€” and a **YAML** mode you can toggle to at any time. + +--- + +## Top-level structure + +A scenario file has three top-level keys. Only `scenarios` is required. + +| Field | Type | Required | Description | +|---|---|---|---| +| `targets` | object | Yes | Connector names for each cloud/infrastructure target used by all scenarios in this file. | +| `targets.aws` | string | No | Name of the AWS connector to use for cloud credentials. | +| `targets.gcp` | string | No | Name of the GCP connector to use for cloud credentials. | +| `targets.azure` | string | No | Name of the Azure connector to use for cloud credentials. | +| `targets.kubernetes` | string | No | Name of the Kubernetes connector to use for cluster access. | +| `targets.ssh` | string | No | Name of the SSH connector to use for remote command detonation. _(The SSH connector is not yet configurable in the UI โ€” see [connectors-and-secrets.md](connectors-and-secrets.md#ssh).)_ | +| `scenarios` | array | **Yes** | List of scenario objects (see below). | + +--- + +## A scenario + +Each item in `scenarios` describes one unit of work: how to trigger activity and what alerts to expect. + +| Field | Type | Required | Description | +|---|---|---|---| +| `name` | string | **Yes** | Display name for this scenario. | +| `expectations` | array | **Yes** | One or more alert expectations (see [Expectations](#expectations)). | +| `enabled` | boolean | No | Whether to run this scenario. Defaults to `true`. Set to `false` to skip without deleting. | +| `indicators` | object | No | Values extracted after detonation and used for log correlation. | +| `indicators.terraformOutput` | string[] | No | Terraform output keys to extract (e.g. `attacker_vm_public_ip`). | +| `indicators.static` | string[] | No | Fixed strings that will appear in generated activity (e.g. a known username). | +| `detonate` | object | No | How to execute the attack. Mutually exclusive with `inject`. | +| `inject` | object | No | How to push a document directly into the SIEM instead of running an attack. Mutually exclusive with `detonate`. | +| `collect` | object | No | How to retrieve related logs after detonation for post-hoc analysis. | + +--- + +## Detonators + +A `detonate` block must contain exactly one detonator. + + +### simrunDetonator + +Runs a pack simulation using Terraform. The pack must be installed before the run. + +| Field | Type | Required | Description | +|---|---|---|---| +| `pack` | string | **Yes** | Name of the installed pack containing the simulation. | +| `simulation` | string | **Yes** | Simulation ID within the pack (e.g. `aws.exfil.s3`). | +| `params` | object | No | Key-value parameters passed to the simulation. Merged with pack-level defaults; per-scenario values take precedence. Map and array values are JSON-encoded. | + +```yaml +scenarios: + - name: s3 exfiltration + detonate: + simrunDetonator: + pack: attack-pack + simulation: aws.s3-disable-public-access-block + params: + aws_region: us-east-1 + bucket_name: my-test-bucket + expectations: + - timeout: 5m + elasticSecurityAlert: + name: "S3 Public Access Block Disabled" + severity: high +``` + +--- + +## Injector + +An `inject` block must contain `elasticInjector`. Use injection to verify a detection rule is wired up without running a real attack: SimRun writes the document and then polls for the expected alert. + +### elasticInjector + +| Field | Type | Required | Description | +|---|---|---|---| +| `documents` | array | **Yes** | One or more documents to inject into Elasticsearch. | +| `documents[].index` | string | **Yes** | Elasticsearch index to write into. | +| `documents[].file` | string | See note | Path to a JSON document file. Supports `{{variable_name}}` placeholder substitution. Required unless `template` is used. | +| `documents[].template` | string | See note | Pack template ID (e.g. `okta.add-group-member`). Required unless `file` is used. | +| `documents[].pack` | string | See note | Pack providing the template. Required when `template` is set. | +| `documents[].vars` | object | No | String-to-string map of variables to substitute in the document using `{{variable_name}}` syntax. | + +Each document must supply both `template` + `pack`. + +```yaml +scenarios: + - name: Okta API key created without network zone restriction + inject: + elasticInjector: + documents: + - index: "logs-okta.system-default" + template: okta.api-token-create + pack: base-dev + expectations: + - elasticSecurityAlert: + name: "Okta API key created/updated without network zone restriction" + timeout: 10m +``` + +--- + +## Collector + +A `collect` block must contain `elasticCollector`. Collectors run after detonation and store related logs with the run result. + +### elasticCollector + +| Field | Type | Required | Description | +|---|---|---|---| +| `index` | string | **Yes** | Elasticsearch index to search for logs. | +| `additionalFields` | object | No | Extra fields to filter by. Values can be static strings or template expressions referencing Terraform outputs, e.g. `{{ indicators.terraformOutput.attacker_vm_public_ip }}`. | + +```yaml +scenarios: + - name: with collector + detonate: + simrunDetonator: + pack: attack-pack + simulation: aws.s3-disable-public-access-block + collect: + elasticCollector: + index: "logs-test" + additionalFields: + source.ip: "{{ indicators.terraformOutput.attacker_vm_public_ip }}" + expectations: + - timeout: 1m + elasticSecurityAlert: + name: "Test signal" +``` + +--- + +## Expectations + +Every scenario must declare at least one expectation. Each expectation specifies a `timeout` and exactly one matcher. + +| Field | Type | Required | Description | +|---|---|---|---| +| `timeout` | string | No | Maximum time to wait for the alert. Written as a Go duration (e.g. `5m`, `30s`, `2m30s`). Defaults to `5m`. | +| `elasticSecurityAlert` | object | See note | Match an Elastic Security Detection alert. | +| `datadogSecuritySignal` | object | See note | Match a Datadog security signal. | + +### elasticSecurityAlert + +Polls Kibana until a Detection Engine alert appears whose `kibana.alert.rule.name.keyword` matches `name`. + +| Field | Type | Required | Description | +|---|---|---|---| +| `name` | string | **Yes** | Exact rule name to match (matched against `kibana.alert.rule.name.keyword`). | +| `severity` | string | No | Alert severity to match. One of: `low`, `medium`, `high`, `critical`. | + +### datadogSecuritySignal + +Polls Datadog Security Signals until a signal with a matching name appears. + +| Field | Type | Required | Description | +|---|---|---|---| +| `name` | string | **Yes** | Exact signal name to match. | +| `severity` | string | No | Signal severity to match. | + +--- + +## Full example + +```yaml +targets: + aws: "aws-prod" + azure: "azure-prod" + +scenarios: + - name: Exfiltrate an AMI by Sharing It + detonate: + simrunDetonator: + pack: stratus-dev + simulation: aws.ec2-share-ami + expectations: + - elasticSecurityAlert: + name: AWS EC2 AMI Shared with Another Account + timeout: 20m + - name: Delete CloudTrail Trail + detonate: + simrunDetonator: + pack: stratus-dev + simulation: aws.cloudtrail-delete + indicators: + terraformOutput: + - cloudtrail_trail_name + expectations: + - elasticSecurityAlert: + name: "AWS CloudTrail Log Deleted" + timeout: 15m +``` + +--- + +## See also + +- [concepts.md](concepts.md) โ€” vocabulary, detonators, matchers, and collectors explained +- [connectors-and-secrets.md](connectors-and-secrets.md) โ€” set up the connectors referenced in `targets` diff --git a/docs/walkthrough.md b/docs/walkthrough.md new file mode 100644 index 0000000..d7cafa8 --- /dev/null +++ b/docs/walkthrough.md @@ -0,0 +1,113 @@ +# Walkthrough: Your First Detection Test + +From a fresh SimRun to your first matched detection. + +## Before you start + +- SimRun is running and reachable. See [getting-started.md](getting-started.md) if you haven't set it up yet. +- You're familiar with the vocabulary โ€” assessments, runs, scenarios, expectations, matchers. See [concepts.md](concepts.md) for a quick overview. + +**Goal:** detonate a real pack simulation in AWS and confirm that the expected Elastic Security alert fires. + +You'll need: +- A running Elastic Security deployment with Kibana access and an API key. +- An AWS account and credentials (access key or role ARN) that SimRun can use to run the simulation. + +--- + +## Step 1 โ€” Open the dashboard + +Navigate to http://localhost:8080. The Dashboard gives an at-a-glance view of recent runs and scenario pass/fail rates. + +--- + +## Step 2 โ€” Add connectors and secrets + +SimRun needs to know where your SIEM is and how to reach AWS. Both are configured as connectors backed by secret groups. + +### Add the Elastic connector + +1. Go to **Connectors** (`/connectors`). +2. Click **Add connector**, choose type `elastic`. +3. Enter your `kibana_url` (e.g. `https://kibana.example.com`). +4. Under **Secret group**, create a new group and add `SR_ELASTIC_API_KEY` with your Elasticsearch API key. +5. Save. SimRun will use this connector as the default SIEM for all runs. + +### Add the AWS connector + +1. Still on **Connectors**, click **Add connector**, choose type `aws`. +2. If you're using role assumption, enter the `role_arn`. +3. (if not using a role) Under **Secret group**, create a group and add `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`. + +See [connectors-and-secrets.md](connectors-and-secrets.md) for the full field reference. + +--- + +## Step 3 โ€” Install a pack + +A pack bundles the Terraform modules and scenario definitions for a set of simulations. + +1. Go to **Packs** (`/packs`) and start a new install. +2. Choose **Remote** and enter the pack name (e.g. `simrun-base-pack`) and its source. (The **Upload** tab installs a pack binary you built locally โ€” handy when developing your own simulations.) +3. Click **Install**. SimRun fetches the pack, validates its manifest, and lists the available simulations. +4. Optionally set pack-level parameters โ€” for example, set `aws_region` to `us-east-2` so every simulation in the pack targets that region by default. + +See [packs.md](packs.md) for both install methods and parameter details. + +--- + +## Step 4 โ€” Create an assessment + +An assessment is a saved definition of scenarios. You'll create one with a single scenario that detonates a pack simulation and expects an Elastic Security alert. + +1. Go to **Assessments** (`/assessments`) and click **New assessment**. +2. Give it a name, then define the scenario. The editor opens in **Builder** mode, where you add detonators and expectations with forms โ€” or switch to **YAML** mode to write or paste it directly. Either way, here's the YAML this scenario produces: + +```yaml +targets: + aws: my-aws-connector # the connector name from Step 2 + +scenarios: + - name: S3 public access block disabled + detonate: + simrunDetonator: + pack: simrun-base-pack + simulation: aws.s3-disable-public-access-block + expectations: + - elasticSecurityAlert: + name: "S3 Public Access Block Disabled" +``` + +Key points: +- `targets.aws` must match the connector name you created in Step 2. +- `simrunDetonator.pack` and `simrunDetonator.simulation` reference the pack you installed in Step 3. +- `elasticSecurityAlert.name` is the exact Detection Engine rule name in Kibana that you expect to fire. + +See [scenarios.md](scenarios.md) for the full YAML reference. + +--- + +## Step 5 โ€” Run it + +Click **Run** on the assessment. SimRun creates a new Run and begins executing scenarios in parallel. + +- Each scenario detonates the simulation, then polls Kibana for the expected alert. +- The run page updates in real time as scenarios complete. + +--- + +## Step 6 โ€” Wait for the results + +Each scenario shows one of: +- **Matched** โ€” the expectation fired; the expected alert was found in Kibana within the timeout. +- **Unmatched** โ€” the alert was not found before the timeout expired. Check whether the rule is enabled in Kibana and that the simulation actually ran. + +If you added a `collect` block to your scenario, the related Elasticsearch logs are shown alongside the results for post-hoc analysis. + +--- + +## Next steps + +- **Rule Coverage** (`/rules/coverage`) โ€” view your Elastic detection rules mapped to MITRE ATT&CK techniques. Identify which techniques have coverage and which are gaps. +- **Scheduling** โ€” run assessments on a recurring schedule directly from the Assessments page. +- **Write your own scenarios** โ€” see [scenarios.md](scenarios.md) for the full YAML reference: multiple expectations, AWS CLI detonation, log injection, indicators, and collectors. diff --git a/web/frontend/src/lib/assets/simrun-icon.png b/web/frontend/src/lib/assets/simrun-icon.png new file mode 100644 index 0000000..e0a3472 Binary files /dev/null and b/web/frontend/src/lib/assets/simrun-icon.png differ diff --git a/web/frontend/src/lib/components/Sidebar.svelte b/web/frontend/src/lib/components/Sidebar.svelte index 76f250e..4490f2e 100644 --- a/web/frontend/src/lib/components/Sidebar.svelte +++ b/web/frontend/src/lib/components/Sidebar.svelte @@ -8,6 +8,7 @@ import { activeRuns } from '$lib/stores/runs'; import { getVersion } from '$lib/api/client'; import { health } from '$lib/stores/health'; + import simrunIcon from '$lib/assets/simrun-icon.png'; import LayoutDashboardIcon from '@lucide/svelte/icons/layout-dashboard'; import PlayIcon from '@lucide/svelte/icons/play'; import FileTextIcon from '@lucide/svelte/icons/file-text'; @@ -54,23 +55,23 @@ {#if sidebar.state === 'collapsed'}
-
- SR -
+ />
{:else}
-
- SR -
+ />
SimRun Attack Simulation diff --git a/web/frontend/src/routes/login/+page.svelte b/web/frontend/src/routes/login/+page.svelte index 720b39b..154ff4c 100644 --- a/web/frontend/src/routes/login/+page.svelte +++ b/web/frontend/src/routes/login/+page.svelte @@ -1,16 +1,13 @@
-
- SR -
+ SimRun Welcome to SimRun Sign in with your Google account to continue