Skip to content

Deploying Canary Tokens

Introduction

Canary Tokens is an open-source honeypot and threat detection platform that creates decoy resources to detect and alert on unauthorized access and suspicious activity. By deploying fake credentials, files, URLs, and infrastructure components throughout your network and systems, Canary Tokens provides early warning of security breaches and data exfiltration attempts. Deploy Canary Tokens on Klutch.sh to create a self-hosted threat detection system that monitors network activity and alerts you when attackers interact with your deployed decoys.

Key Features

  • Web Hook Tokens: Generate URLs that trigger alerts when visited by attackers
  • DNS Tokens: Create decoy DNS names that alert when resolved
  • AWS Infrastructure Tokens: Detect unauthorized AWS account exploration and resource access
  • Fake Credentials: Deploy honeypot AWS API keys, database credentials, and tokens
  • Document Tokens: Embed tracking in Microsoft Office documents for access detection
  • QR Code Tokens: Track when attackers scan fake QR codes
  • Log4Shell Detection: Identify CVE-2021-44228 exploitation attempts
  • Database Tokens: Create fake SQL Server, MySQL, and database dumps for detection
  • File System Tokens: Deploy fake files and folders that trigger alerts on access
  • Email Tokens: Generate unique email addresses to detect unauthorized access
  • Azure Tokens: Detect Azure service principal and Entra ID credential misuse
  • API Integration: REST API for programmatic token creation and management
  • Alert Management: Centralized dashboard for viewing and managing token events
  • Email Notifications: Automated email alerts when tokens are triggered
  • Webhook Support: Send alerts to external systems via webhooks
  • Alert Filtering: Throttle and filter alerts to reduce noise
  • Custom Domains: Use your own domains for token generation
  • IP Geolocation: Track attacker location and network information
  • Token History: Complete audit trail of token interactions
  • Multiple Alert Providers: Support for Mailgun, Sendgrid, Mandrill, and SMTP
  • User Management: Multi-user support with role-based access control

Prerequisites

Before deploying Canary Tokens on Klutch.sh, ensure you have:

  • A Klutch.sh account with access to the dashboard
  • A GitHub repository for your Canary Tokens deployment (public or private)
  • An email service configured for sending alerts (Mailgun, Sendgrid, SMTP, etc.)
  • Understanding of security concepts and threat detection strategies
  • A custom domain (recommended for token generation)

Important Considerations

Deployment Steps

  1. Create a Dockerfile

    Create a Dockerfile in the root of your repository with Canary Tokens configured for Docker deployment:

    FROM python:3.11-slim
    # Install system dependencies
    RUN apt-get update && apt-get install -y \
    build-essential \
    postgresql-client \
    curl \
    git \
    && rm -rf /var/lib/apt/lists/*
    # Clone Canary Tokens repository
    RUN git clone https://github.com/thinkst/canarytokens.git /app
    WORKDIR /app
    # Install Python dependencies
    RUN pip install --no-cache-dir -r requirements.txt
    # Create necessary directories
    RUN mkdir -p /data /config /uploads
    # Expose web interface and API ports
    EXPOSE 8080
    # Create entrypoint script
    COPY entrypoint.sh /app/entrypoint.sh
    RUN chmod +x /app/entrypoint.sh
    # Start Canary Tokens
    CMD ["/app/entrypoint.sh"]
  2. Create Configuration Files

    Create frontend.env for frontend configuration:

    # Frontend Configuration
    CANARY_DOMAINS=example-app.klutch.sh
    CANARY_NXDOMAINS=dns.example-app.klutch.sh,www.example-app.klutch.sh
    CANARY_WEB_IMAGE_UPLOAD_PATH=/uploads
    LOG_FILE=/data/frontend.log
    DEBUG=False
    # Optional: Google API Key for maps in web interface
    CANARY_GOOGLE_API_KEY=

    Create switchboard.env for backend/alert configuration:

    # Switchboard Configuration
    CANARY_PUBLIC_IP=0.0.0.0
    CANARY_PUBLIC_DOMAIN=example-app.klutch.sh
    CANARY_FORCE_HTTPS=True
    # Email Configuration (choose one provider)
    # Mailgun Configuration
    CANARY_MAILGUN_DOMAIN_NAME=mg.example.com
    CANARY_MAILGUN_API_KEY=key-xxxxxxxxxxxx
    # OR SMTP Configuration
    CANARY_SMTP_SERVER=smtp.gmail.com
    CANARY_SMTP_PORT=587
    CANARY_SMTP_USERNAME=your-email@gmail.com
    CANARY_SMTP_PASSWORD=your-app-password
    # Alert Settings
    CANARY_ALERT_EMAIL_FROM_ADDRESS=canarytoken@example.com
    CANARY_ALERT_EMAIL_FROM_DISPLAY=Canarytoken Alerter
    CANARY_ALERT_EMAIL_SUBJECT=Canarytoken Alert
    CANARY_MAX_ALERTS_PER_MINUTE=1000
    # Optional: IP Info API Key for geolocation
    CANARY_IPINFO_API_KEY=
    # Logging
    LOG_FILE=/data/switchboard.log
    DEBUG=False
  3. Create Entrypoint Script

    Create an entrypoint.sh file for container initialization:

    #!/bin/bash
    set -e
    echo "Initializing Canary Tokens..."
    # Create data directory
    mkdir -p /data
    mkdir -p /uploads
    # Load environment variables
    export $(cat /config/frontend.env | xargs)
    export $(cat /config/switchboard.env | xargs)
    # Run database migrations if needed
    python manage.py migrate 2>/dev/null || true
    # Start frontend process in background
    echo "Starting frontend process..."
    python frontend.py &
    FRONTEND_PID=$!
    # Start switchboard process
    echo "Starting switchboard process..."
    python switchboard.py &
    SWITCHBOARD_PID=$!
    # Wait for processes
    wait $FRONTEND_PID $SWITCHBOARD_PID

    Make it executable:

    Terminal window
    chmod +x entrypoint.sh
  4. Create Environment Variables File

    Create a .env.example file for configuration documentation:

    # Canary Tokens Configuration
    # Frontend Settings
    CANARY_DOMAINS=example-app.klutch.sh
    CANARY_NXDOMAINS=dns.example-app.klutch.sh
    CANARY_WEB_IMAGE_UPLOAD_PATH=/uploads
    # Alert Configuration
    CANARY_ALERT_EMAIL_FROM_ADDRESS=canarytoken@example.com
    CANARY_ALERT_EMAIL_FROM_DISPLAY=Canarytoken Alerter
    CANARY_ALERT_EMAIL_SUBJECT=Canarytoken Alert
    # Email Provider (Mailgun)
    CANARY_MAILGUN_DOMAIN_NAME=
    CANARY_MAILGUN_API_KEY=
    # OR Email Provider (SMTP)
    CANARY_SMTP_SERVER=smtp.gmail.com
    CANARY_SMTP_PORT=587
    CANARY_SMTP_USERNAME=
    CANARY_SMTP_PASSWORD=
    # Security Settings
    CANARY_FORCE_HTTPS=True
    CANARY_MAX_ALERTS_PER_MINUTE=1000
    # Optional Services
    CANARY_IPINFO_API_KEY=
    CANARY_GOOGLE_API_KEY=
    # Logging
    DEBUG=False
    LOG_LEVEL=info
  5. Create .gitignore File

    Create a .gitignore file to exclude sensitive files:

    # Environment and configuration files with secrets
    frontend.env
    switchboard.env
    .env
    .env.local
    *.key
    *.pem
    *.crt
    # Data files
    /data/
    /uploads/
    *.db
    *.sqlite
    # Logs
    *.log
    *.txt
    # Python cache
    __pycache__/
    *.pyc
    *.pyo
    *.egg-info/
    dist/
    build/
    # IDE and OS files
    .DS_Store
    .vscode/
    .idea/
    Thumbs.db
  6. Create Docker Compose for Local Testing

    Create a docker-compose.yml for local development and testing (not for Klutch.sh deployment):

    version: '3.8'
    services:
    canarytokens:
    build: .
    container_name: canarytokens-dev
    ports:
    - "8080:8080"
    volumes:
    - ./frontend.env:/config/frontend.env
    - ./switchboard.env:/config/switchboard.env
    - canary_data:/data
    - canary_uploads:/uploads
    environment:
    - PYTHONUNBUFFERED=1
    networks:
    - canary-network
    volumes:
    canary_data:
    canary_uploads:
    networks:
    canary-network:
    driver: bridge
  7. Push to GitHub

    Push your repository to GitHub with all configuration files:

    Terminal window
    git add Dockerfile entrypoint.sh frontend.env switchboard.env \
    docker-compose.yml .env.example .gitignore
    git commit -m "Initial Canary Tokens deployment configuration"
    git push origin main
  8. Deploy on Klutch.sh

    1. Navigate to klutch.sh/app and log in to your dashboard
    2. Click Create New App
    3. Select Docker as the deployment method (detected automatically from your Dockerfile)
    4. Connect your GitHub repository containing the Canary Tokens deployment files
    5. Confirm the Dockerfile is detected from your root directory
    6. Click Deploy to start the deployment process
    7. Wait for the deployment to complete and your app to become active
  9. Configure Traffic Rules and Persistent Volume

    1. In your app dashboard, navigate to Traffic settings
    2. Select HTTP as the traffic type
    3. Set the internal port to 8080 (Canary Tokens web interface default)
    4. Save your traffic configuration
    5. Navigate to Volumes settings
    6. Click Add Volume
    7. Enter mount path: /data
    8. Set volume size to 20GB (adjust based on expected token volume)
    9. Click Attach to create and mount the persistent volume
    10. Your Canary Tokens server will be accessible at example-app.klutch.sh

Initial Setup and Configuration

After deploying Canary Tokens on Klutch.sh, access the web interface and configure your alert system.

Access the Web Interface

  1. Navigate to http://example-app.klutch.sh:8080/ in your browser
  2. You’ll see the Canary Tokens dashboard
  3. The interface shows your deployed tokens and alert history
  4. Create your first token to get started

Create Your First Token

  1. Click the Create Token button
  2. Select a token type:
    • Web Hook: URL that alerts when visited
    • DNS: Domain name that alerts when resolved
    • AWS Infrastructure: Detect AWS account exploration
    • AWS Keys: Honeypot AWS API credentials
    • Database: Fake database credentials
    • Document: Embed tracking in Office documents
  3. Configure token settings:
    • Add a memorable name
    • Set notification email addresses
    • Configure webhook endpoint (optional)
  4. Click Generate to create the token
  5. Copy the generated token and deploy it in your infrastructure

Configure Alert Email

  1. Click Settings in the web interface
  2. Configure your email provider:
    • Mailgun: Add domain and API key
    • Sendgrid: Add API key
    • SMTP: Configure SMTP server details
  3. Set notification email address for alerts
  4. Test email configuration by clicking Send Test Email
  5. Save settings

Set Up Webhook Alerts

  1. In Settings, scroll to Webhooks
  2. Enter your webhook URL for receiving token alerts
  3. Select which events trigger webhook notifications
  4. Canary Tokens will POST alert JSON to your webhook endpoint
  5. Configure your webhook handler to process alert data

Monitor Token Activity

  1. Dashboard shows real-time token interactions
  2. View alert history with:
    • Timestamp of interaction
    • Attacker IP address
    • Geographic location
    • Detailed event information
  3. Filter alerts by:
    • Token type
    • Date range
    • Source IP
  4. Export alert data for analysis and reporting

Deploy Tokens in Your Infrastructure

  1. Web Hook tokens can be placed in accessible locations for discovery
  2. DNS tokens should be used in network monitoring tools
  3. AWS tokens can be deployed in test/staging environments
  4. Document tokens can be included in honeypot files
  5. Database tokens can be added to development databases

Environment Variables

Basic Configuration

Configure these environment variables through your deployment:

  • CANARY_DOMAINS=example-app.klutch.sh - Primary domain for token generation
  • CANARY_NXDOMAINS=dns.example-app.klutch.sh - DNS token domains (non-existent)
  • CANARY_WEB_IMAGE_UPLOAD_PATH=/uploads - Path for uploaded token images
  • CANARY_ALERT_EMAIL_FROM_ADDRESS=canarytoken@example.com - Alert email sender address
  • DEBUG=False - Debug mode (set to True only for troubleshooting)

Production Environment Variables

For production deployments using Nixpacks, configure these environment variables:

# Domain Configuration
CANARY_DOMAINS=example-app.klutch.sh
CANARY_NXDOMAINS=dns.example-app.klutch.sh,tokens.example-app.klutch.sh
CANARY_AWSID_URL=
# Email Configuration (Mailgun)
CANARY_MAILGUN_DOMAIN_NAME=mg.example.com
CANARY_MAILGUN_API_KEY=key-xxxxx
CANARY_MAILGUN_BASE_URL=https://api.mailgun.net
# OR Email Configuration (SMTP)
CANARY_SMTP_SERVER=smtp.gmail.com
CANARY_SMTP_PORT=587
CANARY_SMTP_USERNAME=your-email@example.com
CANARY_SMTP_PASSWORD=your-app-password
CANARY_SMTP_ENABLE_TLS=True
# OR Email Configuration (Sendgrid)
CANARY_SENDGRID_API_KEY=SG.xxxxx
# Alert Settings
CANARY_ALERT_EMAIL_FROM_ADDRESS=noreply@example.com
CANARY_ALERT_EMAIL_FROM_DISPLAY=Canarytoken Security Alert
CANARY_ALERT_EMAIL_SUBJECT=Canarytoken Alert - Action Required
CANARY_MAX_ALERTS_PER_MINUTE=1000
MAX_ALERT_FAILURES=5
# Security
CANARY_FORCE_HTTPS=True
CANARY_PUBLIC_IP=0.0.0.0
CANARY_PUBLIC_DOMAIN=example-app.klutch.sh
# IP Geolocation
CANARY_IPINFO_API_KEY=xxxxx
# Optional Services
CANARY_GOOGLE_API_KEY=
# Logging
LOG_FILE=/data/switchboard.log
LOG_LEVEL=info
DEBUG=False
# Performance
CANARY_THREAD_POOL_SIZE=10
CANARY_REQUEST_TIMEOUT=30

Code Examples

Python - Canary Tokens API Client

# Canary Tokens API Client for Token Management
import requests
import json
from datetime import datetime
from typing import List, Dict, Optional
class CanaryTokensClient:
def __init__(self, base_url="http://example-app.klutch.sh:8080", api_key=None):
self.base_url = base_url
self.api_key = api_key
self.session = requests.Session()
if api_key:
self.session.headers.update({"Authorization": f"Bearer {api_key}"})
def create_web_token(self, memo: str, webhook_url: Optional[str] = None) -> Dict:
"""Create a web hook token"""
try:
payload = {
"type": "web",
"memo": memo,
}
if webhook_url:
payload["webhook_url"] = webhook_url
response = self.session.post(
f"{self.base_url}/api/tokens/create",
json=payload,
timeout=30
)
return response.json()
except Exception as e:
print(f"Error creating web token: {e}")
return {}
def create_dns_token(self, memo: str, dns_name: str) -> Dict:
"""Create a DNS resolution token"""
try:
payload = {
"type": "dns",
"memo": memo,
"dns_name": dns_name
}
response = self.session.post(
f"{self.base_url}/api/tokens/create",
json=payload,
timeout=30
)
return response.json()
except Exception as e:
print(f"Error creating DNS token: {e}")
return {}
def create_aws_token(self, memo: str, aws_account_id: str) -> Dict:
"""Create an AWS infrastructure token"""
try:
payload = {
"type": "aws_infra",
"memo": memo,
"aws_account_id": aws_account_id
}
response = self.session.post(
f"{self.base_url}/api/tokens/create",
json=payload,
timeout=30
)
return response.json()
except Exception as e:
print(f"Error creating AWS token: {e}")
return {}
def get_all_tokens(self) -> List[Dict]:
"""Get all deployed tokens"""
try:
response = self.session.get(
f"{self.base_url}/api/tokens/list",
timeout=30
)
return response.json().get("tokens", [])
except Exception as e:
print(f"Error fetching tokens: {e}")
return []
def get_token_alerts(self, token_id: str, limit: int = 100) -> List[Dict]:
"""Get alerts for a specific token"""
try:
response = self.session.get(
f"{self.base_url}/api/tokens/{token_id}/alerts",
params={"limit": limit},
timeout=30
)
return response.json().get("alerts", [])
except Exception as e:
print(f"Error fetching token alerts: {e}")
return []
def get_all_alerts(self, limit: int = 500) -> List[Dict]:
"""Get all alerts across all tokens"""
try:
response = self.session.get(
f"{self.base_url}/api/alerts/all",
params={"limit": limit},
timeout=30
)
return response.json().get("alerts", [])
except Exception as e:
print(f"Error fetching all alerts: {e}")
return []
def delete_token(self, token_id: str) -> bool:
"""Delete a token"""
try:
response = self.session.delete(
f"{self.base_url}/api/tokens/{token_id}",
timeout=30
)
return response.status_code == 200
except Exception as e:
print(f"Error deleting token: {e}")
return False
def export_alerts_json(self, output_file: str) -> bool:
"""Export all alerts to JSON file"""
try:
alerts = self.get_all_alerts()
with open(output_file, 'w') as f:
json.dump({
"export_date": datetime.now().isoformat(),
"alert_count": len(alerts),
"alerts": alerts
}, f, indent=2)
print(f"Alerts exported to {output_file}")
return True
except Exception as e:
print(f"Error exporting alerts: {e}")
return False
def get_statistics(self) -> Dict:
"""Get deployment statistics"""
try:
response = self.session.get(
f"{self.base_url}/api/stats",
timeout=30
)
return response.json()
except Exception as e:
print(f"Error fetching statistics: {e}")
return {}
# Usage example
if __name__ == "__main__":
client = CanaryTokensClient("http://example-app.klutch.sh:8080")
# Create tokens
print("Creating web hook token...")
web_token = client.create_web_token(
memo="Production server honeypot",
webhook_url="https://your-webhook-handler.example.com/alerts"
)
print(f"Web token: {web_token}")
# Get all tokens
print("\nListing all tokens...")
tokens = client.get_all_tokens()
for token in tokens:
print(f" - {token['memo']}: {token['id']}")
# Get all alerts
print("\nFetching all alerts...")
alerts = client.get_all_alerts(limit=10)
print(f"Total alerts: {len(alerts)}")
for alert in alerts[:5]:
print(f" - {alert['timestamp']}: {alert['description']}")
# Export alerts
print("\nExporting alerts...")
client.export_alerts_json("canary_alerts.json")

Bash - Canary Tokens Management Script

#!/bin/bash
# Canary Tokens Server Management Script
# Requires: curl, jq (optional for JSON formatting)
CANARY_HOST="example-app.klutch.sh"
CANARY_PORT="8080"
CANARY_URL="http://${CANARY_HOST}:${CANARY_PORT}"
# Color output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# Check server status
check_status() {
echo -e "${BLUE}Checking Canary Tokens server status...${NC}"
if curl -s "${CANARY_URL}/" > /dev/null 2>&1; then
echo -e "${GREEN}✓ Canary Tokens server is online${NC}"
return 0
else
echo -e "${RED}✗ Canary Tokens server is offline${NC}"
return 1
fi
}
# Create a web token
create_web_token() {
local memo=$1
if [ -z "$memo" ]; then
echo -e "${RED}Usage: create_web_token <memo>${NC}"
return 1
fi
echo -e "${YELLOW}Creating web token: $memo${NC}"
curl -s -X POST "${CANARY_URL}/api/tokens/create" \
-H "Content-Type: application/json" \
-d "{\"type\": \"web\", \"memo\": \"$memo\"}" | \
jq . 2>/dev/null || echo "Token created (jq not available)"
}
# Create a DNS token
create_dns_token() {
local memo=$1
local dns_name=$2
if [ -z "$memo" ] || [ -z "$dns_name" ]; then
echo -e "${RED}Usage: create_dns_token <memo> <dns_name>${NC}"
return 1
fi
echo -e "${YELLOW}Creating DNS token: $memo${NC}"
curl -s -X POST "${CANARY_URL}/api/tokens/create" \
-H "Content-Type: application/json" \
-d "{\"type\": \"dns\", \"memo\": \"$memo\", \"dns_name\": \"$dns_name\"}" | \
jq . 2>/dev/null || echo "Token created (jq not available)"
}
# List all tokens
list_tokens() {
echo -e "${BLUE}Listing all tokens:${NC}"
curl -s "${CANARY_URL}/api/tokens/list" | \
jq '.tokens[] | {id: .id, memo: .memo, type: .type, created: .created_at}' 2>/dev/null || \
curl -s "${CANARY_URL}/api/tokens/list" | head -50
}
# Get all alerts
get_alerts() {
local limit=${1:-100}
echo -e "${BLUE}Fetching alerts (limit: $limit):${NC}"
curl -s "${CANARY_URL}/api/alerts/all?limit=$limit" | \
jq '.alerts[] | {timestamp: .timestamp, token: .token_memo, source_ip: .source_ip}' 2>/dev/null || \
curl -s "${CANARY_URL}/api/alerts/all?limit=$limit"
}
# Get alerts for specific token
get_token_alerts() {
local token_id=$1
local limit=${2:-50}
if [ -z "$token_id" ]; then
echo -e "${RED}Usage: get_token_alerts <token_id> [limit]${NC}"
return 1
fi
echo -e "${BLUE}Fetching alerts for token $token_id:${NC}"
curl -s "${CANARY_URL}/api/tokens/${token_id}/alerts?limit=$limit" | \
jq '.alerts[] | {timestamp: .timestamp, source_ip: .source_ip, description: .description}' 2>/dev/null || \
curl -s "${CANARY_URL}/api/tokens/${token_id}/alerts?limit=$limit"
}
# Export alerts
export_alerts() {
local output_file=${1:-canary_alerts.json}
echo -e "${YELLOW}Exporting alerts to $output_file${NC}"
curl -s "${CANARY_URL}/api/alerts/all?limit=10000" > "$output_file" && \
echo -e "${GREEN}✓ Alerts exported${NC}" || \
echo -e "${RED}✗ Export failed${NC}"
}
# Monitor alerts in real-time
monitor_alerts() {
echo -e "${YELLOW}Monitoring Canary Tokens (press Ctrl+C to stop)...${NC}"
while true; do
clear
echo -e "${BLUE}=== Canary Tokens Monitor ===${NC}"
echo "Time: $(date)"
echo ""
echo "Recent Alerts:"
curl -s "${CANARY_URL}/api/alerts/all?limit=20" | \
jq '.alerts[] | "\(.timestamp): \(.source_ip) - \(.description)"' 2>/dev/null || \
echo "Fetching alerts..."
sleep 10
done
}
# Display statistics
show_stats() {
echo -e "${BLUE}Canary Tokens Statistics:${NC}"
curl -s "${CANARY_URL}/api/stats" | \
jq . 2>/dev/null || \
curl -s "${CANARY_URL}/api/stats"
}
# Main menu
case "${1:-help}" in
status)
check_status
;;
create-web)
create_web_token "$2"
;;
create-dns)
create_dns_token "$2" "$3"
;;
list)
list_tokens
;;
alerts)
get_alerts "${2:-100}"
;;
token-alerts)
get_token_alerts "$2" "${3:-50}"
;;
export)
export_alerts "${2:-canary_alerts.json}"
;;
monitor)
monitor_alerts
;;
stats)
show_stats
;;
*)
echo -e "${YELLOW}Canary Tokens Management${NC}"
echo "Usage: $0 {status|create-web|create-dns|list|alerts|token-alerts|export|monitor|stats} [args]"
echo ""
echo "Commands:"
echo " status - Check server status"
echo " create-web <memo> - Create a web hook token"
echo " create-dns <memo> <name> - Create a DNS token"
echo " list - List all tokens"
echo " alerts [limit] - Get all alerts (default: 100)"
echo " token-alerts <id> [limit] - Get alerts for token"
echo " export [file] - Export alerts to JSON"
echo " monitor - Monitor alerts in real-time"
echo " stats - Show statistics"
;;
esac

Shell - Canary Tokens Alert Processor

#!/bin/sh
# Canary Tokens Alert Processor
# Process and respond to incoming webhook alerts
WEBHOOK_PORT=9000
ALERT_LOG="canary_alerts.log"
ALERT_SCRIPT="process_alert.sh"
# Create alert processor
start_alert_processor() {
echo "Starting alert processor on port $WEBHOOK_PORT..."
# Simple HTTP server using netcat
while true; do
{
echo -ne "HTTP/1.1 200 OK\r\nContent-Length: 2\r\n\r\nOK"
cat
} | nc -l -p $WEBHOOK_PORT -q 1 | while read line; do
# Log incoming alerts
echo "[$(date)] Alert received: $line" >> "$ALERT_LOG"
# Call alert processing script if exists
if [ -x "$ALERT_SCRIPT" ]; then
"./$ALERT_SCRIPT" "$line" &
fi
done
done
}
# Process alert data
process_alert() {
local alert_data=$1
echo "[$(date)] Processing alert: $alert_data"
# Extract key information from JSON alert
local token_id=$(echo "$alert_data" | grep -o '"token_id":"[^"]*' | cut -d'"' -f4)
local source_ip=$(echo "$alert_data" | grep -o '"source_ip":"[^"]*' | cut -d'"' -f4)
local timestamp=$(echo "$alert_data" | grep -o '"timestamp":"[^"]*' | cut -d'"' -f4)
echo "Token ID: $token_id"
echo "Source IP: $source_ip"
echo "Timestamp: $timestamp"
# Send alert to external system
notify_security_team "$token_id" "$source_ip"
}
# Notify security team
notify_security_team() {
local token_id=$1
local source_ip=$2
local message="CANARY TOKEN TRIGGERED!
Token: $token_id
Source IP: $source_ip
Time: $(date)
Action Required: Investigate immediately"
# Send notification (customize for your system)
echo "ALERT: $message"
# Could send to Slack, PagerDuty, SIEM, etc.
# curl -X POST https://your-slack-webhook.example.com \
# -d "text=$message"
}
# Analyze alert patterns
analyze_patterns() {
echo "Analyzing alert patterns..."
# Count alerts by IP
echo ""
echo "Top attacking IPs:"
grep -o '"source_ip":"[^"]*' "$ALERT_LOG" | cut -d'"' -f4 | \
sort | uniq -c | sort -rn | head -10
# Count alerts by token type
echo ""
echo "Token types triggered:"
grep -o '"token_type":"[^"]*' "$ALERT_LOG" | cut -d'"' -f4 | \
sort | uniq -c | sort -rn
# Timeline of alerts
echo ""
echo "Alert frequency (hourly):"
grep -o '\[.*\]' "$ALERT_LOG" | \
cut -d':' -f1-2 | sort | uniq -c | sort -rn
}
# Export alerts for analysis
export_for_analysis() {
local output_file="alert_analysis_$(date +%s).txt"
echo "Exporting alerts to $output_file..."
{
echo "=== Canary Tokens Alert Analysis ==="
echo "Generated: $(date)"
echo ""
echo "=== Alert Summary ==="
grep -c . "$ALERT_LOG" | xargs echo "Total alerts:"
echo ""
echo "=== Recent Alerts ==="
tail -20 "$ALERT_LOG"
echo ""
echo "=== IP Analysis ==="
analyze_patterns
} > "$output_file"
echo "Analysis exported to $output_file"
}
# Main function
case "${1:-help}" in
start)
start_alert_processor
;;
process)
process_alert "$2"
;;
analyze)
analyze_patterns
;;
export)
export_for_analysis
;;
*)
echo "Canary Tokens Alert Processor"
echo "Usage: $0 {start|process|analyze|export} [args]"
echo ""
echo "Commands:"
echo " start - Start webhook alert processor"
echo " process <json> - Process alert data"
echo " analyze - Analyze alert patterns"
echo " export - Export analysis report"
;;
esac

Best Practices

  • Strategic Placement: Deploy tokens in areas attackers would likely explore during reconnaissance
  • Realistic Naming: Use convincing names for tokens to increase discovery likelihood
  • Monitor Alerts: Set up reliable alert delivery through multiple providers (email + webhook)
  • Alert Response: Create runbooks for responding to token triggers
  • Regular Review: Periodically review token activity and effectiveness
  • Rotate Tokens: Refresh tokens periodically to maintain deception
  • Document Strategy: Document which tokens exist and where they’re deployed
  • Test Alerts: Verify alert delivery works before relying on tokens in production
  • Limit Scope: Start with a small number of tokens and expand gradually
  • Track ROI: Monitor how many false positives vs. actual threats you detect
  • Integrate with SIEM: Send alerts to your security information and event management system
  • Tune Thresholds: Adjust alert throttling based on your environment’s baseline activity

Troubleshooting

Issue: Alerts not being received

  • Verify email provider configuration in switchboard.env
  • Test email settings by sending a test alert from the web interface
  • Check spam/junk folders for alert emails
  • Verify webhook endpoint is accessible and returning 200 OK
  • Review logs for SMTP or webhook errors

Issue: Tokens not triggering

  • Verify tokens are correctly deployed in target environments
  • Confirm network connectivity between token location and server
  • Check that tokens haven’t been cached or ignored by security tools
  • Test token manually to ensure it’s working
  • Review server logs for incoming requests

Issue: High false positive rate

  • Adjust CANARY_MAX_ALERTS_PER_MINUTE to filter excessive alerts
  • Review which systems are legitimately accessing tokens
  • Consider moving tokens to less frequently accessed locations
  • Implement IP-based whitelisting for known-safe systems
  • Enable alert throttling to reduce noise

Issue: Server performance issues

  • Monitor available disk space for alert storage
  • Check if alert database has grown too large
  • Consider archiving old alerts
  • Adjust thread pool size based on token volume
  • Monitor memory usage and connection limits

Issue: Configuration not loading

  • Verify environment variables are set correctly
  • Check that env files are properly formatted
  • Ensure email provider settings are exclusive (only one provider)
  • Review application logs for configuration errors
  • Restart container after changing environment variables

Update Instructions

To update Canary Tokens to the latest version:

  1. Update Dockerfile: Modify base image or clone latest from repository
  2. Test Locally: Build and test with docker-compose before deployment
  3. Backup Data: Create a backup of persistent volumes before updating
  4. Push Changes: Commit and push updated Dockerfile to GitHub
  5. Redeploy: In Klutch.sh dashboard, trigger a manual redeploy
  6. Verify: Test token creation and alert delivery after update

Example Dockerfile update:

# Update the repository checkout to latest
RUN git clone --depth 1 https://github.com/thinkst/canarytokens.git /app

Use Cases

  • Breach Detection: Detect when attackers access honeypot credentials or systems
  • Network Reconnaissance: Identify when attackers probe your infrastructure
  • Insider Threat Detection: Monitor for unauthorized access to sensitive resources
  • Incident Response Validation: Confirm threat actor capabilities and intentions
  • Compliance Monitoring: Maintain audit trail of suspicious activities
  • Threat Intelligence: Gather information about attacker patterns and techniques
  • Early Warning System: Get notified before actual production systems are compromised
  • Security Posture Assessment: Evaluate your organization’s detection capabilities
  • Forensic Investigations: Provide evidence of breach timeline and scope
  • Security Testing: Validate detection and response capabilities

Additional Resources

Conclusion

Deploying Canary Tokens on Klutch.sh provides a self-hosted threat detection system for identifying unauthorized access and suspicious activity in your infrastructure. By following this guide, you’ve set up a production-ready Canary Tokens server with persistent storage for managing your honeypot tokens.

Your Canary Tokens deployment is now ready to deploy decoy resources throughout your network and receive alerts when attackers interact with them. Whether you’re protecting production systems, testing your security monitoring capabilities, or detecting insider threats, Canary Tokens provides powerful early warning capabilities.

For advanced configurations, webhook integration, or troubleshooting assistance, refer to the official Canary Tokens documentation and community resources linked above. Regular monitoring and analysis of token activity will help you understand threats to your organization and improve your security posture.