Skip to main content

Scanners

A scanner runs discovery and vulnerability testing inside your network and reports results back to the CyberOptix CTEM Platform. You deploy it on your own infrastructure; it needs no inbound connectivity.

Deployment is two stages, and they are deliberately separate: install puts the package on the host, and link binds that host to one scanner group in your organization. A scanner that is installed but not linked is inert and harmless, which is what makes it safe to build hosts from an image.

Before you start​

MinimumRecommended
CPU4 cores4 cores
Memory8 GB16 GB
Disk120 GB150 GB

Operating system: Ubuntu Server 24.04, with root or sudo access.

Network: outbound HTTPS (443) to your platform hostname and to the Purple Team Software package repositories, plus access to whatever the scanner is meant to reach in the zones you assign it. No inbound connections are required, so a scanner can sit behind NAT with no forwarded ports.

You will also need, from the platform:

  • A scanner group to link into. Create one under Deployment if you have none.
  • A license key, which gates vulnerability-test synchronization. Email [email protected] if you do not have one.
note

cyberoptix.scanner is the package name and optix is the service account. Both are product-internal identifiers rather than branding, so they read the same on every deployment regardless of which brand you access the platform under.

Install​

Add the package repository:

sudo rm -f /usr/share/keyrings/purpleteamsoftware-archive-keyring.gpg
wget -O - https://apt.fury.io/purpleteamsoftware/gpg.key | sudo gpg --dearmor -o /usr/share/keyrings/purpleteamsoftware-archive-keyring.gpg
echo "deb [signed-by=/usr/share/keyrings/purpleteamsoftware-archive-keyring.gpg] https://apt.purpleteamsoftware.com/ /" | sudo tee /etc/apt/sources.list.d/purpleteamsoftware.list
tip
Why the rm -f first

gpg --dearmor prompts before overwriting an existing keyring. On a re-run - which is common, because this is the step people repeat after a typo - that prompt has nothing attached to answer it, so the command appears to hang. Removing the old keyring first makes the step idempotent.

Install the scanner:

sudo apt update && sudo apt install cyberoptix.scanner -y

Disable swap, and comment out the 127.0.1.1 entry so the host does not resolve its own hostname to loopback during discovery:

sudo sed -i '/swap/ s/^/#/' /etc/fstab && sudo sed -i '/127\.0\.1\.1/ s/^/#/' /etc/hosts
sudo reboot

Add your user to the docker and optix groups:

sudo usermod -aG docker,optix $USER

New group membership does not apply to your current shell. Start a new session so it takes effect:

exec sudo -u $USER bash -l
tip
Prefer this over su $USER

su can prompt for a password, which stalls an otherwise unattended build. sudo -u re-initializes group membership from /etc/group without one.

Install the license key:

sudo bash -c 'echo YOUR_LICENSE_KEY > /etc/optix/license.key' && sudo chmod 600 /etc/optix/license.key

Pull and start the containers:

docker compose -f /etc/optix/docker-compose-optix.yml --profile disable pull
note
What --profile disable does

Two of the images, kali-linux and nmap, are tooling the scanner invokes on demand rather than long-running services. They sit behind a compose profile named disable, so they are never started. Including the profile in the pull means their images are cached locally up front; without it, the first task that needs one pulls it mid-scan.

docker compose -f /etc/optix/docker-compose-optix.yml up -d

Synchronize vulnerability tests, and enable the timer that keeps them current:

sudo /usr/local/bin/sync-vulnerability-tests.sh && sudo systemctl enable --now optix-sync-tests.timer

Fix ownership:

sudo chown optix:optix -R /etc/optix/ && sudo chown optix:optix /var/lib/optix

In the platform, open your scanner group and click the copy icon to copy its link command. Copy it rather than typing it: it arrives with your API hostname, scanner group ID and organization ID already filled in, and all three have to match exactly.

It looks like this:

sudo scanner-link -url https://<your-api-hostname>/ -scanner_group_id <id> -organization_id <id>

On success it prints Scanner linked successfully and writes credentials to /etc/optix/scanner-config.json.

Finally, enable the services:

sudo systemctl enable --now \
scanner-active-discovery.service \
scanner-client-completed-tasks.service \
scanner-client-new-tasks.service \
scanner-task-manager.service \
scanner-vm.service \
scanner-dast.service

Verify​

All six services and the sync timer should report active (running):

systemctl status --no-pager scanner-active-discovery scanner-client-completed-tasks scanner-client-new-tasks scanner-task-manager scanner-vm scanner-dast optix-sync-tests.timer

Two containers should be up, redis and owaspZap:

docker ps

The scanner polls for work every 30 seconds, so the clearest sign it is healthy is task traffic:

sudo journalctl -u scanner-client-new-tasks.service -f

Then confirm the scanner now appears in its group in the platform. If it does not, start with Troubleshooting.

What each service does​

ServicePurpose
scanner-client-new-tasksRetrieves new tasks from the platform, polling every 30s
scanner-task-managerRoutes each task to the right queue by type
scanner-active-discoveryHost and service discovery via Nmap
scanner-vmNetwork vulnerability scanning
scanner-dastDynamic application security testing, via the OWASP ZAP container
scanner-client-completed-tasksReports results back to the platform
optix-sync-testsKeeps vulnerability test definitions current

Work moves between them through Redis queues, which is why redis being down stops everything even though no scanning depends on it directly:

platform ──▶ new-tasks ──▶ NewScannerTasksQueue ──▶ task-manager
│
┌───────────────────────────┴──────────────────┐
▼ ▼
NmapTasksQueue NetworkVulnerabilityTasksQueue
│ │
▼ ▼
active-discovery scanner-vm
│ │
└───────────────────┬──────────────────────────┘
▼
CompletedScannerTasksQueue
│
▼
completed-tasks ──▶ platform

Files​

PathPurposePermissions
/etc/optix/scanner-config.jsonConfiguration and credentials600
/etc/optix/license.keyVulnerability test sync license600
/etc/optix/docker-compose-optix.ymlContainer definitions644
/var/lib/optix/vulnerability_tests/Test definitions755
/var/lib/optix/scanner.sockScanner daemon socketoptix:optix
/var/log/optix/Log files755

Maintenance mode​

Pause task processing without unlinking the scanner - use this before host maintenance so in-flight work is not abandoned:

scanner-cli -mode_maintenance
scanner-cli -mode_running
scanner-cli -version

Next​