mirror of
https://github.com/morten-olsen/homelab-nuclei-operator.git
synced 2026-02-08 02:16:23 +01:00
This major refactor moves from synchronous subprocess-based scanning to asynchronous pod-based scanning using Kubernetes Jobs. ## Architecture Changes - Scanner jobs are now Kubernetes Jobs with TTLAfterFinished for automatic cleanup - Jobs have owner references for garbage collection when NucleiScan is deleted - Configurable concurrency limits, timeouts, and resource requirements ## New Features - Dual-mode binary: --mode=controller (default) or --mode=scanner - Annotation-based configuration for Ingress/VirtualService resources - Operator-level configuration via environment variables - Startup recovery for orphaned scans after operator restart - Periodic cleanup of stuck jobs ## New Files - DESIGN.md: Comprehensive architecture design document - internal/jobmanager/: Job Manager for creating/monitoring scanner jobs - internal/scanner/runner.go: Scanner mode implementation - internal/annotations/: Annotation parsing utilities - charts/nuclei-operator/templates/scanner-rbac.yaml: Scanner RBAC ## API Changes - Added ScannerConfig struct for per-scan scanner configuration - Added JobReference struct for tracking scanner jobs - Added ScannerConfig field to NucleiScanSpec - Added JobRef and ScanStartTime fields to NucleiScanStatus ## Supported Annotations - nuclei.homelab.mortenolsen.pro/enabled - nuclei.homelab.mortenolsen.pro/templates - nuclei.homelab.mortenolsen.pro/severity - nuclei.homelab.mortenolsen.pro/schedule - nuclei.homelab.mortenolsen.pro/timeout - nuclei.homelab.mortenolsen.pro/scanner-image ## RBAC Updates - Added Job and Pod permissions for operator - Created separate scanner service account with minimal permissions ## Documentation - Updated README, user-guide, api.md, and Helm chart README - Added example annotated Ingress resources
984 lines
26 KiB
Markdown
984 lines
26 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)
|
|
- [Scanner Architecture](#scanner-architecture)
|
|
- [Annotation-Based Configuration](#annotation-based-configuration)
|
|
- [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. Creates a Kubernetes Job to execute the Nuclei security scan in an isolated pod
|
|
4. Stores the results in the NucleiScan status
|
|
|
|
This enables continuous security monitoring of your web applications without manual intervention.
|
|
|
|
The operator uses a **pod-based scanning architecture** where each scan runs in its own isolated Kubernetes Job, providing better scalability, reliability, and resource control.
|
|
|
|
---
|
|
|
|
## 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
|
|
```
|
|
|
|
---
|
|
|
|
## Scanner Architecture
|
|
|
|
The nuclei-operator uses a pod-based scanning architecture for improved scalability and reliability:
|
|
|
|
1. **Operator Pod**: Manages NucleiScan resources and creates scanner jobs
|
|
2. **Scanner Jobs**: Kubernetes Jobs that execute nuclei scans in isolated pods
|
|
3. **Direct Status Updates**: Scanner pods update NucleiScan status directly via the Kubernetes API
|
|
|
|
### Architecture Diagram
|
|
|
|
```
|
|
┌─────────────────────────────────────────────────────────────────────┐
|
|
│ Kubernetes Cluster │
|
|
│ │
|
|
│ ┌──────────────────┐ ┌──────────────────────────────────────┐ │
|
|
│ │ Operator Pod │ │ Scanner Jobs │ │
|
|
│ │ │ │ │ │
|
|
│ │ ┌────────────┐ │ │ ┌─────────┐ ┌─────────┐ │ │
|
|
│ │ │ Controller │──┼─────┼─▶│ Job 1 │ │ Job 2 │ ... │ │
|
|
│ │ │ Manager │ │ │ │(Scanner)│ │(Scanner)│ │ │
|
|
│ │ └────────────┘ │ │ └────┬────┘ └────┬────┘ │ │
|
|
│ │ │ │ │ │ │ │ │
|
|
│ └────────┼─────────┘ └───────┼────────────┼─────────────────┘ │
|
|
│ │ │ │ │
|
|
│ ▼ ▼ ▼ │
|
|
│ ┌──────────────────────────────────────────────────────────────┐ │
|
|
│ │ Kubernetes API Server │ │
|
|
│ │ │ │
|
|
│ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │
|
|
│ │ │ NucleiScan │ │ NucleiScan │ │ NucleiScan │ ... │ │
|
|
│ │ │ Resource │ │ Resource │ │ Resource │ │ │
|
|
│ │ └─────────────┘ └─────────────┘ └─────────────┘ │ │
|
|
│ └──────────────────────────────────────────────────────────────┘ │
|
|
│ │
|
|
└─────────────────────────────────────────────────────────────────────┘
|
|
```
|
|
|
|
### Benefits
|
|
|
|
- **Scalability**: Multiple scans can run concurrently across the cluster
|
|
- **Isolation**: Each scan runs in its own pod with dedicated resources
|
|
- **Reliability**: Scans survive operator restarts
|
|
- **Resource Control**: Per-scan resource limits and quotas
|
|
- **Observability**: Individual pod logs for each scan
|
|
|
|
### Scanner Configuration
|
|
|
|
Configure scanner behavior via Helm values:
|
|
|
|
```yaml
|
|
scanner:
|
|
# Enable scanner RBAC resources
|
|
enabled: true
|
|
|
|
# Scanner image (defaults to operator image)
|
|
image: "ghcr.io/morten-olsen/nuclei-operator:latest"
|
|
|
|
# Default scan timeout
|
|
timeout: "30m"
|
|
|
|
# Maximum concurrent scan jobs
|
|
maxConcurrent: 5
|
|
|
|
# Job TTL after completion (seconds)
|
|
ttlAfterFinished: 3600
|
|
|
|
# Default resource requirements for scanner pods
|
|
resources:
|
|
requests:
|
|
cpu: 100m
|
|
memory: 256Mi
|
|
limits:
|
|
cpu: "1"
|
|
memory: 1Gi
|
|
|
|
# Default templates to use
|
|
defaultTemplates: []
|
|
|
|
# Default severity filter
|
|
defaultSeverity: []
|
|
```
|
|
|
|
### Per-Scan Scanner Configuration
|
|
|
|
You can override scanner settings for individual scans using the `scannerConfig` field in the NucleiScan spec:
|
|
|
|
```yaml
|
|
apiVersion: nuclei.homelab.mortenolsen.pro/v1alpha1
|
|
kind: NucleiScan
|
|
metadata:
|
|
name: custom-scan
|
|
spec:
|
|
sourceRef:
|
|
apiVersion: networking.k8s.io/v1
|
|
kind: Ingress
|
|
name: my-ingress
|
|
namespace: default
|
|
uid: "abc123"
|
|
targets:
|
|
- https://example.com
|
|
scannerConfig:
|
|
# Override scanner image
|
|
image: "custom-scanner:latest"
|
|
# Override timeout
|
|
timeout: "1h"
|
|
# Custom resource requirements
|
|
resources:
|
|
requests:
|
|
cpu: 200m
|
|
memory: 512Mi
|
|
limits:
|
|
cpu: "2"
|
|
memory: 2Gi
|
|
# Node selector for scanner pod
|
|
nodeSelector:
|
|
node-type: scanner
|
|
# Tolerations for scanner pod
|
|
tolerations:
|
|
- key: "scanner"
|
|
operator: "Equal"
|
|
value: "true"
|
|
effect: "NoSchedule"
|
|
```
|
|
|
|
---
|
|
|
|
## Annotation-Based Configuration
|
|
|
|
You can configure scanning behavior for individual Ingress or VirtualService resources using annotations.
|
|
|
|
### Supported Annotations
|
|
|
|
| Annotation | Type | Default | Description |
|
|
|------------|------|---------|-------------|
|
|
| `nuclei.homelab.mortenolsen.pro/enabled` | bool | `true` | Enable/disable scanning for this resource |
|
|
| `nuclei.homelab.mortenolsen.pro/templates` | string | - | Comma-separated list of template paths or tags |
|
|
| `nuclei.homelab.mortenolsen.pro/severity` | string | - | Comma-separated severity filter: info,low,medium,high,critical |
|
|
| `nuclei.homelab.mortenolsen.pro/schedule` | string | - | Cron schedule for periodic scans |
|
|
| `nuclei.homelab.mortenolsen.pro/timeout` | duration | `30m` | Scan timeout |
|
|
| `nuclei.homelab.mortenolsen.pro/scanner-image` | string | - | Override scanner image |
|
|
| `nuclei.homelab.mortenolsen.pro/exclude-templates` | string | - | Templates to exclude |
|
|
| `nuclei.homelab.mortenolsen.pro/tags` | string | - | Template tags to include |
|
|
| `nuclei.homelab.mortenolsen.pro/exclude-tags` | string | - | Template tags to exclude |
|
|
|
|
### Example Annotated Ingress
|
|
|
|
```yaml
|
|
apiVersion: networking.k8s.io/v1
|
|
kind: Ingress
|
|
metadata:
|
|
name: myapp-ingress
|
|
annotations:
|
|
nuclei.homelab.mortenolsen.pro/enabled: "true"
|
|
nuclei.homelab.mortenolsen.pro/severity: "medium,high,critical"
|
|
nuclei.homelab.mortenolsen.pro/schedule: "0 2 * * *"
|
|
nuclei.homelab.mortenolsen.pro/templates: "cves/,vulnerabilities/"
|
|
spec:
|
|
rules:
|
|
- host: myapp.example.com
|
|
http:
|
|
paths:
|
|
- path: /
|
|
pathType: Prefix
|
|
backend:
|
|
service:
|
|
name: myapp
|
|
port:
|
|
number: 80
|
|
```
|
|
|
|
### Example Annotated VirtualService
|
|
|
|
```yaml
|
|
apiVersion: networking.istio.io/v1beta1
|
|
kind: VirtualService
|
|
metadata:
|
|
name: myapp-vs
|
|
annotations:
|
|
nuclei.homelab.mortenolsen.pro/enabled: "true"
|
|
nuclei.homelab.mortenolsen.pro/severity: "high,critical"
|
|
nuclei.homelab.mortenolsen.pro/timeout: "1h"
|
|
nuclei.homelab.mortenolsen.pro/tags: "cve,oast"
|
|
spec:
|
|
hosts:
|
|
- myapp.example.com
|
|
gateways:
|
|
- my-gateway
|
|
http:
|
|
- route:
|
|
- destination:
|
|
host: myapp
|
|
port:
|
|
number: 80
|
|
```
|
|
|
|
### Disabling Scanning
|
|
|
|
To disable scanning for a specific resource:
|
|
|
|
```yaml
|
|
metadata:
|
|
annotations:
|
|
nuclei.homelab.mortenolsen.pro/enabled: "false"
|
|
```
|
|
|
|
This is useful when you want to temporarily exclude certain resources from scanning without removing them from the cluster.
|
|
|
|
### Annotation Precedence
|
|
|
|
When both annotations and NucleiScan spec fields are present, the following precedence applies:
|
|
|
|
1. **NucleiScan spec fields** (highest priority) - Direct configuration in the NucleiScan resource
|
|
2. **Annotations** - Configuration from the source Ingress/VirtualService
|
|
3. **Helm values** - Default configuration from the operator deployment
|
|
4. **Built-in defaults** (lowest priority) - Hardcoded defaults in the operator
|
|
|
|
---
|
|
|
|
## 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 |