Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ generate-configuration:
# Format: example_path::observed_resources_path (observed_resources_path optional).
EXAMPLES := \
examples/securitystacks/minimal.yaml:: \
examples/securitystacks/nodepool.yaml:: \
examples/securitystacks/standard.yaml::

render\:all:
Expand Down
28 changes: 28 additions & 0 deletions apis/securitystacks/definition.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,34 @@ spec:
enum:
- ProviderConfig
- ClusterProviderConfig
nodePool:
description: Optional dedicated Karpenter NodePool for security workloads. When enabled, non-DaemonSet pods are scheduled with workload-type=security and tolerate security=true:NoSchedule; DaemonSets only receive tolerations.
type: object
properties:
enabled:
description: Whether to create a dedicated NodePool. Defaults to false.
type: boolean
default: false
name:
description: NodePool name on the target cluster. Defaults to "hops-security".
type: string
nodeClassName:
description: EKS Auto Mode NodeClass to reference. Defaults to "hops-default".
type: string
limits:
description: Karpenter NodePool resource limits. Defaults to nodes=10.
type: object
x-kubernetes-preserve-unknown-fields: true
requirements:
description: Karpenter scheduling requirements. Defaults to amd64/linux spot or on-demand nodes.
type: array
items:
type: object
x-kubernetes-preserve-unknown-fields: true
disruption:
description: Karpenter disruption settings. Defaults to WhenEmptyOrUnderutilized after 60s.
type: object
x-kubernetes-preserve-unknown-fields: true
trivy:
description: Trivy Operator configuration.
type: object
Expand Down
11 changes: 11 additions & 0 deletions examples/securitystacks/nodepool.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
apiVersion: hops.ops.com.ai/v1alpha1
kind: SecurityStack
metadata:
name: security
namespace: default
spec:
clusterName: default
labels:
team: platform
nodePool:
enabled: true
42 changes: 42 additions & 0 deletions functions/render/000-state-init.yaml.gotmpl
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,36 @@
"kind" ($k8sPCR.kind | default "ProviderConfig")
}}

# ==============================================================================
# NodePool configuration
# ==============================================================================
{{- $nodePoolSpec := $spec.nodePool | default dict }}
{{- $nodePoolEnabled := false }}
{{- if hasKey $nodePoolSpec "enabled" }}
{{- $nodePoolEnabled = $nodePoolSpec.enabled }}
{{- end }}
{{- $nodePoolName := $nodePoolSpec.name | default "hops-security" }}
{{- $nodePoolNodeClassName := $nodePoolSpec.nodeClassName | default "hops-default" }}
{{- $nodePoolLimits := $nodePoolSpec.limits | default (dict "nodes" 10) }}
{{- $nodePoolRequirements := $nodePoolSpec.requirements | default (list
(dict "key" "karpenter.sh/capacity-type" "operator" "In" "values" (list "spot" "on-demand"))
(dict "key" "eks.amazonaws.com/instance-category" "operator" "In" "values" (list "c" "m" "r"))
(dict "key" "eks.amazonaws.com/instance-generation" "operator" "Gt" "values" (list "4"))
(dict "key" "eks.amazonaws.com/instance-memory" "operator" "Gt" "values" (list "7999"))
(dict "key" "eks.amazonaws.com/instance-cpu" "operator" "Gt" "values" (list "1"))
(dict "key" "kubernetes.io/arch" "operator" "In" "values" (list "amd64"))
(dict "key" "kubernetes.io/os" "operator" "In" "values" (list "linux"))
) }}
{{- $nodePoolDisruption := $nodePoolSpec.disruption | default (dict "consolidationPolicy" "WhenEmptyOrUnderutilized" "consolidateAfter" "60s") }}
{{- $nodePoolTaintKey := "security" }}
{{- $nodePoolTaintValue := "true" }}
{{- $nodePoolNodeSelector := dict }}
{{- $nodePoolTolerations := list }}
{{- if $nodePoolEnabled }}
{{- $nodePoolNodeSelector = dict "workload-type" "security" }}
{{- $nodePoolTolerations = list (dict "key" $nodePoolTaintKey "operator" "Equal" "value" $nodePoolTaintValue "effect" "NoSchedule") }}
{{- end }}

# ==============================================================================
# Trivy Operator component
# ==============================================================================
Expand Down Expand Up @@ -115,6 +145,18 @@
"labels" $labels
"helmProviderConfigRef" $helmPCR
"kubernetesProviderConfigRef" $k8sPCR
"nodePool" (dict
"enabled" $nodePoolEnabled
"name" $nodePoolName
"nodeClassName" $nodePoolNodeClassName
"limits" $nodePoolLimits
"requirements" $nodePoolRequirements
"disruption" $nodePoolDisruption
"taintKey" $nodePoolTaintKey
"taintValue" $nodePoolTaintValue
"nodeSelector" $nodePoolNodeSelector
"tolerations" $nodePoolTolerations
)
"trivy" (dict
"enabled" $tvEnabled
"namespace" $tvNamespace
Expand Down
76 changes: 76 additions & 0 deletions functions/render/155-nodepool.yaml.gotmpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
# code: language=yaml
#
# Optional Karpenter NodePool for security workloads.
# DaemonSets get tolerations from their Helm values; Deployments and Jobs also
# get node selectors so they land on this pool.
#

{{- if $state.nodePool.enabled }}
---
apiVersion: kubernetes.m.crossplane.io/v1alpha1
kind: Object
metadata:
name: {{ $state.name }}-nodepool-security
annotations:
{{ setResourceNameAnnotation "nodepool-security" }}
labels: {{ $state.labels | toJson }}
spec:
managementPolicies: {{ $state.managementPolicies | toJson }}
forProvider:
manifest:
apiVersion: karpenter.sh/v1
kind: NodePool
metadata:
name: {{ $state.nodePool.name }}
spec:
template:
metadata:
labels:
workload-type: security
spec:
nodeClassRef:
group: eks.amazonaws.com
kind: NodeClass
name: {{ $state.nodePool.nodeClassName }}
taints:
- key: {{ $state.nodePool.taintKey }}
value: {{ $state.nodePool.taintValue | quote }}
effect: NoSchedule
requirements: {{ $state.nodePool.requirements | toJson }}
limits: {{ $state.nodePool.limits | toJson }}
disruption: {{ $state.nodePool.disruption | toJson }}
providerConfigRef:
name: {{ $state.kubernetesProviderConfigRef.name }}
kind: {{ $state.kubernetesProviderConfigRef.kind }}

{{- $nodePoolObjectName := printf "%s-nodepool-security" $state.name }}
{{- $securityReleases := list
(dict "enabled" $state.trivy.enabled "name" $state.trivy.releaseName "usageName" "trivy")
(dict "enabled" $state.falco.enabled "name" $state.falco.releaseName "usageName" "falco")
(dict "enabled" $state.kubescape.enabled "name" $state.kubescape.releaseName "usageName" "kubescape")
}}
{{- range $release := $securityReleases }}
{{- if $release.enabled }}
---
apiVersion: protection.crossplane.io/v1beta1
kind: Usage
metadata:
name: {{ $state.name }}-delete-{{ $release.usageName }}-before-nodepool
annotations:
{{ setResourceNameAnnotation (printf "usage-%s-before-nodepool" $release.usageName) }}
labels: {{ $state.labels | toJson }}
spec:
replayDeletion: true
of:
apiVersion: kubernetes.m.crossplane.io/v1alpha1
kind: Object
resourceRef:
name: {{ $nodePoolObjectName }}
by:
apiVersion: helm.m.crossplane.io/v1beta1
kind: Release
resourceRef:
name: {{ $release.name }}
{{- end }}
{{- end }}
{{- end }}
26 changes: 24 additions & 2 deletions functions/render/200-trivy.yaml.gotmpl
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,16 @@ spec:
# operator Deployment, NOT `operator.resources` (which is ignored).
resources:
requests:
cpu: 100m
memory: 1Gi
cpu: 50m
memory: 826Mi
limits:
memory: 1Gi
{{- if $state.nodePool.enabled }}
nodeSelector:
{{- toYaml $state.nodePool.nodeSelector | nindent 8 }}
tolerations:
{{- toYaml $state.nodePool.tolerations | nindent 8 }}
{{- end }}
trivy:
# Scan targets — image vulns + workload config + RBAC posture + secrets.
# Cluster-compliance (CIS / NSA) is left off here; Kubescape covers that
Expand All @@ -71,6 +77,22 @@ spec:
# signal cadence once ObserveStack alerts are wired.
vulnerabilityScannerScanOnlyCurrentRevisions: true
configAuditScannerScanOnlyCurrentRevisions: true
{{- if $state.nodePool.enabled }}
scanJobNodeSelector:
{{- toYaml $state.nodePool.nodeSelector | nindent 10 }}
scanJobTolerations:
{{- toYaml $state.nodePool.tolerations | nindent 10 }}
{{- end }}
{{- if $state.nodePool.enabled }}
nodeCollector:
# Node collector is per-node; tolerate all taints so node scans are not
# silently skipped on dedicated pools.
tolerations:
- effect: NoSchedule
operator: Exists
- effect: NoExecute
operator: Exists
{{- end }}
serviceMonitor:
# Gated on spec.observe.enabled (default true) — flips on when
# ObserveStack integration is wired. Prometheus on the platform uses
Expand Down
44 changes: 37 additions & 7 deletions functions/render/210-falco.yaml.gotmpl
Original file line number Diff line number Diff line change
Expand Up @@ -60,11 +60,29 @@ spec:
tty: false
resources:
requests:
cpu: 100m
memory: 512Mi
cpu: 50m
memory: 826Mi
limits:
cpu: 1000m
memory: 2Gi
falcoctl:
artifact:
install:
resources:
requests:
cpu: 10m
memory: 50Mi
limits:
cpu: 100m
memory: 128Mi
follow:
resources:
requests:
cpu: 11m
memory: 50Mi
limits:
cpu: 100m
memory: 128Mi
# Run on every node, mirroring the ambient DaemonSet (ztunnel / istio-cni)
# tolerations pattern. Don't miss events on tainted node pools.
tolerations:
Expand Down Expand Up @@ -98,11 +116,17 @@ spec:
# Burstable: stateless event forwarder, restart-cheap.
resources:
requests:
cpu: 50m
memory: 64Mi
cpu: 15m
memory: 100Mi
limits:
cpu: 100m
memory: 128Mi
memory: 256Mi
{{- if $state.nodePool.enabled }}
nodeSelector:
{{- toYaml $state.nodePool.nodeSelector | nindent 10 }}
tolerations:
{{- toYaml $state.nodePool.tolerations | nindent 10 }}
{{- end }}
{{- if $state.observe.enabled }}
config:
# Direct Loki output — Falcosidekick 2.31 does NOT expose an OTLP
Expand Down Expand Up @@ -133,11 +157,17 @@ spec:
k8s-metacollector:
resources:
requests:
cpu: 50m
memory: 128Mi
cpu: 15m
memory: 100Mi
limits:
cpu: 100m
memory: 256Mi
{{- if $state.nodePool.enabled }}
nodeSelector:
{{- toYaml $state.nodePool.nodeSelector | nindent 10 }}
tolerations:
{{- toYaml $state.nodePool.tolerations | nindent 10 }}
{{- end }}
{{- if gt (len $fl.values) 0 }}
{{- toYaml $fl.values | nindent 6 }}
{{- end }}
Expand Down
Loading
Loading