remediators

package
v0.2.172 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 8, 2026 License: Apache-2.0 Imports: 14 Imported by: 0

Documentation

Overview

Package remediators implements the individual cluster operations ("actions") that the operator performs in response to a TypeOperatorAction command.

Each action is a Remediator: it can Plan a change (without touching the cluster), Apply it (optionally as a server-side dry-run), and Revert it. New actions are added by implementing Remediator and registering them in NewRegistry — the command pipeline in mainhandler does not change.

Index

Constants

View Source
const (
	AnnotationRemediated = "kubescape.io/remediated"
	AnnotationReason     = "kubescape.io/remediation-reason"
	AnnotationFindingRef = "kubescape.io/remediation-finding-ref"
)

Annotation keys written by the annotate action. They mark a workload as having been acted on by Kubescape and carry the audit context (the reason and the finding that justified the action).

View Source
const (
	PatchTypeStrategic = "strategic"
	PatchTypeMerge     = "merge"
)

Patch type names accepted in Command.Args' "patchType" field. Strategic is the default when patchType is omitted.

View Source
const (
	// LabelQuarantine marks the deny-all NetworkPolicy created by the quarantine
	// action, so it can be found and removed on revert.
	LabelQuarantine = "kubescape.io/quarantine"
	// AnnotationQuarantineTarget records, on the NetworkPolicy, the workload it
	// isolates — part of the audit trail.
	AnnotationQuarantineTarget = "kubescape.io/quarantine-target"
)

Variables

This section is empty.

Functions

func IsNamespacedKind

func IsNamespacedKind(kind string) bool

IsNamespacedKind reports whether kind is one of the namespaced workload kinds Phase-1 actions operate on. The action handler uses it to enforce the namespace safety rail up front: a namespaced target with no namespace would otherwise skip the excluded-namespace check and fail late at the API server.

func NewRegistry

func NewRegistry(client kubernetes.Interface) map[apis.OperatorActionType]Remediator

NewRegistry builds the set of remediators backed by the given client. New actions are added by extending this map; the command pipeline does not change. cordon is added in a later phase.

Types

type AnnotateRemediator

type AnnotateRemediator struct {
	// contains filtered or unexported fields
}

AnnotateRemediator is the lowest-blast-radius action: it adds Kubescape remediation annotations to a workload. It is the first action shipped, to prove the CLI -> operator -> status pipeline end to end.

func NewAnnotateRemediator

func NewAnnotateRemediator(client kubernetes.Interface) *AnnotateRemediator

NewAnnotateRemediator returns an annotate remediator backed by client.

func (*AnnotateRemediator) Apply

func (r *AnnotateRemediator) Apply(ctx context.Context, p Plan, dryRun bool) (Result, error)

Apply sends the planned patch. With dryRun=true it is a server-side dry-run (validated against admission, never persisted); only dryRun=false writes.

func (*AnnotateRemediator) Plan

func (r *AnnotateRemediator) Plan(ctx context.Context, req Request) (Plan, error)

Plan computes the annotation patch without applying it.

func (*AnnotateRemediator) Revert

func (r *AnnotateRemediator) Revert(ctx context.Context, t Target, dryRun bool) (Result, error)

Revert removes the Kubescape remediation annotations from the target. Like Apply, dryRun=true issues a server-side dry-run (validated against admission, never persisted); only dryRun=false performs a real write — so the safe-by-default contract is honored for revert too.

The contract's revert verb undoes every reversible action without naming which one was applied, so revert runs annotate even on a workload that was only quarantined. To keep the audit trail honest, a workload carrying none of the remediation annotations is reported as a no-op ("nothing to revert", Applied=false) rather than claiming annotations were removed.

type PatchRemediator added in v0.2.172

type PatchRemediator struct {
	// contains filtered or unexported fields
}

PatchRemediator applies an arbitrary caller-supplied patch to a single workload. Unlike the other actions, the operator does not know the patch's semantics up front — it is opaque, backend-authored content — so Plan only validates shape (target kind/namespace, JSON/YAML well-formedness), and Revert cannot reconstruct the pre-patch state.

func NewPatchRemediator added in v0.2.172

func NewPatchRemediator(client kubernetes.Interface) *PatchRemediator

NewPatchRemediator returns a patch remediator backed by client.

func (*PatchRemediator) Apply added in v0.2.172

func (r *PatchRemediator) Apply(ctx context.Context, p Plan, dryRun bool) (Result, error)

Apply sends the planned patch. With dryRun=true it is a server-side dry-run (validated against admission, never persisted); only dryRun=false writes.

func (*PatchRemediator) Plan added in v0.2.172

func (r *PatchRemediator) Plan(ctx context.Context, req Request) (Plan, error)

Plan validates the target and patch payload and returns the canonical (JSON-encoded) patch body Apply would send.

func (*PatchRemediator) Revert added in v0.2.172

func (r *PatchRemediator) Revert(ctx context.Context, t Target, dryRun bool) (Result, error)

Revert is not supported for arbitrary patches: the operator does not record the pre-patch state, so there is nothing to reconstruct. Returning an error (rather than a silent no-op) keeps the audit trail honest about the fact that the target was not restored.

type Plan

type Plan struct {
	Action      string `json:"action"`
	Target      Target `json:"target"`
	Description string `json:"description"`
	// Patch is the exact patch body Apply would send, included for transparency
	// in the dry-run preview.
	Patch string `json:"patch,omitempty"`
	// PatchType is the patch action's patch type (Strategic Merge Patch or
	// JSON Merge Patch), empty for actions other than patch.
	PatchType string `json:"patchType,omitempty"`
}

Plan is the computed, not-yet-applied effect of a remediation. It is returned to the caller (CLI / OperatorCommand status) so a change can be previewed before any cluster write happens.

type QuarantineRemediator

type QuarantineRemediator struct {
	// contains filtered or unexported fields
}

QuarantineRemediator isolates a workload by creating a deny-all NetworkPolicy that selects the workload's pods (both ingress and egress denied). It does not mutate or recreate the pods, so container state is preserved for forensic investigation (the design's resolved default; scale-to-zero is a future, explicit opt-in). Revert deletes the NetworkPolicy.

Isolation semantics and preconditions (surfaced in the plan/result via quarantineCaveat):

  • CNI enforcement: a NetworkPolicy only isolates traffic on a CNI that enforces NetworkPolicy. On a non-enforcing CNI the policy is created but has no effect; the action still reports success because the desired object was applied — enforcement is a cluster property the operator cannot verify.
  • Blast radius: the policy selects by the workload's selector labels, so it isolates every pod matching them — including pods owned by other workloads that reuse the same labels (blue/green, canary, a second Deployment reusing "app="). Quarantine assumes the selector identifies the intended pods.
  • Pod targets: a NetworkPolicy selects pods by label, not by name. A controller-managed pod's labels are shared by every replica of its template (pod-template-hash, etc.), so quarantining a Pod isolates the whole ReplicaSet/template, not the single named pod. Single-pod isolation is not achievable with a NetworkPolicy.

func NewQuarantineRemediator

func NewQuarantineRemediator(client kubernetes.Interface) *QuarantineRemediator

NewQuarantineRemediator returns a quarantine remediator backed by client.

func (*QuarantineRemediator) Apply

func (r *QuarantineRemediator) Apply(ctx context.Context, p Plan, dryRun bool) (Result, error)

Apply creates the planned deny-all NetworkPolicy. With dryRun=true it is sent as a server-side dry-run (validated against admission, never persisted); only dryRun=false performs a real write. If a policy already exists (a prior quarantine), it is reconciled to the freshly planned spec so that a selector that drifted since the first quarantine (the workload was edited/redeployed) still isolates the currently-running pods, rather than leaving a stale policy in place while reporting success.

func (*QuarantineRemediator) Plan

func (r *QuarantineRemediator) Plan(ctx context.Context, req Request) (Plan, error)

Plan reads the target workload's pod selector from the live object and computes the deny-all NetworkPolicy without creating it.

func (*QuarantineRemediator) Revert

func (r *QuarantineRemediator) Revert(ctx context.Context, t Target, dryRun bool) (Result, error)

Revert deletes the deny-all NetworkPolicy that quarantined the target. A missing policy is treated as success (nothing to undo). Like Apply, dryRun=true issues a server-side dry-run delete, so the safe-by-default contract holds for revert too.

type Remediator

type Remediator interface {
	// Plan computes the intended change without mutating the cluster.
	Plan(ctx context.Context, req Request) (Plan, error)
	// Apply executes a plan. When dryRun is true the write is sent with
	// server-side dry-run (validated against admission, never persisted).
	Apply(ctx context.Context, p Plan, dryRun bool) (Result, error)
	// Revert undoes a previously applied action on the target. Like Apply, a
	// dryRun=true revert is a server-side dry-run (validated, never persisted),
	// so the safe-by-default contract holds for revert too.
	Revert(ctx context.Context, t Target, dryRun bool) (Result, error)
}

Remediator computes and performs a single class of cluster operation.

type Request

type Request struct {
	Target     Target
	Reason     string
	FindingRef string
	// Patch and PatchType are used by the patch action only: Patch is the raw
	// (JSON or YAML) patch body, and PatchType selects Strategic Merge Patch
	// (the default, when empty) or JSON Merge Patch.
	Patch     string
	PatchType types.PatchType
}

Request carries a single remediation's target plus the audit metadata that some actions (e.g. annotate) record on the mutated object.

type Result

type Result struct {
	Action      string `json:"action"`
	Target      Target `json:"target"`
	DryRun      bool   `json:"dryRun"`
	Applied     bool   `json:"applied"`
	Description string `json:"description"`
	// Patch and PatchType record the exact bytes and patch type a confirmed
	// (non-dry-run) patch action sent to the API server, so the audit trail
	// (OperatorCommand status + KubescapeRemediation event) can reconstruct
	// what changed. Empty for actions other than patch.
	Patch     string `json:"patch,omitempty"`
	PatchType string `json:"patchType,omitempty"`
}

Result is the outcome of Apply or Revert.

type Target

type Target struct {
	Kind      string `json:"kind"`
	Namespace string `json:"namespace,omitempty"`
	Name      string `json:"name"`
}

Target identifies a single concrete object a remediation acts on.

func (Target) String

func (t Target) String() string

String renders the target as kind/namespace/name (kind/name for cluster-scoped objects), used in plans, results, logs and events.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL