Files
nuclei-operator/charts/nuclei-operator/templates/deployment.yaml
Morten Olsen 12d681ada1 feat: implement pod-based scanning architecture
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
2025-12-12 20:55:09 +01:00

117 lines
4.2 KiB
YAML

apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "nuclei-operator.fullname" . }}-controller-manager
namespace: {{ .Release.Namespace }}
labels:
{{- include "nuclei-operator.labels" . | nindent 4 }}
spec:
replicas: {{ .Values.replicaCount }}
selector:
matchLabels:
{{- include "nuclei-operator.selectorLabels" . | nindent 6 }}
template:
metadata:
annotations:
kubectl.kubernetes.io/default-container: manager
{{- with .Values.podAnnotations }}
{{- toYaml . | nindent 8 }}
{{- end }}
labels:
{{- include "nuclei-operator.selectorLabels" . | nindent 8 }}
{{- with .Values.podLabels }}
{{- toYaml . | nindent 8 }}
{{- end }}
spec:
{{- with .Values.imagePullSecrets }}
imagePullSecrets:
{{- toYaml . | nindent 8 }}
{{- end }}
serviceAccountName: {{ include "nuclei-operator.serviceAccountName" . }}
securityContext:
{{- toYaml .Values.podSecurityContext | nindent 8 }}
containers:
- name: manager
image: {{ include "nuclei-operator.image" . }}
imagePullPolicy: {{ .Values.image.pullPolicy }}
command:
- /manager
args:
{{- if .Values.leaderElection.enabled }}
- --leader-elect
{{- end }}
- --health-probe-bind-address=:8081
{{- if .Values.metrics.enabled }}
- --metrics-bind-address=:8443
- --metrics-secure=true
{{- end }}
env:
- name: NUCLEI_BINARY_PATH
value: {{ .Values.nuclei.binaryPath | quote }}
- name: NUCLEI_TEMPLATES_PATH
value: {{ .Values.nuclei.templatesPath | quote }}
- name: NUCLEI_TIMEOUT
value: {{ .Values.nuclei.timeout | quote }}
- name: NUCLEI_RESCAN_AGE
value: {{ .Values.nuclei.rescanAge | quote }}
- name: NUCLEI_BACKOFF_INITIAL
value: {{ .Values.nuclei.backoff.initial | quote }}
- name: NUCLEI_BACKOFF_MAX
value: {{ .Values.nuclei.backoff.max | quote }}
- name: NUCLEI_BACKOFF_MULTIPLIER
value: {{ .Values.nuclei.backoff.multiplier | quote }}
- name: SCANNER_IMAGE
value: {{ .Values.scanner.image | default (printf "%s:%s" .Values.image.repository (.Values.image.tag | default .Chart.AppVersion)) | quote }}
- name: SCANNER_TIMEOUT
value: {{ .Values.scanner.timeout | quote }}
- name: MAX_CONCURRENT_SCANS
value: {{ .Values.scanner.maxConcurrent | quote }}
- name: JOB_TTL_AFTER_FINISHED
value: {{ .Values.scanner.ttlAfterFinished | quote }}
- name: SCANNER_SERVICE_ACCOUNT
value: {{ include "nuclei-operator.fullname" . }}-scanner
{{- if .Values.scanner.defaultTemplates }}
- name: DEFAULT_TEMPLATES
value: {{ join "," .Values.scanner.defaultTemplates | quote }}
{{- end }}
{{- if .Values.scanner.defaultSeverity }}
- name: DEFAULT_SEVERITY
value: {{ join "," .Values.scanner.defaultSeverity | quote }}
{{- end }}
ports: []
securityContext:
{{- toYaml .Values.securityContext | nindent 10 }}
{{- with .Values.healthProbes.livenessProbe }}
livenessProbe:
{{- toYaml . | nindent 10 }}
{{- end }}
{{- with .Values.healthProbes.readinessProbe }}
readinessProbe:
{{- toYaml . | nindent 10 }}
{{- end }}
resources:
{{- toYaml .Values.resources | nindent 10 }}
volumeMounts:
- name: nuclei-templates
mountPath: {{ .Values.nuclei.templatesPath }}
readOnly: true
- name: nuclei-cache
mountPath: /home/nonroot/.nuclei
volumes:
- name: nuclei-templates
emptyDir: {}
- name: nuclei-cache
emptyDir: {}
{{- with .Values.nodeSelector }}
nodeSelector:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.affinity }}
affinity:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.tolerations }}
tolerations:
{{- toYaml . | nindent 8 }}
{{- end }}
terminationGracePeriodSeconds: 10