feat: clone-and-go remote agent install kit
This commit is contained in:
@@ -0,0 +1,20 @@
|
|||||||
|
# onlyscans remote-agent .env (copy to .env, fill the three AGENT_ values)
|
||||||
|
# Values come from the central /agents admin page (Sam provisions them).
|
||||||
|
|
||||||
|
# Username of the agent record created at /agents (e.g. chch-1)
|
||||||
|
AGENT_IDENTITY=
|
||||||
|
|
||||||
|
# The password shown ONCE at agent creation (or after a reset on /agents)
|
||||||
|
AGENT_PASSWORD=
|
||||||
|
|
||||||
|
# The location NAME this agent scans from (e.g. chch-office)
|
||||||
|
AGENT_LOCATION=
|
||||||
|
|
||||||
|
# NOT needed — the registry image is publicly pullable. Only fill this if
|
||||||
|
# Sam tells you the registry has been re-privatized (then also run:
|
||||||
|
# docker login gitea.noctools.nz -u sam -p <this-token>).
|
||||||
|
# REGISTRY_TOKEN=
|
||||||
|
|
||||||
|
# Optional CVE matching via central API (leave empty unless Sam provides it)
|
||||||
|
CVE_MATCH_API=
|
||||||
|
CVE_MATCH_TOKEN=
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
.env
|
||||||
@@ -0,0 +1,78 @@
|
|||||||
|
# Only Scans — remote agent install kit
|
||||||
|
|
||||||
|
This repo installs a **remote scan agent** for the Only Scans platform on a
|
||||||
|
docker host at your site. The agent is a location-labelled scanner: it logs
|
||||||
|
into the central instance with its own credentials, picks up scans queued
|
||||||
|
for your location, and reports results back.
|
||||||
|
|
||||||
|
The agent is inert without centrally-provisioned credentials — this repo
|
||||||
|
contains no secrets.
|
||||||
|
|
||||||
|
## What you get from Sam (central operator)
|
||||||
|
|
||||||
|
1. An **agent username** (e.g. `chch-1`)
|
||||||
|
2. The **password** shown once at agent creation
|
||||||
|
3. Your **location name** (e.g. `chch-office`)
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
|
||||||
|
- Docker + the `docker compose` plugin
|
||||||
|
- Egress to `scan-api.noctools.nz:443` (the central API, TLS)
|
||||||
|
- Network reachability to the scan targets for your site — see
|
||||||
|
"Host-network variant" below if you need ARP-level LAN discovery
|
||||||
|
- ~512 MB RAM for the container
|
||||||
|
|
||||||
|
## Install
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git clone https://gitea.noctools.nz/sam/onlyscans-agent-kit.git
|
||||||
|
cd onlyscans-agent-kit
|
||||||
|
cp .env.agent.example .env
|
||||||
|
# edit .env: AGENT_IDENTITY / AGENT_PASSWORD / AGENT_LOCATION
|
||||||
|
docker compose -f docker-compose.agent.yml up -d
|
||||||
|
docker logs -f onlyscans-agent
|
||||||
|
```
|
||||||
|
|
||||||
|
The worker image pulls anonymously — no `docker login` required.
|
||||||
|
|
||||||
|
**Expected log lines on a healthy start:**
|
||||||
|
`authenticated` … `agent <name>: AGENT_LOCATION "<loc>" validated`.
|
||||||
|
A rejected password or unknown location name is FATAL by design —
|
||||||
|
check the values in `.env` and `docker compose -f docker-compose.agent.yml up -d --force-recreate`.
|
||||||
|
|
||||||
|
**Verify centrally:** Sam confirms the agent flips **online** on the
|
||||||
|
central `/agents` page within ~90 s, then queues a pinned test scan against
|
||||||
|
your location — `claimed_by` should show the agent username.
|
||||||
|
|
||||||
|
## Upgrades
|
||||||
|
|
||||||
|
The compose file pins an image tag. To upgrade: `git pull` this repo,
|
||||||
|
bump the tag + `AGENT_VERSION` in `docker-compose.agent.yml` if Sam hasn't
|
||||||
|
already, then:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker compose -f docker-compose.agent.yml pull
|
||||||
|
docker compose -f docker-compose.agent.yml up -d
|
||||||
|
```
|
||||||
|
|
||||||
|
The agent re-authenticates and resumes polling.
|
||||||
|
|
||||||
|
## Options
|
||||||
|
|
||||||
|
- **Host-network variant** (scan the site LAN directly, ARP-level
|
||||||
|
discovery, non-routed subnets): swap the service to `network_mode: host`
|
||||||
|
per the commented block in `docker-compose.agent.yml`.
|
||||||
|
- **Second agent on the same box:** copy the compose file, change the
|
||||||
|
project `name:` and `container_name` (and `WORKER_HEALTH_PORT` under
|
||||||
|
host networking) per the comments in the file.
|
||||||
|
- **CVE matching** (optional): fill `CVE_MATCH_API` + `CVE_MATCH_TOKEN`
|
||||||
|
in `.env` only if Sam provides them. Without it, scans complete
|
||||||
|
normally with the CVE stage skipped.
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
| Symptom | Meaning |
|
||||||
|
|---|---|
|
||||||
|
| Container exits ~1 s after start | Bad `AGENT_PASSWORD` or unknown `AGENT_LOCATION` — fatal by design; fix `.env` and recreate |
|
||||||
|
| Agent shows **offline** centrally (`/agents`) | Container down, or no egress to `scan-api.noctools.nz:443` — check `docker logs onlyscans-agent` |
|
||||||
|
| Scans stay queued | Agent online but for a different location, or targets unreachable from the container's network — try the host-network variant |
|
||||||
@@ -0,0 +1,84 @@
|
|||||||
|
# onlyscans REMOTE AGENT install kit — run this ON THE REMOTE SITE's
|
||||||
|
# docker host. One agent = one location = one vantage.
|
||||||
|
#
|
||||||
|
# Prereqs (do these FIRST, on the central instance's web UI):
|
||||||
|
# 1. Admin → /agents → create the LOCATION for this site (e.g. "chch-office").
|
||||||
|
# 2. /agents → New agent: username (e.g. "chch-1") + that location. The
|
||||||
|
# password is shown ONCE — put it in .env as AGENT_PASSWORD below.
|
||||||
|
#
|
||||||
|
# Then on this host:
|
||||||
|
# cp .env.agent.example .env (fill AGENT_IDENTITY / AGENT_PASSWORD /
|
||||||
|
# AGENT_LOCATION) → docker compose -f docker-compose.agent.yml up -d
|
||||||
|
# The worker image pulls anonymously from the public registry — no
|
||||||
|
# `docker login` needed. (Fallback if the registry is ever re-privatized:
|
||||||
|
# Sam issues a gitea read:package token → `docker login gitea.noctools.nz
|
||||||
|
# -u sam -p <token>`.)
|
||||||
|
# Full walkthrough: README.md in this repo.
|
||||||
|
# (Running a SECOND agent on the same box: copy this file, change the project
|
||||||
|
# `name:` and `container_name` below — otherwise compose project + container
|
||||||
|
# collide with the first agent.)
|
||||||
|
#
|
||||||
|
# The agent talks to the central PocketBase over the public tunnel TLS
|
||||||
|
# (https://scan-api.noctools.nz) — credentials and results are encrypted in
|
||||||
|
# transit. It needs egress to: scan-api.noctools.nz:443, the scan targets,
|
||||||
|
# and (only if CVE_MATCH_API is set) that API host.
|
||||||
|
name: onlyscans-agent
|
||||||
|
services:
|
||||||
|
agent:
|
||||||
|
image: gitea.noctools.nz/sam/onlyscans-worker:20260821-2
|
||||||
|
# Bump the tag to track the central worker version (see README.md).
|
||||||
|
container_name: onlyscans-agent
|
||||||
|
restart: unless-stopped
|
||||||
|
cap_add:
|
||||||
|
- NET_RAW # nmap/masscan raw-packet scanning
|
||||||
|
- NET_ADMIN
|
||||||
|
environment:
|
||||||
|
PB_URL: https://scan-api.noctools.nz
|
||||||
|
AGENT_IDENTITY: ${AGENT_IDENTITY:?set in .env — the username created on /agents}
|
||||||
|
AGENT_PASSWORD: ${AGENT_PASSWORD:?set in .env — the shown-once password}
|
||||||
|
AGENT_LOCATION: ${AGENT_LOCATION:?set in .env — the location NAME from /agents}
|
||||||
|
AGENT_HEARTBEAT_SECONDS: 30
|
||||||
|
# Shown on /agents (agent_version) — bump together with the image tag
|
||||||
|
# when upgrading so the central UI can confirm the rollout.
|
||||||
|
AGENT_VERSION: 20260821-2
|
||||||
|
# Optional: CVE matching via the central cve-match API. Leave EMPTY unless
|
||||||
|
# Sam has given you a CVE_MATCH_API URL + token (its public exposure is a
|
||||||
|
# manual central-side step). Without it, scans still complete — the CVE
|
||||||
|
# stage is skipped for agents with no local NVD DB.
|
||||||
|
CVE_MATCH_API: ${CVE_MATCH_API:-}
|
||||||
|
CVE_MATCH_TOKEN: ${CVE_MATCH_TOKEN:-}
|
||||||
|
POLL_INTERVAL_MS: 5000
|
||||||
|
NMAP_VERSION_INTENSITY: 9
|
||||||
|
FINGERPRINT_CONCURRENCY: 4
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "wget", "--spider", "-q", "http://127.0.0.1:8081/healthz"]
|
||||||
|
interval: 15s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 4
|
||||||
|
deploy:
|
||||||
|
resources:
|
||||||
|
limits:
|
||||||
|
memory: 512m
|
||||||
|
|
||||||
|
# ── Host-network variant ────────────────────────────────────────────────────
|
||||||
|
# The default bridge network can only scan what it routes to. To scan the
|
||||||
|
# site's LAN directly (ARP-level discovery, non-routed subnets), swap the
|
||||||
|
# service to host networking. Each agent on a shared host stack needs its OWN
|
||||||
|
# health port — and the healthcheck `test` below MUST be bumped in tandem
|
||||||
|
# (it hardcodes the port; a stale probe would hit the FIRST agent's healthz
|
||||||
|
# and report false-healthy for the others):
|
||||||
|
#
|
||||||
|
# services:
|
||||||
|
# agent:
|
||||||
|
# image: gitea.noctools.nz/sam/onlyscans-worker:20260821-2
|
||||||
|
# network_mode: host # container shares the host's stack
|
||||||
|
# environment:
|
||||||
|
# ...
|
||||||
|
# WORKER_HEALTH_PORT: "8082" # 8083, 8084… for further agents on this box
|
||||||
|
# healthcheck:
|
||||||
|
# test: ["CMD", "wget", "--spider", "-q", "http://127.0.0.1:8082/healthz"]
|
||||||
|
# # …keep matching WORKER_HEALTH_PORT on every copy
|
||||||
|
# # NO ports:, NO networks: — host mode ignores them
|
||||||
|
#
|
||||||
|
# Masscan at high rates can disrupt fragile networks; coordinate rate with
|
||||||
|
# the profile's masscan_rate on the central instance.
|
||||||
Reference in New Issue
Block a user