Files
nuclei-operator/docs/user-guide.md
Morten Olsen 277fc459d5 init
2025-12-12 11:10:01 +01:00

762 lines
17 KiB
Markdown

# User Guide
This guide provides detailed instructions for using the Nuclei Operator to automate security scanning of your Kubernetes applications.
## Table of Contents
- [Introduction](#introduction)
- [Installation](#installation)
- [Basic Usage](#basic-usage)
- [Configuration Options](#configuration-options)
- [Working with Ingress Resources](#working-with-ingress-resources)
- [Working with VirtualService Resources](#working-with-virtualservice-resources)
- [Scheduled Scans](#scheduled-scans)
- [Viewing Scan Results](#viewing-scan-results)
- [Best Practices](#best-practices)
- [Security Considerations](#security-considerations)
- [Troubleshooting](#troubleshooting)
---
## Introduction
The Nuclei Operator automates security scanning by watching for Kubernetes Ingress and Istio VirtualService resources. When a new resource is created or updated, the operator automatically:
1. Extracts target URLs from the resource
2. Creates a NucleiScan custom resource
3. Executes a Nuclei security scan
4. Stores the results in the NucleiScan status
This enables continuous security monitoring of your web applications without manual intervention.
---
## Installation
### Prerequisites
Before installing the Nuclei Operator, ensure you have:
- A Kubernetes cluster (v1.26 or later)
- `kubectl` configured to access your cluster
- Cluster admin permissions (for CRD installation)
### Quick Installation
```bash
# Clone the repository
git clone https://github.com/mortenolsen/nuclei-operator.git
cd nuclei-operator
# Install CRDs
make install
# Deploy the operator
make deploy IMG=ghcr.io/mortenolsen/nuclei-operator:latest
```
### Verify Installation
```bash
# Check that the operator is running
kubectl get pods -n nuclei-operator-system
# Verify CRDs are installed
kubectl get crd nucleiscans.nuclei.homelab.mortenolsen.pro
```
Expected output:
```
NAME CREATED AT
nucleiscans.nuclei.homelab.mortenolsen.pro 2024-01-15T10:00:00Z
```
---
## Basic Usage
### Automatic Scanning via Ingress
The simplest way to use the operator is to create an Ingress resource. The operator will automatically create a NucleiScan.
**Step 1: Create an Ingress**
```yaml
# my-app-ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: my-app
namespace: default
spec:
tls:
- hosts:
- myapp.example.com
secretName: myapp-tls
rules:
- host: myapp.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: my-app
port:
number: 80
```
```bash
kubectl apply -f my-app-ingress.yaml
```
**Step 2: View the Created NucleiScan**
```bash
# List NucleiScans
kubectl get nucleiscans
# View details
kubectl describe nucleiscan my-app-scan
```
### Manual NucleiScan Creation
You can also create NucleiScan resources manually for more control:
```yaml
# manual-scan.yaml
apiVersion: nuclei.homelab.mortenolsen.pro/v1alpha1
kind: NucleiScan
metadata:
name: manual-security-scan
namespace: default
spec:
sourceRef:
apiVersion: networking.k8s.io/v1
kind: Ingress
name: my-app
namespace: default
uid: "your-ingress-uid" # Get with: kubectl get ingress my-app -o jsonpath='{.metadata.uid}'
targets:
- https://myapp.example.com
severity:
- high
- critical
```
```bash
kubectl apply -f manual-scan.yaml
```
---
## Configuration Options
### Severity Filtering
Filter scan results by severity level:
```yaml
spec:
severity:
- info # Informational findings
- low # Low severity
- medium # Medium severity
- high # High severity
- critical # Critical severity
```
**Recommended configurations:**
| Use Case | Severity Levels |
|----------|-----------------|
| Production monitoring | `medium`, `high`, `critical` |
| Security audit | `info`, `low`, `medium`, `high`, `critical` |
| Quick check | `high`, `critical` |
### Template Selection
Specify which Nuclei templates to use:
```yaml
spec:
templates:
- cves/ # CVE checks
- vulnerabilities/ # General vulnerabilities
- exposures/ # Exposed services/files
- misconfiguration/ # Misconfigurations
- default-logins/ # Default credentials
- takeovers/ # Subdomain takeovers
```
**Template categories:**
| Category | Description |
|----------|-------------|
| `cves/` | Known CVE vulnerabilities |
| `vulnerabilities/` | General vulnerability checks |
| `exposures/` | Exposed sensitive files and services |
| `misconfiguration/` | Security misconfigurations |
| `default-logins/` | Default credential checks |
| `takeovers/` | Subdomain takeover vulnerabilities |
| `technologies/` | Technology detection |
| `ssl/` | SSL/TLS issues |
### Environment Variables
Configure the operator using environment variables in the deployment:
```yaml
# In config/manager/manager.yaml
env:
- name: NUCLEI_BINARY_PATH
value: "/usr/local/bin/nuclei"
- name: NUCLEI_TEMPLATES_PATH
value: "/nuclei-templates"
- name: NUCLEI_TIMEOUT
value: "30m"
```
| Variable | Description | Default |
|----------|-------------|---------|
| `NUCLEI_BINARY_PATH` | Path to Nuclei binary | `nuclei` |
| `NUCLEI_TEMPLATES_PATH` | Custom templates directory | (Nuclei default) |
| `NUCLEI_TIMEOUT` | Scan timeout duration | `30m` |
---
## Working with Ingress Resources
### URL Extraction
The operator extracts URLs from Ingress resources based on:
1. **TLS configuration**: Hosts in `spec.tls[].hosts` are scanned with HTTPS
2. **Rules**: Hosts in `spec.rules[].host` are scanned
3. **Paths**: Individual paths from `spec.rules[].http.paths[]` are included
**Example Ingress:**
```yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: multi-path-app
spec:
tls:
- hosts:
- secure.example.com
secretName: secure-tls
rules:
- host: secure.example.com
http:
paths:
- path: /api
pathType: Prefix
backend:
service:
name: api-service
port:
number: 8080
- path: /admin
pathType: Prefix
backend:
service:
name: admin-service
port:
number: 8081
- host: public.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: public-service
port:
number: 80
```
**Extracted URLs:**
- `https://secure.example.com/api`
- `https://secure.example.com/admin`
- `http://public.example.com/`
### Naming Convention
NucleiScan resources are named based on the Ingress:
```
<ingress-name>-scan
```
For example, an Ingress named `my-app` creates a NucleiScan named `my-app-scan`.
### Owner References
The operator sets owner references on NucleiScan resources, enabling:
- **Automatic cleanup**: When an Ingress is deleted, its NucleiScan is also deleted
- **Relationship tracking**: Easy identification of which Ingress created which scan
---
## Working with VirtualService Resources
### Prerequisites
VirtualService support requires Istio to be installed in your cluster.
### URL Extraction
The operator extracts URLs from VirtualService resources based on:
1. **Hosts**: All hosts in `spec.hosts[]`
2. **HTTP routes**: Paths from `spec.http[].match[].uri`
**Example VirtualService:**
```yaml
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
name: my-istio-app
namespace: default
spec:
hosts:
- myapp.example.com
gateways:
- my-gateway
http:
- match:
- uri:
prefix: /api
route:
- destination:
host: api-service
port:
number: 8080
- match:
- uri:
prefix: /web
route:
- destination:
host: web-service
port:
number: 80
```
**Extracted URLs:**
- `https://myapp.example.com/api`
- `https://myapp.example.com/web`
### Naming Convention
NucleiScan resources for VirtualServices follow the same pattern:
```
<virtualservice-name>-scan
```
---
## Scheduled Scans
### Enabling Scheduled Scans
Add a `schedule` field to run scans periodically:
```yaml
spec:
schedule: "@every 24h"
```
### Schedule Formats
**Simplified interval format:**
| Format | Description |
|--------|-------------|
| `@every 1h` | Every hour |
| `@every 6h` | Every 6 hours |
| `@every 24h` | Every 24 hours |
| `@every 168h` | Every week |
**Standard cron format:**
```
┌───────────── minute (0 - 59)
│ ┌───────────── hour (0 - 23)
│ │ ┌───────────── day of month (1 - 31)
│ │ │ ┌───────────── month (1 - 12)
│ │ │ │ ┌───────────── day of week (0 - 6) (Sunday = 0)
│ │ │ │ │
* * * * *
```
**Examples:**
| Schedule | Description |
|----------|-------------|
| `0 2 * * *` | Daily at 2:00 AM |
| `0 */6 * * *` | Every 6 hours |
| `0 3 * * 0` | Weekly on Sunday at 3:00 AM |
| `0 0 1 * *` | Monthly on the 1st at midnight |
### Suspending Scheduled Scans
Temporarily pause scheduled scans without deleting the resource:
```yaml
spec:
schedule: "@every 24h"
suspend: true # Scans are paused
```
To resume:
```bash
kubectl patch nucleiscan my-scan -p '{"spec":{"suspend":false}}'
```
### Viewing Next Scheduled Time
```bash
kubectl get nucleiscan my-scan -o jsonpath='{.status.nextScheduledTime}'
```
---
## Viewing Scan Results
### List All Scans
```bash
# Basic listing
kubectl get nucleiscans
# With additional details
kubectl get nucleiscans -o wide
# In all namespaces
kubectl get nucleiscans -A
```
### View Scan Details
```bash
# Full details
kubectl describe nucleiscan my-app-scan
# JSON output
kubectl get nucleiscan my-app-scan -o json
# YAML output
kubectl get nucleiscan my-app-scan -o yaml
```
### Extract Specific Information
```bash
# Get scan phase
kubectl get nucleiscan my-app-scan -o jsonpath='{.status.phase}'
# Get total findings count
kubectl get nucleiscan my-app-scan -o jsonpath='{.status.summary.totalFindings}'
# Get findings by severity
kubectl get nucleiscan my-app-scan -o jsonpath='{.status.summary.findingsBySeverity}'
# Get all findings
kubectl get nucleiscan my-app-scan -o jsonpath='{.status.findings}' | jq .
# Get critical findings only
kubectl get nucleiscan my-app-scan -o json | jq '.status.findings[] | select(.severity == "critical")'
```
### Export Results
```bash
# Export to JSON file
kubectl get nucleiscan my-app-scan -o json > scan-results.json
# Export findings only
kubectl get nucleiscan my-app-scan -o jsonpath='{.status.findings}' > findings.json
# Export as CSV (using jq)
kubectl get nucleiscan my-app-scan -o json | jq -r '.status.findings[] | [.templateId, .severity, .host, .matchedAt] | @csv' > findings.csv
```
### Watch Scan Progress
```bash
# Watch scan status changes
kubectl get nucleiscans -w
# Watch specific scan
watch kubectl get nucleiscan my-app-scan
```
---
## Best Practices
### 1. Use Severity Filters in Production
Avoid scanning for `info` level findings in production to reduce noise:
```yaml
spec:
severity:
- medium
- high
- critical
```
### 2. Schedule Scans During Off-Peak Hours
Run scheduled scans during low-traffic periods:
```yaml
spec:
schedule: "0 3 * * *" # 3 AM daily
```
### 3. Use Namespaces for Organization
Organize scans by environment or team:
```bash
# Development scans
kubectl get nucleiscans -n development
# Production scans
kubectl get nucleiscans -n production
```
### 4. Label Your Resources
Add labels for better organization and filtering:
```yaml
metadata:
labels:
environment: production
team: security
compliance: pci-dss
```
```bash
# Filter by label
kubectl get nucleiscans -l environment=production
```
### 5. Monitor Scan Failures
Set up alerts for failed scans:
```bash
# Find failed scans
kubectl get nucleiscans --field-selector status.phase=Failed
```
### 6. Regular Template Updates
Keep Nuclei templates updated for the latest vulnerability checks. The operator uses the templates bundled in the container image.
### 7. Resource Limits
Ensure the operator has appropriate resource limits:
```yaml
resources:
limits:
cpu: 500m
memory: 512Mi
requests:
cpu: 100m
memory: 128Mi
```
---
## Security Considerations
### Network Access
The operator needs network access to scan targets. Consider:
1. **Network Policies**: Ensure the operator can reach scan targets
2. **Egress Rules**: Allow outbound traffic to target hosts
3. **Internal vs External**: Be aware of scanning internal vs external endpoints
### RBAC Permissions
The operator requires specific permissions:
- **Read** Ingress and VirtualService resources
- **Full control** over NucleiScan resources
- **Create** events for logging
Review the RBAC configuration in `config/rbac/role.yaml`.
### Scan Impact
Consider the impact of security scans:
1. **Rate Limiting**: Nuclei respects rate limits, but be aware of target capacity
2. **WAF/IDS Alerts**: Scans may trigger security alerts on targets
3. **Logging**: Scan traffic will appear in target access logs
### Sensitive Data
Scan results may contain sensitive information:
1. **Access Control**: Restrict access to NucleiScan resources
2. **Data Retention**: Consider cleanup policies for old scan results
3. **Audit Logging**: Enable Kubernetes audit logging for compliance
### Container Security
The operator container includes the Nuclei binary:
1. **Image Updates**: Regularly update the operator image
2. **Vulnerability Scanning**: Scan the operator image itself
3. **Non-root User**: The operator runs as a non-root user
---
## Troubleshooting
### Scan Stuck in Pending
**Symptoms:** NucleiScan remains in `Pending` phase
**Solutions:**
1. Check operator logs:
```bash
kubectl logs -n nuclei-operator-system deployment/nuclei-operator-controller-manager
```
2. Verify the operator is running:
```bash
kubectl get pods -n nuclei-operator-system
```
3. Check for resource constraints:
```bash
kubectl describe pod -n nuclei-operator-system -l control-plane=controller-manager
```
### Scan Failed
**Symptoms:** NucleiScan shows `Failed` phase
**Solutions:**
1. Check the error message:
```bash
kubectl get nucleiscan my-scan -o jsonpath='{.status.lastError}'
```
2. Common errors:
- **Timeout**: Increase timeout or reduce targets
- **Network error**: Check connectivity to targets
- **Binary not found**: Verify Nuclei is installed in the container
3. Retry the scan:
```bash
# Trigger a new scan by updating the spec
kubectl patch nucleiscan my-scan -p '{"spec":{"targets":["https://example.com"]}}'
```
### No NucleiScan Created for Ingress
**Symptoms:** Ingress exists but no NucleiScan is created
**Solutions:**
1. Verify the Ingress has hosts defined:
```bash
kubectl get ingress my-ingress -o jsonpath='{.spec.rules[*].host}'
```
2. Check operator RBAC:
```bash
kubectl auth can-i list ingresses --as=system:serviceaccount:nuclei-operator-system:nuclei-operator-controller-manager
```
3. Check operator logs for errors:
```bash
kubectl logs -n nuclei-operator-system deployment/nuclei-operator-controller-manager | grep -i error
```
### Empty Scan Results
**Symptoms:** Scan completes but has no findings
**Possible causes:**
1. **Targets not accessible**: Verify targets are reachable from the operator pod
2. **Severity filter too strict**: Try including more severity levels
3. **Templates not matching**: Ensure templates are appropriate for the targets
**Verification:**
```bash
# Test connectivity from operator pod
kubectl exec -n nuclei-operator-system deployment/nuclei-operator-controller-manager -- curl -I https://your-target.com
```
### High Resource Usage
**Symptoms:** Operator consuming excessive CPU/memory
**Solutions:**
1. Reduce concurrent scans by adjusting controller concurrency
2. Increase resource limits:
```yaml
resources:
limits:
cpu: 1000m
memory: 1Gi
```
3. Reduce scan scope (fewer targets or templates)
### Scheduled Scans Not Running
**Symptoms:** Scheduled scan time passes but scan doesn't start
**Solutions:**
1. Verify scan is not suspended:
```bash
kubectl get nucleiscan my-scan -o jsonpath='{.spec.suspend}'
```
2. Check the schedule format:
```bash
kubectl get nucleiscan my-scan -o jsonpath='{.spec.schedule}'
```
3. Verify next scheduled time:
```bash
kubectl get nucleiscan my-scan -o jsonpath='{.status.nextScheduledTime}'
```
### Getting Help
If you're still experiencing issues:
1. Check the [GitHub Issues](https://github.com/mortenolsen/nuclei-operator/issues)
2. Review the [Architecture documentation](../ARCHITECTURE.md)
3. Enable debug logging and collect logs
4. Open a new issue with:
- Kubernetes version
- Operator version
- Relevant resource YAML (sanitized)
- Operator logs
- Steps to reproduce