Configuration Best Practices¶
This page provides production-tested best practices for configuring OWASP Amass deployments. It covers configuration hierarchy, resolver management, scope tuning, secrets handling, and performance optimization.
For basic installation and initial configuration, see Installation. For detailed information about the Configuration System architecture, see Configuration. For deployment strategies, see Docker Deployment.
Configuration Hierarchy and Loading¶
Amass follows a three-tier configuration hierarchy where later sources override earlier ones:
- YAML Configuration File - Primary configuration source
- Environment Variables - Override specific settings
- Command-Line Arguments - Highest priority overrides
Configuration File Resolution Order¶
The system searches for configuration files in the following order:
graph TD
CLI["CLI --config flag"] --> EnvVar["AMASS_CONFIG environment variable"]
EnvVar --> UserDir["$HOME/.config/amass/config.yaml"]
UserDir --> SystemDir["/etc/amass/config.yaml (Unix only)"]
SystemDir --> DefaultConfig["Use default in-memory config"]
CLI -->|"Found"| LoadConfig["Load Configuration"]
EnvVar -->|"Found"| LoadConfig
UserDir -->|"Found"| LoadConfig
SystemDir -->|"Found"| LoadConfig
DefaultConfig --> LoadConfig
LoadConfig --> ValidateScope["Validate Scope"]
LoadConfig --> ValidateResolvers["Validate Resolvers"]
LoadConfig --> ValidateTransforms["Validate Transformations"]
ValidateScope --> ReadyToRun["Configuration Ready"]
ValidateResolvers --> ReadyToRun
ValidateTransforms --> ReadyToRun
Best Practice: Multi-Environment Configuration¶
Structure your configuration files for different environments:
$HOME/.config/amass/
├── config.yaml # Default configuration
├── config.production.yaml # Production overrides
├── config.staging.yaml # Staging overrides
└── resolvers/
├── trusted.txt # Custom trusted resolvers
└── public.txt # Additional public resolvers
Use the AMASS_CONFIG environment variable to switch between environments:
amass enum -d example.com
export AMASS_CONFIG=$HOME/.config/amass/config.production.yaml
amass enum -d example.com
amass enum -config $HOME/.config/amass/config.staging.yaml -d example.com
Resolver Configuration Best Practices¶
Understanding Resolver Types¶
Amass uses two distinct resolver pools with different characteristics:
| Resolver Type | Default Count | Default QPS | Purpose | Source |
|---|---|---|---|---|
| Trusted (Baseline) | 17 hardcoded | 15 queries/sec | Primary resolution, validation | |
| Public | Fetched dynamically | 5 queries/sec | Load distribution, diversity |
graph LR
subgraph "Resolver Configuration"
ConfigYAML["config.yaml"] --> TrustedList["Trusted Resolvers<br/>17 baseline + custom"]
ConfigYAML --> PublicList["Public Resolvers<br/>From public-dns.info"]
TrustedList --> TrustedQPS["TrustedQPS: 15<br/>per resolver"]
PublicList --> PublicQPS["ResolversQPS: 5<br/>per resolver"]
TrustedQPS --> CalcMaxQPS["Config.CalcMaxQPS()"]
PublicQPS --> CalcMaxQPS
CalcMaxQPS --> MaxDNSQueries["Config.MaxDNSQueries<br/>= (trusted × 15) + (public × 5)"]
end
subgraph "Runtime Usage"
MaxDNSQueries --> DNSEngine["DNS Resolution Engine"]
DNSEngine --> WildcardDetector["Wildcard Detector<br/>Uses 8.8.4.4 only"]
end
Best Practice: Custom Resolver Lists¶
For production deployments, provide custom resolver lists to avoid reliance on external services:
config.yaml:
options:
resolvers:
- 8.8.8.8 # Direct IP address
- 1.1.1.1 # Direct IP address
- ./resolvers/custom-resolvers.txt # Relative path from config file
- /etc/amass/resolvers/prod.txt # Absolute path
resolvers/custom-resolvers.txt:
The configuration system handles both direct IP addresses and file paths, resolving relative paths from the config file location:
Best Practice: Resolver QPS Tuning¶
Adjust QPS rates based on your resolver infrastructure and rate limits:
Calculation formula:
Best Practice: Resolver Reliability Filtering¶
The public resolver fetcher automatically filters by reliability score:
This prevents unstable resolvers from polluting results. For custom resolver lists, validate reliability before adding:
Scope Management Best Practices¶
Rigid vs Flexible Boundaries¶
Amass supports two scope enforcement modes:
graph TB
subgraph "Flexible Mode (rigid: false)"
FlexInput["Input: example.com"]
FlexInput --> FlexDNS["DNS Discovery"]
FlexDNS --> FlexSubdomain["mail.example.com"]
FlexDNS --> FlexIP["203.0.113.10"]
FlexIP --> FlexReverse["PTR: shared.hosting.com"]
FlexReverse --> FlexExpand["Explore shared.hosting.com<br/>(out of original scope)"]
end
subgraph "Rigid Mode (rigid: true)"
RigidInput["Input: example.com"]
RigidInput --> RigidDNS["DNS Discovery"]
RigidDNS --> RigidSubdomain["mail.example.com"]
RigidDNS --> RigidIP["203.0.113.10"]
RigidIP --> RigidReverse["PTR: shared.hosting.com"]
RigidReverse --> RigidStop["Discard shared.hosting.com<br/>(out of scope)"]
end
Best Practice: Scope Definition for Different Use Cases¶
Targeted Assessment (Rigid Boundaries):
rigid_boundaries: true
scope:
domains:
- example.com
- example.net
cidrs:
- 203.0.113.0/24
asns:
- 64496
ports:
- 80
- 443
- 8080
- 8443
Comprehensive Discovery (Flexible Boundaries):
Best Practice: Blacklist Management¶
Use blacklists to exclude specific subdomains from enumeration:
scope:
domains:
- example.com
blacklist:
- cdn.example.com # Third-party CDN
- legacy-*.example.com # Pattern matching not supported
- test.example.com # Internal testing domain
Important: Blacklist entries must be exact matches. Pattern matching is not currently supported.
API Key and Secrets Management¶
Architecture for Credential Storage¶
graph TD
subgraph "Configuration Sources"
ConfigFile["config.yaml<br/>(API keys in plain text)"]
EnvVars["Environment Variables<br/>AMASS_CONFIG"]
SecretManager["Secret Manager<br/>(HashiCorp Vault, AWS Secrets)"]
end
subgraph "Amass Configuration Loading"
LoadConfig["Config.LoadSettings()"]
DataSrcConfigs["Config.DataSrcConfigs"]
LoadConfig --> ParseYAML["Parse YAML"]
ParseYAML --> LoadDataSourceSettings["loadDataSourceSettings()"]
LoadDataSourceSettings --> DataSrcConfigs
end
ConfigFile --> LoadConfig
EnvVars -->|"Override path"| LoadConfig
SecretManager -->|"Inject at runtime"| EnvVars
DataSrcConfigs --> Plugins["API Integration Plugins<br/>(GLEIF, Aviato, etc.)"]
Best Practice: Externalized Secrets¶
Development (config.yaml):
Production (Environment Variables + Template):
config.production.yaml (template):
Deployment script:
#!/bin/bash
export AVIATO_API_KEY=$(vault kv get -field=api_key secret/amass/aviato)
export GLEIF_API_KEY=$(vault kv get -field=api_key secret/amass/gleif)
envsubst < config.production.yaml.template > config.production.yaml
amass enum -config config.production.yaml -d example.com
rm config.production.yaml
Best Practice: Minimal Permission API Keys¶
Configure API keys with minimal required permissions:
| Data Source | Required Permissions | Rate Limit Considerations |
|---|---|---|
| GLEIF | Public read access | No key required for basic search |
| Aviato | Company search, employee read | 1000 requests/day on free tier |
| RDAP | No authentication | Rate limited by registry |
| BGP.Tools WHOIS | No authentication | Aggressive rate limiting |
Performance Tuning Best Practices¶
DNS Query Rate Optimization¶
graph LR
subgraph "Configuration Inputs"
TrustedCount["Trusted Resolvers<br/>Count: N"]
PublicCount["Public Resolvers<br/>Count: M"]
TrustedQPS["TrustedQPS<br/>Default: 15"]
PublicQPS["ResolversQPS<br/>Default: 5"]
end
subgraph "Calculation"
CalcMaxQPS["MaxDNSQueries =<br/>(N × TrustedQPS) + (M × PublicQPS)"]
end
subgraph "Impact"
EnumSpeed["Enumeration Speed"]
ResolverLoad["Resolver Load"]
FalsePositives["False Positive Rate"]
end
TrustedCount --> CalcMaxQPS
PublicCount --> CalcMaxQPS
TrustedQPS --> CalcMaxQPS
PublicQPS --> CalcMaxQPS
CalcMaxQPS -->|"Higher = Faster"| EnumSpeed
CalcMaxQPS -->|"Higher = More Load"| ResolverLoad
CalcMaxQPS -->|"Too High = Errors"| FalsePositives
Best Practice: Resource Allocation¶
Small Scope (1-10 domains):
Medium Scope (10-100 domains):
trusted_resolvers:
- 8.8.8.8
- 1.1.1.1
- 9.9.9.9
- 208.67.222.222
options:
resolvers:
- ./resolvers/additional-20.txt
Large Scope (100+ domains):
trusted_resolvers:
- ./resolvers/corporate-dns-pool.txt # 10 resolvers
options:
resolvers:
- ./resolvers/public-validated.txt # 50 resolvers
Best Practice: TTL Configuration¶
The MinimumTTL setting controls how long discovered data is cached:
options:
minimum_ttl: 1440 # 24 hours (default)
# minimum_ttl: 60 # 1 hour for rapidly changing infrastructure
# minimum_ttl: 10080 # 7 days for stable environments
Trade-offs:
| TTL Value | Pros | Cons |
|---|---|---|
| Low (60 min) | Fresh data, detects changes quickly | More DNS queries, slower enumeration |
| Medium (1440 min) | Balanced performance | May miss recent changes |
| High (10080 min) | Faster enumeration, reduced load | Stale data risk |
Transformation Configuration¶
Understanding the Transformation System¶
Transformations control how discovered assets flow through the processing pipeline:
graph TD
subgraph "Transformation Configuration"
DefaultTransform["DefaultTransformations<br/>TTL: 1440<br/>Confidence: 50<br/>Priority: 5"]
CustomTransform["Custom Transformations<br/>Per asset type"]
end
subgraph "Asset Processing"
IncomingAsset["Incoming Asset<br/>(FQDN, IP, etc.)"]
CheckTransform["Check Transformations map"]
ApplyDefault["Apply Default"]
ApplyCustom["Apply Custom"]
IncomingAsset --> CheckTransform
CheckTransform -->|"No match"| ApplyDefault
CheckTransform -->|"Match found"| ApplyCustom
end
subgraph "Transformation Properties"
TTL["TTL<br/>(cache duration)"]
Confidence["Confidence<br/>(trust score)"]
Priority["Priority<br/>(processing order)"]
end
DefaultTransform --> ApplyDefault
CustomTransform --> ApplyCustom
ApplyDefault --> TTL
ApplyDefault --> Confidence
ApplyDefault --> Priority
ApplyCustom --> TTL
ApplyCustom --> Confidence
ApplyCustom --> Priority
Best Practice: Asset-Specific Transformations¶
Configure different processing rules for different asset types:
transformations:
fqdn:
ttl: 1440 # 24 hours for domain names
confidence: 80 # High confidence in DNS data
priority: 1 # Process domains first
ip_address:
ttl: 2880 # 48 hours for IP addresses (more stable)
confidence: 90 # Very high confidence
priority: 3 # Process after domains
organization:
ttl: 10080 # 7 days for organization data
confidence: 70 # Medium confidence (fuzzy matching)
priority: 5 # Lower priority
Production Deployment Patterns¶
Pattern 1: Engine-as-a-Service¶
Run the engine as a persistent service, with ephemeral enumeration clients:
graph TB
subgraph "Production Infrastructure"
EngineService["amass engine<br/>(systemd/docker service)<br/>GraphQL API: :8080"]
GraphDB["Graph Database<br/>$HOME/.config/amass/"]
EngineService --> GraphDB
end
subgraph "Enumeration Clients"
CronJob["Cron Job<br/>Daily enum"]
ManualRun["Manual Investigation"]
CICD["CI/CD Pipeline"]
CronJob -->|"HTTP"| EngineService
ManualRun -->|"HTTP"| EngineService
CICD -->|"HTTP"| EngineService
end
subgraph "Analysis Tools"
OAMAssoc["oam_assoc<br/>(graph queries)"]
OAMTrack["oam_track<br/>(change detection)"]
OAMViz["oam_viz<br/>(visualization)"]
OAMAssoc --> GraphDB
OAMTrack --> GraphDB
OAMViz --> GraphDB
end
systemd service configuration:
[Unit]
Description=OWASP Amass Engine
After=network.target
[Service]
Type=simple
User=amass
Environment="AMASS_CONFIG=/etc/amass/config.production.yaml"
ExecStart=/usr/local/bin/amass engine
Restart=always
RestartSec=10
[Install]
WantedBy=multi-user.target
Pattern 2: Containerized Deployment¶
Mount configuration and data directories as volumes:
version: '3.8'
services:
amass-engine:
image: owaspamass/amass:latest
container_name: amass-engine
volumes:
- ./config:/root/.config/amass:ro
- ./data:/root/.config/amass/data
- ./resolvers:/etc/amass/resolvers:ro
environment:
- AMASS_CONFIG=/root/.config/amass/config.yaml
ports:
- "8080:8080"
restart: unless-stopped
amass-enum:
image: owaspamass/amass:latest
container_name: amass-enum
depends_on:
- amass-engine
command: enum -d example.com
volumes:
- ./config:/root/.config/amass:ro
- ./output:/output
Pattern 3: Configuration Validation Pipeline¶
Validate configuration before deployment:
#!/bin/bash
CONFIG_FILE="$1"
echo "Validating configuration: $CONFIG_FILE"
yamllint "$CONFIG_FILE" || exit 1
grep -E "^\s+- ./" "$CONFIG_FILE" | while read -r line; do
path=$(echo "$line" | sed 's/.*- //')
if [ ! -f "$path" ]; then
echo "ERROR: Referenced file not found: $path"
exit 1
fi
done
if grep -q "resolvers:" "$CONFIG_FILE"; then
echo "Testing resolver connectivity..."
# Extract and test each resolver
fi
echo "Configuration validation passed"
Common Pitfalls and Solutions¶
Pitfall 1: Relative Path Resolution¶
Problem: Relative paths in config fail when running from different directories.
Solution: Use absolute paths or understand resolution order:
options:
resolvers:
- resolvers/custom.txt
options:
resolvers:
- ./resolvers/custom.txt
options:
resolvers:
- /etc/amass/resolvers/custom.txt
The system resolves ./ paths relative to the config file's directory, not the working directory:
Pitfall 2: Insufficient Resolver Pool¶
Problem: Using only default resolvers causes rate limiting and slow enumeration.
Solution: Provision adequate resolver infrastructure:
trusted_resolvers:
- 8.8.8.8
- 1.1.1.1
# Add more trusted resolvers
options:
resolvers:
- ./resolvers/validated-public.txt # 50+ resolvers
Pitfall 3: Scope Creep with Flexible Boundaries¶
Problem: Flexible boundaries discover too many unrelated assets.
Solution: Use seed/scope separation:
seed:
domains:
- example.com
scope:
domains:
- example.com
- "*.example.com"
cidrs:
- 203.0.113.0/24
rigid_boundaries: true
Pitfall 4: Missing Output Directory Permissions¶
Problem: Amass fails to create database files due to permission errors.
Solution: Ensure output directory exists with correct permissions:
mkdir -p $HOME/.config/amass
chmod 755 $HOME/.config/amass
mkdir -p /var/lib/amass
chown amass:amass /var/lib/amass
The system automatically creates the output directory if it doesn't exist:
Pitfall 5: Transformation Map Misconfig¶
Problem: No transformations defined causes assets to be ignored.
Solution: Ensure default transformations cover all asset types:
transformations:
default:
ttl: 1440
confidence: 50
priority: 5
# Override for specific types
fqdn:
ttl: 720
confidence: 80
priority: 1
If no transformation is defined for an asset type, it falls back to DefaultTransformations:
Configuration Checklist¶
Use this checklist before production deployment:
- Configuration File
- Valid YAML syntax
- All file paths exist and are accessible
-
No hardcoded secrets in version control
-
Resolvers
- At least 5 trusted resolvers configured
- Resolver files validated (all valid IPs)
- QPS tuned for infrastructure capacity
-
MaxDNSQueries calculated and appropriate
-
Scope
- Domains explicitly listed
- CIDRs and ASNs verified
- Blacklist populated if needed
-
Rigid boundaries setting appropriate for use case
-
API Keys
- Stored in external secret manager
- Minimal permissions configured
-
Rate limits understood and monitored
-
Performance
- MinimumTTL appropriate for update frequency
- Transformation priorities set correctly
-
Resource allocation matches scope size
-
Infrastructure
- Output directory exists with correct permissions
- Sufficient disk space for graph database
- Network access to required APIs
- DNS resolver connectivity verified