This commit is contained in:
Morten Olsen
2025-12-12 11:10:01 +01:00
commit 277fc459d5
64 changed files with 8625 additions and 0 deletions

514
docs/api.md Normal file
View File

@@ -0,0 +1,514 @@
# API Reference
This document provides a complete reference for the Nuclei Operator Custom Resource Definitions (CRDs).
## Table of Contents
- [NucleiScan](#nucleiscan)
- [Metadata](#metadata)
- [Spec](#spec)
- [Status](#status)
- [Type Definitions](#type-definitions)
- [SourceReference](#sourcereference)
- [Finding](#finding)
- [ScanSummary](#scansummary)
- [ScanPhase](#scanphase)
- [Examples](#examples)
---
## NucleiScan
`NucleiScan` is the primary custom resource for the Nuclei Operator. It represents a security scan configuration and stores the scan results.
**API Group:** `nuclei.homelab.mortenolsen.pro`
**API Version:** `v1alpha1`
**Kind:** `NucleiScan`
**Short Names:** `ns`, `nscan`
### Metadata
Standard Kubernetes metadata fields apply. The operator automatically sets owner references when creating NucleiScan resources from Ingress or VirtualService resources.
| Field | Type | Description |
|-------|------|-------------|
| `name` | string | Unique name within the namespace |
| `namespace` | string | Namespace where the resource resides |
| `labels` | map[string]string | Labels for organizing and selecting resources |
| `annotations` | map[string]string | Annotations for storing additional metadata |
| `ownerReferences` | []OwnerReference | References to owner resources (set automatically) |
### Spec
The `spec` field defines the desired state of the NucleiScan.
```yaml
spec:
sourceRef:
apiVersion: networking.k8s.io/v1
kind: Ingress
name: my-ingress
namespace: default
uid: "abc123-def456"
targets:
- https://example.com
- https://api.example.com
templates:
- cves/
- vulnerabilities/
severity:
- medium
- high
- critical
schedule: "@every 24h"
suspend: false
```
#### Spec Fields
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `sourceRef` | [SourceReference](#sourcereference) | Yes | Reference to the source Ingress or VirtualService |
| `targets` | []string | Yes | List of URLs to scan (minimum 1) |
| `templates` | []string | No | Nuclei templates to use. If empty, uses default templates |
| `severity` | []string | No | Severity filter. Valid values: `info`, `low`, `medium`, `high`, `critical` |
| `schedule` | string | No | Cron schedule for periodic rescanning |
| `suspend` | bool | No | When true, suspends scheduled scans |
#### Schedule Format
The `schedule` field supports two formats:
1. **Simplified interval format:**
- `@every <duration>` - e.g., `@every 24h`, `@every 6h`, `@every 30m`
2. **Standard cron format:**
- `* * * * *` - minute, hour, day of month, month, day of week
- Examples:
- `0 2 * * *` - Daily at 2:00 AM
- `0 */6 * * *` - Every 6 hours
- `0 3 * * 0` - Weekly on Sunday at 3:00 AM
### Status
The `status` field contains the observed state of the NucleiScan, including scan results.
```yaml
status:
phase: Completed
conditions:
- type: Ready
status: "True"
reason: ScanCompleted
message: "Scan completed with 3 findings"
lastTransitionTime: "2024-01-15T10:35:00Z"
- type: ScanActive
status: "False"
reason: ScanCompleted
message: "Scan completed successfully"
lastTransitionTime: "2024-01-15T10:35:00Z"
lastScanTime: "2024-01-15T10:30:00Z"
completionTime: "2024-01-15T10:35:00Z"
nextScheduledTime: "2024-01-16T10:30:00Z"
summary:
totalFindings: 3
findingsBySeverity:
medium: 2
high: 1
targetsScanned: 2
durationSeconds: 300
findings:
- templateId: CVE-2021-44228
templateName: Apache Log4j RCE
severity: critical
type: http
host: https://example.com
matchedAt: https://example.com/api/login
timestamp: "2024-01-15T10:32:00Z"
lastError: ""
observedGeneration: 1
```
#### Status Fields
| Field | Type | Description |
|-------|------|-------------|
| `phase` | [ScanPhase](#scanphase) | Current phase of the scan |
| `conditions` | []Condition | Standard Kubernetes conditions |
| `lastScanTime` | *Time | When the last scan was initiated |
| `completionTime` | *Time | When the last scan completed |
| `nextScheduledTime` | *Time | When the next scheduled scan will run |
| `summary` | *[ScanSummary](#scansummary) | Aggregated scan statistics |
| `findings` | [][Finding](#finding) | Array of scan results |
| `lastError` | string | Error message if the scan failed |
| `observedGeneration` | int64 | Generation observed by the controller |
#### Conditions
The operator maintains the following condition types:
| Type | Description |
|------|-------------|
| `Ready` | Indicates whether the scan has completed successfully |
| `ScanActive` | Indicates whether a scan is currently running |
**Condition Reasons:**
| Reason | Description |
|--------|-------------|
| `ScanPending` | Scan is waiting to start |
| `ScanRunning` | Scan is currently in progress |
| `ScanCompleted` | Scan completed successfully |
| `ScanFailed` | Scan failed with an error |
| `ScanSuspended` | Scan is suspended |
---
## Type Definitions
### SourceReference
`SourceReference` identifies the Ingress or VirtualService that triggered the scan.
```go
type SourceReference struct {
APIVersion string `json:"apiVersion"`
Kind string `json:"kind"`
Name string `json:"name"`
Namespace string `json:"namespace"`
UID string `json:"uid"`
}
```
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `apiVersion` | string | Yes | API version of the source resource (e.g., `networking.k8s.io/v1`) |
| `kind` | string | Yes | Kind of the source resource. Valid values: `Ingress`, `VirtualService` |
| `name` | string | Yes | Name of the source resource |
| `namespace` | string | Yes | Namespace of the source resource |
| `uid` | string | Yes | UID of the source resource |
### Finding
`Finding` represents a single vulnerability or issue discovered during a scan.
```go
type Finding struct {
TemplateID string `json:"templateId"`
TemplateName string `json:"templateName,omitempty"`
Severity string `json:"severity"`
Type string `json:"type,omitempty"`
Host string `json:"host"`
MatchedAt string `json:"matchedAt,omitempty"`
ExtractedResults []string `json:"extractedResults,omitempty"`
Description string `json:"description,omitempty"`
Reference []string `json:"reference,omitempty"`
Tags []string `json:"tags,omitempty"`
Timestamp metav1.Time `json:"timestamp"`
Metadata *runtime.RawExtension `json:"metadata,omitempty"`
}
```
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `templateId` | string | Yes | Nuclei template identifier (e.g., `CVE-2021-44228`) |
| `templateName` | string | No | Human-readable template name |
| `severity` | string | Yes | Severity level: `info`, `low`, `medium`, `high`, `critical` |
| `type` | string | No | Finding type: `http`, `dns`, `ssl`, `tcp`, etc. |
| `host` | string | Yes | Target host that was scanned |
| `matchedAt` | string | No | Specific URL or endpoint where the issue was found |
| `extractedResults` | []string | No | Data extracted by the template |
| `description` | string | No | Detailed description of the finding |
| `reference` | []string | No | URLs to additional information |
| `tags` | []string | No | Tags associated with the finding |
| `timestamp` | Time | Yes | When the finding was discovered |
| `metadata` | RawExtension | No | Additional template metadata (preserved as JSON) |
### ScanSummary
`ScanSummary` provides aggregated statistics about the scan.
```go
type ScanSummary struct {
TotalFindings int `json:"totalFindings"`
FindingsBySeverity map[string]int `json:"findingsBySeverity,omitempty"`
TargetsScanned int `json:"targetsScanned"`
DurationSeconds int64 `json:"durationSeconds,omitempty"`
}
```
| Field | Type | Description |
|-------|------|-------------|
| `totalFindings` | int | Total number of findings |
| `findingsBySeverity` | map[string]int | Breakdown of findings by severity level |
| `targetsScanned` | int | Number of targets that were scanned |
| `durationSeconds` | int64 | Duration of the scan in seconds |
### ScanPhase
`ScanPhase` represents the current phase of the scan lifecycle.
```go
type ScanPhase string
const (
ScanPhasePending ScanPhase = "Pending"
ScanPhaseRunning ScanPhase = "Running"
ScanPhaseCompleted ScanPhase = "Completed"
ScanPhaseFailed ScanPhase = "Failed"
)
```
| Phase | Description |
|-------|-------------|
| `Pending` | Scan is waiting to be executed |
| `Running` | Scan is currently in progress |
| `Completed` | Scan finished successfully |
| `Failed` | Scan failed with an error |
---
## Examples
### Basic NucleiScan
A minimal NucleiScan configuration:
```yaml
apiVersion: nuclei.homelab.mortenolsen.pro/v1alpha1
kind: NucleiScan
metadata:
name: basic-scan
namespace: default
spec:
sourceRef:
apiVersion: networking.k8s.io/v1
kind: Ingress
name: my-ingress
namespace: default
uid: "12345678-1234-1234-1234-123456789012"
targets:
- https://example.com
```
### NucleiScan with Severity Filter
Scan only for medium, high, and critical vulnerabilities:
```yaml
apiVersion: nuclei.homelab.mortenolsen.pro/v1alpha1
kind: NucleiScan
metadata:
name: severity-filtered-scan
namespace: default
spec:
sourceRef:
apiVersion: networking.k8s.io/v1
kind: Ingress
name: production-ingress
namespace: production
uid: "abcdef12-3456-7890-abcd-ef1234567890"
targets:
- https://api.example.com
- https://www.example.com
severity:
- medium
- high
- critical
```
### NucleiScan with Specific Templates
Use specific Nuclei template categories:
```yaml
apiVersion: nuclei.homelab.mortenolsen.pro/v1alpha1
kind: NucleiScan
metadata:
name: cve-scan
namespace: default
spec:
sourceRef:
apiVersion: networking.k8s.io/v1
kind: Ingress
name: app-ingress
namespace: default
uid: "fedcba98-7654-3210-fedc-ba9876543210"
targets:
- https://app.example.com
templates:
- cves/
- vulnerabilities/
- exposures/
severity:
- high
- critical
```
### Scheduled NucleiScan
Run a scan daily at 2:00 AM:
```yaml
apiVersion: nuclei.homelab.mortenolsen.pro/v1alpha1
kind: NucleiScan
metadata:
name: daily-security-scan
namespace: default
spec:
sourceRef:
apiVersion: networking.k8s.io/v1
kind: Ingress
name: main-ingress
namespace: default
uid: "11111111-2222-3333-4444-555555555555"
targets:
- https://example.com
- https://api.example.com
severity:
- medium
- high
- critical
schedule: "0 2 * * *"
suspend: false
```
### NucleiScan for VirtualService
Scan an Istio VirtualService:
```yaml
apiVersion: nuclei.homelab.mortenolsen.pro/v1alpha1
kind: NucleiScan
metadata:
name: istio-app-scan
namespace: istio-apps
spec:
sourceRef:
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
name: my-virtualservice
namespace: istio-apps
uid: "vs-uid-12345"
targets:
- https://istio-app.example.com
severity:
- low
- medium
- high
- critical
```
### Comprehensive Security Audit
Full security audit with all severity levels and template categories:
```yaml
apiVersion: nuclei.homelab.mortenolsen.pro/v1alpha1
kind: NucleiScan
metadata:
name: comprehensive-audit
namespace: security
labels:
audit-type: comprehensive
compliance: required
spec:
sourceRef:
apiVersion: networking.k8s.io/v1
kind: Ingress
name: production-ingress
namespace: production
uid: "prod-uid-67890"
targets:
- https://www.example.com
- https://api.example.com
- https://admin.example.com
templates:
- cves/
- vulnerabilities/
- exposures/
- misconfiguration/
- default-logins/
- takeovers/
severity:
- info
- low
- medium
- high
- critical
schedule: "0 3 * * 0" # Weekly on Sunday at 3 AM
suspend: false
```
---
## Print Columns
When listing NucleiScan resources with `kubectl get nucleiscans`, the following columns are displayed:
| Column | JSONPath | Description |
|--------|----------|-------------|
| NAME | `.metadata.name` | Resource name |
| PHASE | `.status.phase` | Current scan phase |
| FINDINGS | `.status.summary.totalFindings` | Total number of findings |
| SOURCE | `.spec.sourceRef.kind` | Source resource kind |
| AGE | `.metadata.creationTimestamp` | Resource age |
**Example output:**
```
NAME PHASE FINDINGS SOURCE AGE
my-app-scan Completed 5 Ingress 2d
api-scan Running 0 Ingress 1h
istio-app-scan Completed 2 VirtualService 5d
```
---
## Validation
The CRD includes validation rules enforced by the Kubernetes API server:
### Spec Validation
- `sourceRef.kind` must be either `Ingress` or `VirtualService`
- `targets` must contain at least one item
- `severity` values must be one of: `info`, `low`, `medium`, `high`, `critical`
### Status Validation
- `phase` must be one of: `Pending`, `Running`, `Completed`, `Failed`
---
## RBAC Requirements
To interact with NucleiScan resources, the following RBAC permissions are needed:
### Read-only Access
```yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: nucleiscan-viewer
rules:
- apiGroups: ["nuclei.homelab.mortenolsen.pro"]
resources: ["nucleiscans"]
verbs: ["get", "list", "watch"]
```
### Full Access
```yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: nucleiscan-editor
rules:
- apiGroups: ["nuclei.homelab.mortenolsen.pro"]
resources: ["nucleiscans"]
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
- apiGroups: ["nuclei.homelab.mortenolsen.pro"]
resources: ["nucleiscans/status"]
verbs: ["get"]

762
docs/user-guide.md Normal file
View File

@@ -0,0 +1,762 @@
# 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