Sensor deployment
Deploying a sensor
The sensor is a single container that only makes outbound HTTPS calls. Run it with the hardened profile below.
Hardened docker run
This is the command the Console generates. Every flag matters: the container runs as non-root, with a read-only filesystem, all Linux capabilities dropped except binding low ports, and no privilege escalation.
docker run -d --name kandaro-sensor \
--read-only --tmpfs /tmp \
--cap-drop ALL --cap-add NET_BIND_SERVICE \
--security-opt no-new-privileges \
-v kandaro-sensor:/app/data \
-e KANDARO_API_URL=https://api.kandaro.com \
-e KANDARO_ENROLL_TOKEN=<token from the Console> \
ghcr.io/kandaro/kandaro-sensor:<version>Never run the sensor with --privileged and never mount the Docker socket. Pin the image by version tag or digest: the sensor never updates its own code, and the Console tells you when a new version is available.
Its own IP on the LAN (macvlan, recommended)
With macvlan the decoy gets its own IP and MAC address and looks like a separate device on your network, rather than a port on the Docker host.
docker network create -d macvlan \
--subnet=192.168.1.0/24 --gateway=192.168.1.1 \
-o parent=eth0 decoy-net
docker run -d --name kandaro-sensor --network decoy-net \
--ip 192.168.1.250 --mac-address 00:11:32:aa:bb:cc \
--read-only --tmpfs /tmp --cap-drop ALL --cap-add NET_BIND_SERVICE \
--security-opt no-new-privileges -v kandaro-sensor:/app/data \
-e KANDARO_API_URL=https://api.kandaro.com -e KANDARO_ENROLL_TOKEN=<token> \
ghcr.io/kandaro/kandaro-sensor:<version>Adjust the parent interface, subnet, IP and MAC to your network. With macvlan the Docker host itself cannot reach the container’s IP directly, so test from another machine.
Docker Compose
The same setup as a compose file. Keep the enrol token in an .env file next to it.
services:
kandaro-sensor:
image: ghcr.io/kandaro/kandaro-sensor:<version>
restart: unless-stopped
read_only: true
tmpfs: [/tmp]
cap_drop: [ALL]
cap_add: [NET_BIND_SERVICE]
security_opt: [no-new-privileges:true]
environment:
KANDARO_API_URL: https://api.kandaro.com
KANDARO_ENROLL_TOKEN: ${KANDARO_ENROLL_TOKEN}
volumes:
- kandaro-sensor:/app/data
networks:
decoy-net:
ipv4_address: 192.168.1.250
mac_address: 00:11:32:aa:bb:cc
networks:
decoy-net:
driver: macvlan
driver_opts: { parent: eth0 }
ipam:
config:
- subnet: 192.168.1.0/24
gateway: 192.168.1.1
volumes:
kandaro-sensor:Verify the image signature
Sensor images are signed with Sigstore cosign (keyless, from our build pipeline) and ship with an SBOM. Verify before you run:
cosign verify ghcr.io/kandaro/kandaro-sensor:<version> \
--certificate-oidc-issuer https://token.actions.githubusercontent.com \
--certificate-identity-regexp '^https://github.com/kandaro/'Environment variables
| Variable | Default | Meaning |
|---|---|---|
KANDARO_API_URL | (unset) | Backend URL. Must be https:// for public hosts. Unset = standalone mode (console and local log only). |
KANDARO_ENROLL_TOKEN | (unset) | One-time enrol token from the Console. Ignored once credentials exist. |
KANDARO_PORT_OFFSET | 0 | Added to every port, e.g. 10000 to test without low ports. |
KANDARO_DATA_DIR | /app/data | Identity, SSH host keys, credentials, spool and event log. |
KANDARO_BIND | 0.0.0.0 | Bind address for all emulated services. |
KANDARO_PROFILE | (unset) | Local profile override; wins over the Console setting. |
Enrolment and credentials
- On first boot the sensor exchanges the enrol token for its own API key and stores it in
credentials.jsonin the data volume (mode 0600). - To re-enrol, create a new token in the Console, set it, and delete
credentials.json. If a key is revoked and a new token is present, the sensor re-enrols automatically. - If the API is unreachable, events are spooled to disk (50 MB cap) and delivered in order once the connection is back.
The data volume holds the passwords and API keys attackers try. If any of them are real keys of yours, rotate them immediately, and protect the volume like a password vault.
Placement tips
- Pick a profile that fits the segment: a printer in the office VLAN, a NAS or database server in the server network.
- Make the MAC address fit. Use an OUI (first three bytes) of a vendor that matches the profile; scanners show the vendor name.
- Make it discoverable. Give it an attractive DNS name (
backup,finance-share,vcenter) or leave a “forgotten” reference in documentation. - Do not expose it to the internet. You would get thousands of events from internet scanners. Inside your network, every hit matters.
- Ignore your own tools. Put monitoring and vulnerability scanners on the ignore list.
- Use several sensors with different profiles in different VLANs.
Known limitations
- SYN (stealth) scans don’t complete a TCP connection, so they are not seen. Connect scans, service detection and real connection attempts are.
- OS fingerprinting shows the host’s Linux TCP stack, even for Windows profiles. An experienced attacker using
nmap -Ocould notice.