Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 20 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
.PHONY: help cluster-up cluster-down cluster-status deploy-cilium deploy-falco \
deploy-kyverno deploy-observability deploy-agent deploy-ui \
setup-local dev-agent dev-ui demo-local hubble-ui grafana-ui k9s \
test test-agent test-ui simulate-threats clean
setup-local dev-agent dev-ui demo-local demo-cluster demo-cluster-dry-run hubble-ui grafana-ui k9s \
test test-agent test-ui test-cluster-demo simulate-threats clean

THREAT_COUNT ?= 10
THREAT_SCENARIO ?= mixed
Expand All @@ -16,6 +16,8 @@ help:
@echo " make cluster-up Provision VMs, install k3s, Cilium, namespaces"
@echo " make cluster-down Stop all OrbStack VMs"
@echo " make cluster-status Show node and pod status"
@echo " make demo-cluster Run guarded real-cluster threat demo"
@echo " make demo-cluster-dry-run Validate cluster prerequisites without changes"
@echo ""
@echo " Security"
@echo " make deploy-falco Install Falco via Helm"
Expand All @@ -34,6 +36,7 @@ help:
@echo ""
@echo " Utilities"
@echo " make test Run agent tests and build the UI"
@echo " make test-cluster-demo Test cluster-demo safety guards"
@echo " make simulate-threats Generate randomized demo incidents"
@echo " make hubble-ui Open Hubble network flow UI"
@echo " make grafana-ui Port-forward Grafana to localhost:3000"
Expand Down Expand Up @@ -109,6 +112,18 @@ dev-ui:
demo-local:
@bash scripts/demo-local.sh "$(THREAT_COUNT)" "$(THREAT_SCENARIO)" "$(THREAT_SEED)"

demo-cluster:
@DEMO_CLUSTER_CONTEXT="$(DEMO_CLUSTER_CONTEXT)" \
DEMO_NAMESPACE="$(or $(DEMO_NAMESPACE),argus-demo)" \
DEMO_WAIT_SECONDS="$(or $(DEMO_WAIT_SECONDS),30)" \
DEMO_KEEP_RESOURCES="$(or $(DEMO_KEEP_RESOURCES),false)" \
bash scripts/demo-cluster.sh

demo-cluster-dry-run:
@DEMO_NAMESPACE="$(or $(DEMO_NAMESPACE),argus-demo)" \
DEMO_WAIT_SECONDS="$(or $(DEMO_WAIT_SECONDS),30)" \
bash scripts/demo-cluster.sh --dry-run

test: test-agent test-ui

test-agent:
Expand All @@ -117,6 +132,9 @@ test-agent:
test-ui:
@npm --prefix ui run build

test-cluster-demo:
@bash scripts/tests/test-demo-cluster.sh

simulate-threats:
@curl --fail --silent http://localhost:8000/health >/dev/null || \
(echo "Argus backend is not running on localhost:8000."; \
Expand Down
112 changes: 59 additions & 53 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,53 @@ command, expected result, testing mode, and troubleshooting path, follow the
| Mode | Command | Cluster required? | Evidence |
|---|---|---:|---|
| Local synthetic | `make demo-local` | No | Generated incidents for console and workflow testing |
| Full Kubernetes | `bash cluster/test-diverse-threats.sh` | Yes | Real Falco, Cilium, and Kyverno signals |
| Full Kubernetes | `make demo-cluster` | Yes | Real Falco, Cilium, Kyverno, and Argus evidence |

For a guarded, one-command run against an existing cluster with Cilium, Falco,
Kyverno, and Argus already installed:

```bash
make demo-cluster
```

The command displays the active context and requires you to type it exactly before
creating anything. It uses a dedicated `argus-demo` namespace, collects runtime
evidence, and deletes that namespace on exit. Run `make demo-cluster-dry-run` for a
read-only prerequisite check.

### Full k3s demo — existing OrbStack cluster

OrbStack exposes its own single-node Kubernetes context named `orbstack`. That is
**not** the Argus cluster. Argus runs on three Ubuntu VMs managed by OrbStack and uses
the kubeconfig context named `argus`.

```text
OrbStack application
├── built-in Kubernetes → context: orbstack → node: orbstack
└── Linux machines
├── k3s-master ┐
├── k3s-worker1 ├→ context: argus → real three-node k3s cluster
└── k3s-worker2 ┘
```

If those three machines already exist, do **not** run `make cluster-up` again. Select
and verify the existing cluster:

```bash
orb list
kubectl config get-contexts
kubectl config use-context argus
kubectl get nodes -o wide
make demo-cluster-dry-run
make demo-cluster
```

Expected preflight components are three ready k3s nodes plus Cilium, Falco, Kyverno,
and the Argus agent. At the confirmation prompt, type the exact context printed by the
command (`argus` for this repository's OrbStack cluster).

`make demo-cluster` currently collects real cluster evidence in the terminal. It does
not yet launch the React console; cluster UI startup is the next integration step.

## Part of the Sentinel multi-agent platform

Expand Down Expand Up @@ -110,9 +156,9 @@ The Kubernetes deployment uses the in-cluster Sentinel service address automatic

| Node | Role | IP | Status |
|---|---|---|---|
| k3s-master | Control plane | 192.168.139.42 | Active |
| k3s-worker1 | Worker | 192.168.139.77 | Active |
| k3s-worker2 | Worker | 192.168.139.45 | Active |
| k3s-master | Control plane | 192.168.139.42 | Ready — k3s v1.34.6 |
| k3s-worker1 | Worker | 192.168.139.77 | Ready — k3s v1.34.6 |
| k3s-worker2 | Worker | 192.168.139.45 | Ready — k3s v1.34.6 |

**Cilium:** v1.15.0 — eBPF mode, kube-proxy replacement enabled
**Hubble:** Relay + UI enabled — live network flow observability active
Expand Down Expand Up @@ -278,57 +324,17 @@ Kyverno catches a separate category of threat — workloads that violate securit
Start with the cluster-free [Quickstart](#quickstart--no-cluster-required) unless you
specifically need real kernel, network, and admission-control evidence.

### Prerequisites
- macOS (Apple Silicon M-series)
- OrbStack installed (`brew install orbstack`)
- CLI tools: `brew install kubectl helm k3sup cilium-cli hubble k9s`

### Spin up the cluster
```bash
make cluster-up
```
Use exactly one of these paths:

This provisions 3 OrbStack VMs, installs k3s, deploys Cilium with eBPF kube-proxy replacement, enables Hubble, and creates all namespaces.

### Verify the cluster
```bash
make cluster-status
cilium hubble ui
```

### Run services separately

**Backend agent:**
```bash
make dev-agent
```

**Console UI:**
```bash
make dev-ui
```

The UI runs at `http://localhost:5173` and proxies `/api/*` to the agent at port 8000.

The backend must be running before generating incidents. To populate the console:
```bash
make simulate-threats THREAT_COUNT=10 THREAT_SCENARIO=mixed
```

The generator randomizes threat type, workload, blast radius, enrichment evidence, and
recommended response. Use a seed to replay the exact same selection during tests or a
recorded demo:

```bash
make simulate-threats \
THREAT_COUNT=10 \
THREAT_SCENARIO=mixed \
THREAT_SEED=20260717
```
- Existing `k3s-*` OrbStack machines: select `argus`, run the dry-run, then run
`make demo-cluster`.
- Fresh Apple Silicon workstation: review the environment-specific bootstrap variables,
run `make cluster-up`, deploy the required security components, then run the dry-run.

Supported scenarios are `mixed`, `human_approval`, and `attack_chain`. The response
includes severity and action distributions plus the effective seed. Omitting `seed`
generates a new random run; reusing the returned seed reproduces its incident selection.
The complete commands, expected output, context explanation, manual cluster UI path,
and troubleshooting guide are in [setup.md](setup.md). Do not use `make dev-agent` or
`make simulate-threats` as substitutes for real-cluster evidence; those commands run
the local synthetic application path.

## Architecture decisions

Expand Down
34 changes: 18 additions & 16 deletions cluster/test-diverse-threats.sh
Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@
#!/bin/bash
set -e
#!/usr/bin/env bash
set -Eeuo pipefail

namespace="${DEMO_NAMESPACE:-argus-demo}"

echo "🎯 Creating diverse security threats for Argus detection..."
echo "These pods comply with Kyverno policies but trigger Falco runtime rules"
echo ""

# Clean up any existing threat pods first
kubectl delete pods -l 'threat-type' --force --grace-period=0 2>/dev/null || true
kubectl delete pods -n "$namespace" -l 'threat-type' --force --grace-period=0 2>/dev/null || true
sleep 2

# 1. Shell spawn in container (Falco will detect shell execution)
echo "1️⃣ Creating pod that spawns shell..."
cat <<EOF | kubectl apply -f -
cat <<EOF | kubectl apply -n "$namespace" -f -
apiVersion: v1
kind: Pod
metadata:
Expand All @@ -25,7 +27,7 @@ spec:
fsGroup: 1000
containers:
- name: shell-spawner
image: docker.io/library/busybox:latest
image: docker.io/library/busybox:1.36.1
command: ["sh"]
args: ["-c", "while true; do sh -c 'echo spawning shell'; sleep 5; done"]
securityContext:
Expand All @@ -44,7 +46,7 @@ EOF

# 2. File access patterns (Falco will detect sensitive file reads)
echo "2️⃣ Creating pod that reads sensitive files..."
cat <<EOF | kubectl apply -f -
cat <<EOF | kubectl apply -n "$namespace" -f -
apiVersion: v1
kind: Pod
metadata:
Expand All @@ -58,7 +60,7 @@ spec:
fsGroup: 1000
containers:
- name: file-reader
image: docker.io/library/busybox:latest
image: docker.io/library/busybox:1.36.1
command: ["sh"]
args: ["-c", "while true; do cat /etc/passwd /etc/group 2>/dev/null || true; sleep 10; done"]
securityContext:
Expand All @@ -77,7 +79,7 @@ EOF

# 3. Process execution patterns
echo "3️⃣ Creating pod with suspicious process execution..."
cat <<EOF | kubectl apply -f -
cat <<EOF | kubectl apply -n "$namespace" -f -
apiVersion: v1
kind: Pod
metadata:
Expand All @@ -91,7 +93,7 @@ spec:
fsGroup: 1000
containers:
- name: process-spawner
image: docker.io/library/busybox:latest
image: docker.io/library/busybox:1.36.1
command: ["sh"]
args: ["-c", "while true; do ps aux 2>/dev/null || ps; ls -la /proc 2>/dev/null || true; sleep 20; done"]
securityContext:
Expand All @@ -110,7 +112,7 @@ EOF

# 4. File modification attempts
echo "4️⃣ Creating pod that attempts file modifications..."
cat <<EOF | kubectl apply -f -
cat <<EOF | kubectl apply -n "$namespace" -f -
apiVersion: v1
kind: Pod
metadata:
Expand All @@ -124,7 +126,7 @@ spec:
fsGroup: 1000
containers:
- name: file-modifier
image: docker.io/library/busybox:latest
image: docker.io/library/busybox:1.36.1
command: ["sh"]
args: ["-c", "while true; do touch /tmp/suspicious-file; echo 'data' > /tmp/suspicious-file; rm /tmp/suspicious-file 2>/dev/null || true; sleep 8; done"]
securityContext:
Expand All @@ -143,7 +145,7 @@ EOF

# 5. Network activity simulation
echo "5️⃣ Creating pod with network activity..."
cat <<EOF | kubectl apply -f -
cat <<EOF | kubectl apply -n "$namespace" -f -
apiVersion: v1
kind: Pod
metadata:
Expand All @@ -157,7 +159,7 @@ spec:
fsGroup: 1000
containers:
- name: network-scanner
image: docker.io/library/busybox:latest
image: docker.io/library/busybox:1.36.1
command: ["sh"]
args: ["-c", "while true; do wget -T 2 -O /dev/null http://example.com 2>/dev/null || true; sleep 15; done"]
securityContext:
Expand All @@ -184,10 +186,10 @@ echo " - File modification patterns"
echo " - Network activity"
echo ""
echo "🔍 Check the Argus UI Command Center for detections"
echo "⏱️ Pods will run continuously until deleted"
echo "⏱️ The demo-cluster wrapper observes these pods, then deletes the demo namespace"
echo ""
echo "To view pod status:"
echo " kubectl get pods -l 'threat-type'"
echo " kubectl get pods -n $namespace -l 'threat-type'"
echo ""
echo "To clean up all threat pods:"
echo " kubectl delete pods -l 'threat-type' --force --grace-period=0"
echo " kubectl delete namespace $namespace"
38 changes: 30 additions & 8 deletions docs/GETTING_STARTED.md
Original file line number Diff line number Diff line change
Expand Up @@ -99,19 +99,38 @@ The UI proxies `/api/*` to the agent at `http://127.0.0.1:8000`.

## Full-cluster mode

Full-cluster mode provisions three k3s nodes on OrbStack and deploys Cilium, Falco,
Kyverno, Prometheus, Grafana, Loki, and Argus. Follow [setup.md](../setup.md) for the
complete prerequisites and deployment sequence.
The guarded demo works with an existing Kubernetes cluster where Cilium, Falco,
Kyverno, and Argus are already installed. The repository also includes an OrbStack/k3s
development-cluster bootstrap; follow [setup.md](../setup.md) when you need that stack.

After the stack is healthy, create real policy-compliant workloads that trigger runtime
rules:
OrbStack's built-in `orbstack` Kubernetes context is separate from the three-node k3s
cluster. Select the Argus context before preflight:

```bash
bash cluster/test-diverse-threats.sh
kubectl config get-contexts
kubectl config use-context argus
kubectl get nodes -o wide
```

This script requires a working `kubectl` context. It creates real pods and runs continuously
until those pods are deleted.
The expected nodes are `k3s-master`, `k3s-worker1`, and `k3s-worker2`. If the output
contains one node named `orbstack`, the wrong cluster is selected.

After the stack is healthy, run the guarded cluster demo:

```bash
make demo-cluster
```

The command prints the active Kubernetes context and API server, then requires the exact
context name before it creates resources. It validates node, Cilium, Falco, Kyverno, and
Argus readiness; launches bounded workloads in an isolated `argus-demo` namespace;
collects evidence; and removes the namespace on exit.

Run the read-only preflight first when using a new cluster:

```bash
make demo-cluster-dry-run
```

## Troubleshooting

Expand All @@ -123,6 +142,9 @@ until those pods are deleted.
| Console opens but has no incidents | The backend was restarted or never seeded | Run `make simulate-threats` |
| Cluster panels show no live data | Local synthetic mode has no Kubernetes telemetry | Use full-cluster mode for real telemetry |
| `kubectl` connection failure | Full-cluster mode is not configured | Complete [setup.md](../setup.md) |
| Cilium missing while the three OrbStack VMs are running | The `orbstack` context is selected instead of the k3s cluster | Run `kubectl config use-context argus`, then repeat the dry run |
| `make cluster-up` reports that machines already exist | The k3s VMs are already provisioned | Do not recreate them; select `argus` and run `make demo-cluster-dry-run` |
| Cluster demo finishes without opening a browser | The current cluster runner collects terminal evidence only | Use the manual port-forward in [setup.md](../setup.md); integrated UI startup is pending |

## Verify the repository

Expand Down
Loading
Loading