# Deploy via AWS

The [`scanner-inc/agents`](https://github.com/scanner-inc/agents/tree/main/aws) repository includes two Claude Agent SDK programs with full Terraform infrastructure, ready to deploy to your own AWS account. Both are written in TypeScript against the [Claude Agent SDK](https://github.com/anthropics/claude-agent-sdk).

## What these agents do

### Alert triage agent

A container-image Lambda that investigates Scanner detection alerts autonomously. Ingress is Scanner webhook → API Gateway (API key auth, rate limited) → SQS → Lambda. When an alert arrives, the agent:

1. Reviews the alert and generates 2 to 4 hypotheses (benign activity, misconfiguration, real attack, insider threat).
2. Queries Scanner MCP for evidence in a 4 to 6 hour window around the event, looking for related activity from the same user, IP, or account, plus expansion indicators like privilege escalation, lateral movement, or persistence.
3. Classifies the alert as BENIGN, SUSPICIOUS, or MALICIOUS with a confidence percentage.
4. Runs two self-critique passes before committing to a classification.
5. Posts a structured finding to Slack (TL;DR, classification, timeline, hypothesis testing, key evidence, MITRE ATT\&CK tags, recommended next questions). Logs every MCP tool call as structured JSON to CloudWatch for audit.

**Why run it.** Most alerts in a mature SOC are false positives. Manual triage is repetitive work analysts would rather spend on real threats. This agent handles the repetition in seconds per alert, filters the obvious benign cases, and gives analysts a pre-populated finding for the interesting ones.

**Why deploy to AWS rather than n8n.** Full control over the runtime. The agent runs inside your own AWS account; every MCP tool call and reasoning step lands in CloudWatch for audit; credentials live in Secrets Manager; infrastructure is managed by Terraform. Compliance-heavy environments that cannot run agents in third-party SaaS should use this path. Teams with platform engineers will also find code easier to version, test, and review than an n8n workflow JSON.

See [`aws/alert-triage/`](https://github.com/scanner-inc/agents/tree/main/aws/alert-triage) for the Lambda source, Dockerfile, Terraform, and system prompt.

### Threat hunting agent

A scheduled ECS Fargate task that proactively hunts for evidence of compromise across your historical Scanner logs. Runs on an EventBridge schedule (every 6 hours by default). Each run:

1. Discovers available indices via `get_scanner_context`.
2. Pulls fresh threat intel from multiple public feeds: CISA KEV (known exploited vulnerabilities), ThreatFox (IOCs), AlienVault OTX (pulses), Feodo Tracker (C2 IPs).
3. Filters the intel for indicators relevant to the customer's ingested log sources.
4. Posts a Slack announcement with what is being hunted and why.
5. Sweeps historical logs for IOCs (IPs, domains, hashes) via Scanner MCP. Pivots to behavioral queries when hits are found.
6. Correlates findings, builds timelines, maps to MITRE ATT\&CK.
7. Posts a structured findings report to Slack with evidence, confidence, visibility gaps, and recommended next questions.

**Why run it.** Known-bad IOCs land in public feeds daily. A SOC without a threat-hunting program typically has no systematic way to check for them across its log history. This agent runs while the team sleeps, checks every IOC in a fresh batch against the full Scanner log history, and only pages on findings. The 6-hour cadence and typical Scanner query speeds mean even large tenants hunt over 1+ years of data per run without timing out.

Also available as an n8n workflow — see [Deploy via n8n](/scanner/using-scanner-complete-feature-reference/mcp-and-ai-secops/deploying-agents/n8n.md#threat-hunting-agent) for the visual-editor version. The two are functionally similar but differ in a few details (the n8n version posts a single findings report rather than separate "hunt starting" and "hunt complete" messages, and wires three threat intel sources directly as HTTP Request Tools instead of going through `mcp-threatintel-server`).

See [`aws/threat-hunting/`](https://github.com/scanner-inc/agents/tree/main/aws/threat-hunting) for the container source, Dockerfile, Terraform, and system prompt.

## Prerequisites

* Node.js 22+
* Docker (for building container images)
* Terraform (for provisioning AWS infrastructure)
* AWS CLI, configured with a profile that has permission to create Lambda, ECS, VPC, ECR, IAM, Secrets Manager, and EventBridge resources
* An Anthropic API key
* A Scanner account with MCP access and a Scanner API key
* **For `threat-hunting/`** only:
  * A Slack workspace with a bot token
  * An [AlienVault OTX](https://otx.alienvault.com/) API key (free)
  * An [abuse.ch](https://abuse.ch/) auth key (free)

## Clone the repo

```bash
git clone https://github.com/scanner-inc/agents.git
cd agents/aws
```

## Install dependencies and verify AWS auth

```bash
./scripts/setup.sh
```

This runs `npm install` in both `alert-triage/` and `threat-hunting/`, then verifies your AWS profile is authenticated.

## Configure environment variables

Copy the root template and fill in credentials:

```bash
cp .env.template .env
# Edit .env
```

Minimum required:

```
AWS_PROFILE=your-aws-profile
AWS_REGION=us-west-2
ANTHROPIC_API_KEY=sk-ant-...
SCANNER_MCP_URL=https://mcp.<your-env>.scanner.dev/v1/mcp
SCANNER_MCP_API_KEY=...
```

Each sub-agent folder (`alert-triage/`, `threat-hunting/`) also has its own `.env.template` with agent-specific values (Slack tokens, threat intel API keys for threat-hunting; webhook API key for alert-triage).

## Deploy alert-triage

```bash
cd alert-triage
cp .env.template .env
# Edit .env with this agent's credentials
./deploy.sh
```

`deploy.sh` handles: ECR repo creation, TypeScript build, Docker build (linux/amd64), ECR push, Terraform apply, and Lambda code update. After it completes, Terraform outputs include:

* The API Gateway invoke URL for Scanner webhooks
* The API key value (use this as the `x-api-key` header in the Scanner event sink config)

Point your Scanner event sink (**Settings** → **Event Sinks** → **Create New Sink** → **Webhook**) at the invoke URL with the API key as a custom header. Attach the sink to the detection rules you want triaged.

## Deploy threat-hunting

```bash
cd ../threat-hunting
cp .env.template .env
# Edit .env — Anthropic, Scanner, Slack, OTX, abuse.ch
./deploy.sh
```

`deploy.sh` provisions an ECS cluster, Fargate task definition, a private VPC with a NAT gateway (for outbound API calls), an EventBridge schedule, IAM roles, and Secrets Manager entries for all credentials.

After deployment, EventBridge runs the hunt every 6 hours automatically. You can trigger a manual run with the command printed at the end of the deploy script.

## Architectures

### Alert triage

```
Scanner webhook event sink
    │  POST /v1/alerts (with x-api-key)
    ▼
API Gateway (REST, API key auth, rate-limited 5 req/s)
    │  forwards body to SQS (AWS service integration)
    ▼
SQS queue (batch_size=1, visibility_timeout=960s)
    │  triggers
    ▼
Lambda (container image, Node.js 22, reserved_concurrent_executions=5)
    │  queries Scanner MCP in a loop, classifies the alert
    ├──▶ Slack (finding posted via Slack MCP)
    └──▶ CloudWatch (structured JSON log of every tool call)
```

### Threat hunting

```
EventBridge schedule (every 6 hours)
    │  triggers
    ▼
ECS Fargate task on a private subnet
    │  outbound traffic via NAT gateway
    │  pulls IOCs: CISA KEV, ThreatFox, OTX, Feodo
    │  hunts via Scanner MCP
    └──▶ Slack (announcement + findings report via Slack MCP)
```

## Cost notes

`threat-hunting/` provisions a NAT gateway, which is always-on at about $32/month. The Fargate task itself is pay-per-run. `alert-triage/` has no steady-state infrastructure cost beyond Lambda/SQS, both of which are effectively free at low volume.

When you are done evaluating, tear down everything with:

```bash
./scripts/teardown.sh
```

This destroys the NAT gateway, ECS, Lambda, SQS, VPC, and all related resources across both agents.

## Troubleshooting

* **`deploy.sh` fails at Terraform apply with a permissions error**: your AWS profile lacks one of the required IAM permissions. Check the error message for the specific action; the Terraform files in each agent's `terraform/` directory list all resources being created.
* **Lambda times out (900 seconds)**: the agent ran for too long. Check CloudWatch logs to see where it stalled. Typically Scanner MCP unreachable or an MCP tool call hanging. Verify `SCANNER_MCP_URL` and `SCANNER_MCP_API_KEY` are correct in Secrets Manager.
* **Fargate task fails to start**: most often a container image push issue. Check that `deploy.sh` pushed to ECR successfully and that the task definition references the image digest.
* **Slack posts do not appear**: the Slack MCP server requires `SLACK_BOT_TOKEN` and `SLACK_TEAM_ID`. If these are missing, `alert-triage` degrades gracefully (agent runs but does not post); `threat-hunting` refuses to start (Slack is required).

See each agent's own README in the repository for agent-specific architecture notes, environment variables, and the canonical list of known issues.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.scanner.dev/scanner/using-scanner-complete-feature-reference/mcp-and-ai-secops/deploying-agents/aws.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
