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
318 lines
8.6 KiB
Go
318 lines
8.6 KiB
Go
//go:build !ignore_autogenerated
|
|
|
|
/*
|
|
Copyright 2025.
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
you may not use this file except in compliance with the License.
|
|
You may obtain a copy of the License at
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
See the License for the specific language governing permissions and
|
|
limitations under the License.
|
|
*/
|
|
|
|
// Code generated by controller-gen. DO NOT EDIT.
|
|
|
|
package v1alpha1
|
|
|
|
import (
|
|
"k8s.io/api/core/v1"
|
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
"k8s.io/apimachinery/pkg/runtime"
|
|
)
|
|
|
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
|
func (in *Finding) DeepCopyInto(out *Finding) {
|
|
*out = *in
|
|
if in.ExtractedResults != nil {
|
|
in, out := &in.ExtractedResults, &out.ExtractedResults
|
|
*out = make([]string, len(*in))
|
|
copy(*out, *in)
|
|
}
|
|
if in.Reference != nil {
|
|
in, out := &in.Reference, &out.Reference
|
|
*out = make([]string, len(*in))
|
|
copy(*out, *in)
|
|
}
|
|
if in.Tags != nil {
|
|
in, out := &in.Tags, &out.Tags
|
|
*out = make([]string, len(*in))
|
|
copy(*out, *in)
|
|
}
|
|
in.Timestamp.DeepCopyInto(&out.Timestamp)
|
|
if in.Metadata != nil {
|
|
in, out := &in.Metadata, &out.Metadata
|
|
*out = new(runtime.RawExtension)
|
|
(*in).DeepCopyInto(*out)
|
|
}
|
|
}
|
|
|
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Finding.
|
|
func (in *Finding) DeepCopy() *Finding {
|
|
if in == nil {
|
|
return nil
|
|
}
|
|
out := new(Finding)
|
|
in.DeepCopyInto(out)
|
|
return out
|
|
}
|
|
|
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
|
func (in *JobReference) DeepCopyInto(out *JobReference) {
|
|
*out = *in
|
|
if in.StartTime != nil {
|
|
in, out := &in.StartTime, &out.StartTime
|
|
*out = (*in).DeepCopy()
|
|
}
|
|
}
|
|
|
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new JobReference.
|
|
func (in *JobReference) DeepCopy() *JobReference {
|
|
if in == nil {
|
|
return nil
|
|
}
|
|
out := new(JobReference)
|
|
in.DeepCopyInto(out)
|
|
return out
|
|
}
|
|
|
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
|
func (in *NucleiScan) DeepCopyInto(out *NucleiScan) {
|
|
*out = *in
|
|
out.TypeMeta = in.TypeMeta
|
|
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
|
|
in.Spec.DeepCopyInto(&out.Spec)
|
|
in.Status.DeepCopyInto(&out.Status)
|
|
}
|
|
|
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NucleiScan.
|
|
func (in *NucleiScan) DeepCopy() *NucleiScan {
|
|
if in == nil {
|
|
return nil
|
|
}
|
|
out := new(NucleiScan)
|
|
in.DeepCopyInto(out)
|
|
return out
|
|
}
|
|
|
|
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
|
func (in *NucleiScan) DeepCopyObject() runtime.Object {
|
|
if c := in.DeepCopy(); c != nil {
|
|
return c
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
|
func (in *NucleiScanList) DeepCopyInto(out *NucleiScanList) {
|
|
*out = *in
|
|
out.TypeMeta = in.TypeMeta
|
|
in.ListMeta.DeepCopyInto(&out.ListMeta)
|
|
if in.Items != nil {
|
|
in, out := &in.Items, &out.Items
|
|
*out = make([]NucleiScan, len(*in))
|
|
for i := range *in {
|
|
(*in)[i].DeepCopyInto(&(*out)[i])
|
|
}
|
|
}
|
|
}
|
|
|
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NucleiScanList.
|
|
func (in *NucleiScanList) DeepCopy() *NucleiScanList {
|
|
if in == nil {
|
|
return nil
|
|
}
|
|
out := new(NucleiScanList)
|
|
in.DeepCopyInto(out)
|
|
return out
|
|
}
|
|
|
|
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
|
func (in *NucleiScanList) DeepCopyObject() runtime.Object {
|
|
if c := in.DeepCopy(); c != nil {
|
|
return c
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
|
func (in *NucleiScanSpec) DeepCopyInto(out *NucleiScanSpec) {
|
|
*out = *in
|
|
out.SourceRef = in.SourceRef
|
|
if in.Targets != nil {
|
|
in, out := &in.Targets, &out.Targets
|
|
*out = make([]string, len(*in))
|
|
copy(*out, *in)
|
|
}
|
|
if in.Templates != nil {
|
|
in, out := &in.Templates, &out.Templates
|
|
*out = make([]string, len(*in))
|
|
copy(*out, *in)
|
|
}
|
|
if in.Severity != nil {
|
|
in, out := &in.Severity, &out.Severity
|
|
*out = make([]string, len(*in))
|
|
copy(*out, *in)
|
|
}
|
|
if in.ScannerConfig != nil {
|
|
in, out := &in.ScannerConfig, &out.ScannerConfig
|
|
*out = new(ScannerConfig)
|
|
(*in).DeepCopyInto(*out)
|
|
}
|
|
}
|
|
|
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NucleiScanSpec.
|
|
func (in *NucleiScanSpec) DeepCopy() *NucleiScanSpec {
|
|
if in == nil {
|
|
return nil
|
|
}
|
|
out := new(NucleiScanSpec)
|
|
in.DeepCopyInto(out)
|
|
return out
|
|
}
|
|
|
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
|
func (in *NucleiScanStatus) DeepCopyInto(out *NucleiScanStatus) {
|
|
*out = *in
|
|
if in.Conditions != nil {
|
|
in, out := &in.Conditions, &out.Conditions
|
|
*out = make([]metav1.Condition, len(*in))
|
|
for i := range *in {
|
|
(*in)[i].DeepCopyInto(&(*out)[i])
|
|
}
|
|
}
|
|
if in.LastScanTime != nil {
|
|
in, out := &in.LastScanTime, &out.LastScanTime
|
|
*out = (*in).DeepCopy()
|
|
}
|
|
if in.CompletionTime != nil {
|
|
in, out := &in.CompletionTime, &out.CompletionTime
|
|
*out = (*in).DeepCopy()
|
|
}
|
|
if in.NextScheduledTime != nil {
|
|
in, out := &in.NextScheduledTime, &out.NextScheduledTime
|
|
*out = (*in).DeepCopy()
|
|
}
|
|
if in.Summary != nil {
|
|
in, out := &in.Summary, &out.Summary
|
|
*out = new(ScanSummary)
|
|
(*in).DeepCopyInto(*out)
|
|
}
|
|
if in.Findings != nil {
|
|
in, out := &in.Findings, &out.Findings
|
|
*out = make([]Finding, len(*in))
|
|
for i := range *in {
|
|
(*in)[i].DeepCopyInto(&(*out)[i])
|
|
}
|
|
}
|
|
if in.LastRetryTime != nil {
|
|
in, out := &in.LastRetryTime, &out.LastRetryTime
|
|
*out = (*in).DeepCopy()
|
|
}
|
|
if in.JobRef != nil {
|
|
in, out := &in.JobRef, &out.JobRef
|
|
*out = new(JobReference)
|
|
(*in).DeepCopyInto(*out)
|
|
}
|
|
if in.ScanStartTime != nil {
|
|
in, out := &in.ScanStartTime, &out.ScanStartTime
|
|
*out = (*in).DeepCopy()
|
|
}
|
|
}
|
|
|
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NucleiScanStatus.
|
|
func (in *NucleiScanStatus) DeepCopy() *NucleiScanStatus {
|
|
if in == nil {
|
|
return nil
|
|
}
|
|
out := new(NucleiScanStatus)
|
|
in.DeepCopyInto(out)
|
|
return out
|
|
}
|
|
|
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
|
func (in *ScanSummary) DeepCopyInto(out *ScanSummary) {
|
|
*out = *in
|
|
if in.FindingsBySeverity != nil {
|
|
in, out := &in.FindingsBySeverity, &out.FindingsBySeverity
|
|
*out = make(map[string]int, len(*in))
|
|
for key, val := range *in {
|
|
(*out)[key] = val
|
|
}
|
|
}
|
|
}
|
|
|
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ScanSummary.
|
|
func (in *ScanSummary) DeepCopy() *ScanSummary {
|
|
if in == nil {
|
|
return nil
|
|
}
|
|
out := new(ScanSummary)
|
|
in.DeepCopyInto(out)
|
|
return out
|
|
}
|
|
|
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
|
func (in *ScannerConfig) DeepCopyInto(out *ScannerConfig) {
|
|
*out = *in
|
|
if in.Resources != nil {
|
|
in, out := &in.Resources, &out.Resources
|
|
*out = new(v1.ResourceRequirements)
|
|
(*in).DeepCopyInto(*out)
|
|
}
|
|
if in.Timeout != nil {
|
|
in, out := &in.Timeout, &out.Timeout
|
|
*out = new(metav1.Duration)
|
|
**out = **in
|
|
}
|
|
if in.TemplateURLs != nil {
|
|
in, out := &in.TemplateURLs, &out.TemplateURLs
|
|
*out = make([]string, len(*in))
|
|
copy(*out, *in)
|
|
}
|
|
if in.NodeSelector != nil {
|
|
in, out := &in.NodeSelector, &out.NodeSelector
|
|
*out = make(map[string]string, len(*in))
|
|
for key, val := range *in {
|
|
(*out)[key] = val
|
|
}
|
|
}
|
|
if in.Tolerations != nil {
|
|
in, out := &in.Tolerations, &out.Tolerations
|
|
*out = make([]v1.Toleration, len(*in))
|
|
for i := range *in {
|
|
(*in)[i].DeepCopyInto(&(*out)[i])
|
|
}
|
|
}
|
|
}
|
|
|
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ScannerConfig.
|
|
func (in *ScannerConfig) DeepCopy() *ScannerConfig {
|
|
if in == nil {
|
|
return nil
|
|
}
|
|
out := new(ScannerConfig)
|
|
in.DeepCopyInto(out)
|
|
return out
|
|
}
|
|
|
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
|
func (in *SourceReference) DeepCopyInto(out *SourceReference) {
|
|
*out = *in
|
|
}
|
|
|
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SourceReference.
|
|
func (in *SourceReference) DeepCopy() *SourceReference {
|
|
if in == nil {
|
|
return nil
|
|
}
|
|
out := new(SourceReference)
|
|
in.DeepCopyInto(out)
|
|
return out
|
|
}
|