From 3d46102d322e2a304680eb647556c0e3a91ec93c Mon Sep 17 00:00:00 2001 From: Mahil Patel Date: Thu, 26 Mar 2026 23:26:29 +0530 Subject: [PATCH 1/9] feat: added optional SPIRE config and RBAC(ServiceAccounts, ClusterRoles, ClusterRoleBindings) for SPIRE components gated by spire.enabled Signed-off-by: Mahil Patel --- .../charts/base/templates/spire/rbac.yaml | 135 ++++++++++++++++++ manifests/charts/base/values.yaml | 52 +++++++ 2 files changed, 187 insertions(+) create mode 100644 manifests/charts/base/templates/spire/rbac.yaml diff --git a/manifests/charts/base/templates/spire/rbac.yaml b/manifests/charts/base/templates/spire/rbac.yaml new file mode 100644 index 00000000..2c178653 --- /dev/null +++ b/manifests/charts/base/templates/spire/rbac.yaml @@ -0,0 +1,135 @@ +{{- if .Values.spire.enabled }} +# --- SPIRE Server --- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: spire-server + namespace: {{ .Release.Namespace }} + labels: + app: spire-server +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: spire-server + labels: + app: spire-server +rules: + # Required for k8s_psat NodeAttestor to validate projected service account tokens + - apiGroups: ["authentication.k8s.io"] + resources: ["tokenreviews"] + verbs: ["create"] + # Required for node attestation and registration entry management + - apiGroups: [""] + resources: ["nodes"] + verbs: ["get", "list", "watch"] +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: spire-server + labels: + app: spire-server +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: spire-server +subjects: + - kind: ServiceAccount + name: spire-server + namespace: {{ .Release.Namespace }} +--- + +# --- SPIRE Agent --- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: spire-agent + namespace: {{ .Release.Namespace }} + labels: + app: spire-agent +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: spire-agent + labels: + app: spire-agent +rules: + # Required for k8s workload attestor to query pod metadata from kubelet + - apiGroups: [""] + resources: ["pods"] + verbs: ["get", "list"] + # Required for workload attestation to resolve node information + - apiGroups: [""] + resources: ["nodes"] + verbs: ["get", "list"] + # Required for k8s_psat NodeAttestor to create token reviews + - apiGroups: ["authentication.k8s.io"] + resources: ["tokenreviews"] + verbs: ["create"] +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: spire-agent + labels: + app: spire-agent +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: spire-agent +subjects: + - kind: ServiceAccount + name: spire-agent + namespace: {{ .Release.Namespace }} + +--- +# --- SPIRE Controller Manager --- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: spire-controller-manager + namespace: {{ .Release.Namespace }} + labels: + app: spire-controller-manager +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: spire-controller-manager + labels: + app: spire-controller-manager +rules: + # Required to watch ClusterSPIFFEID CRDs and sync entries to SPIRE Server + - apiGroups: ["spire.spiffe.io"] + resources: ["clusterspiffeids"] + verbs: ["get", "list", "watch", "create", "update", "patch"] + - apiGroups: ["spire.spiffe.io"] + resources: ["clusterspiffeids/status"] + verbs: ["get", "update", "patch"] + # Required to watch pods for label-based workload matching + - apiGroups: [""] + resources: ["pods"] + verbs: ["get", "list", "watch"] + # Required to resolve namespaces for namespaceSelector + - apiGroups: [""] + resources: ["namespaces"] + verbs: ["get", "list", "watch"] +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: spire-controller-manager + labels: + app: spire-controller-manager +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: spire-controller-manager +subjects: + - kind: ServiceAccount + name: spire-controller-manager + namespace: {{ .Release.Namespace }} +{{- end }} + diff --git a/manifests/charts/base/values.yaml b/manifests/charts/base/values.yaml index 25a07979..22f6d275 100644 --- a/manifests/charts/base/values.yaml +++ b/manifests/charts/base/values.yaml @@ -63,3 +63,55 @@ volcano: repository: ghcr.io/volcano-sh/vc-agent-scheduler pullPolicy: IfNotPresent tag: "latest" + +# SPIRE Configuration (Internal Workload Identity) +spire: + enabled: false + trustDomain: "agentcube.local" + clusterName: "agentcube-cluster" + server: + image: + repository: ghcr.io/spiffe/spire-server + tag: "1.12.0" + pullPolicy: IfNotPresent + service: + type: ClusterIP + port: 8081 + ca: + ttl: "24h" + x509SvidDefaultTtl: "1h" + dataStore: + type: "sqlite3" + connectionString: "/run/spire/data/datastore.sqlite3" + resources: + limits: + cpu: 200m + memory: 512Mi + requests: + cpu: 50m + memory: 128Mi + agent: + image: + repository: ghcr.io/spiffe/spire-agent + tag: "1.12.0" + pullPolicy: IfNotPresent + resources: + limits: + cpu: 200m + memory: 256Mi + requests: + cpu: 50m + memory: 64Mi + controllerManager: + image: + repository: ghcr.io/spiffe/spire-controller-manager + tag: "0.6.4" + pullPolicy: IfNotPresent + resources: + limits: + cpu: 100m + memory: 128Mi + requests: + cpu: 50m + memory: 64Mi + From 0c881c019549f441c728fac86f7751be7a0d6c3c Mon Sep 17 00:00:00 2001 From: Mahil Patel Date: Fri, 27 Mar 2026 18:40:30 +0530 Subject: [PATCH 2/9] feat: added SPIRE Server StatefulSet and ConfigMap config for SPIRE components gated by spire.enabled Signed-off-by: Mahil Patel --- .../base/templates/spire/spire-server.yaml | 123 ++++++++++++++++++ 1 file changed, 123 insertions(+) create mode 100644 manifests/charts/base/templates/spire/spire-server.yaml diff --git a/manifests/charts/base/templates/spire/spire-server.yaml b/manifests/charts/base/templates/spire/spire-server.yaml new file mode 100644 index 00000000..14d4bb86 --- /dev/null +++ b/manifests/charts/base/templates/spire/spire-server.yaml @@ -0,0 +1,123 @@ +{{- if .Values.spire.enabled }} +apiVersion: v1 +kind: ConfigMap +metadata: + name: spire-server-config + namespace: {{ .Release.Namespace }} + labels: + app: spire-server +data: + server.conf: | + server { + bind_address = "0.0.0.0" + bind_port = "{{ .Values.spire.server.service.port }}" + trust_domain = "{{ .Values.spire.trustDomain }}" + data_dir = "/run/spire/data" + + ca_ttl = "{{ .Values.spire.server.ca.ttl }}" + default_x509_svid_ttl = "{{ .Values.spire.server.ca.x509SvidDefaultTtl }}" + } + + plugins { + DataStore "sql" { + plugin_data { + database_type = "{{ .Values.spire.server.dataStore.type }}" + connection_string = "{{ .Values.spire.server.dataStore.connectionString }}" + } + } + + NodeAttestor "k8s_psat" { + plugin_data { + clusters = { + "{{ .Values.spire.clusterName }}" = { + service_account_allow_list = [ + "{{ .Release.Namespace }}:spire-agent" + ] + } + } + } + } + + KeyManager "disk" { + plugin_data { + keys_path = "/run/spire/data/keys.json" + } + } + } + +--- +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: spire-server + namespace: {{ .Release.Namespace }} + labels: + app: spire-server +spec: + replicas: 1 + selector: + matchLabels: + app: spire-server + serviceName: spire-server + template: + metadata: + labels: + app: spire-server + spec: + serviceAccountName: spire-server + containers: + - name: spire-server + image: "{{ .Values.spire.server.image.repository }}:{{ .Values.spire.server.image.tag }}" + imagePullPolicy: {{ .Values.spire.server.image.pullPolicy }} + args: ["-config", "/run/spire/config/server.conf"] + ports: + - name: grpc + containerPort: {{ .Values.spire.server.service.port }} + protocol: TCP + volumeMounts: + - name: spire-config + mountPath: /run/spire/config + readOnly: true + - name: spire-data + mountPath: /run/spire/data + livenessProbe: + exec: + command: + - /opt/spire/bin/spire-server + - healthcheck + initialDelaySeconds: 15 + periodSeconds: 60 + readinessProbe: + exec: + command: + - /opt/spire/bin/spire-server + - healthcheck + initialDelaySeconds: 5 + periodSeconds: 10 + resources: + {{- toYaml .Values.spire.server.resources | nindent 12 }} + volumes: + - name: spire-config + configMap: + name: spire-server-config + - name: spire-data + emptyDir: {} + +--- +apiVersion: v1 +kind: Service +metadata: + name: spire-server + namespace: {{ .Release.Namespace }} + labels: + app: spire-server +spec: + type: {{ .Values.spire.server.service.type }} + ports: + - name: grpc + port: {{ .Values.spire.server.service.port }} + targetPort: {{ .Values.spire.server.service.port }} + protocol: TCP + selector: + app: spire-server +{{- end }} From 9394345fad9ad7efab0671d3102b776383a984c3 Mon Sep 17 00:00:00 2001 From: Mahil Patel Date: Fri, 27 Mar 2026 18:53:46 +0530 Subject: [PATCH 3/9] feat: added SPIRE Agent DaemonSet and ConfigMap config for SPIRE components gated by spire.enabled Signed-off-by: Mahil Patel --- .../base/templates/spire/spire-agent.yaml | 113 ++++++++++++++++++ 1 file changed, 113 insertions(+) create mode 100644 manifests/charts/base/templates/spire/spire-agent.yaml diff --git a/manifests/charts/base/templates/spire/spire-agent.yaml b/manifests/charts/base/templates/spire/spire-agent.yaml new file mode 100644 index 00000000..20ae1a9f --- /dev/null +++ b/manifests/charts/base/templates/spire/spire-agent.yaml @@ -0,0 +1,113 @@ +{{- if .Values.spire.enabled }} +apiVersion: v1 +kind: ConfigMap +metadata: + name: spire-agent-config + namespace: {{ .Release.Namespace }} + labels: + app: spire-agent +data: + agent.conf: | + agent { + data_dir = "/run/spire/data" + log_level = "INFO" + server_address = "spire-server.{{ .Release.Namespace }}.svc.cluster.local" + server_port = "{{ .Values.spire.server.service.port }}" + socket_path = "/run/spire/sockets/agent.sock" + trust_domain = "{{ .Values.spire.trustDomain }}" + } + + plugins { + NodeAttestor "k8s_psat" { + plugin_data { + cluster = "{{ .Values.spire.clusterName }}" + } + } + + KeyManager "memory" { + plugin_data {} + } + + WorkloadAttestor "k8s" { + plugin_data { + # TODO: In production environments, set this to false to enforce kubelet certificate verification + skip_kubelet_verification = true + } + } + } + +--- +apiVersion: apps/v1 +kind: DaemonSet +metadata: + name: spire-agent + namespace: {{ .Release.Namespace }} + labels: + app: spire-agent +spec: + selector: + matchLabels: + app: spire-agent + template: + metadata: + labels: + app: spire-agent + spec: + serviceAccountName: spire-agent + hostPID: true + hostNetwork: true + dnsPolicy: ClusterFirstWithHostNet + containers: + - name: spire-agent + image: "{{ .Values.spire.agent.image.repository }}:{{ .Values.spire.agent.image.tag }}" + imagePullPolicy: {{ .Values.spire.agent.image.pullPolicy }} + args: ["-config", "/run/spire/config/agent.conf"] + volumeMounts: + - name: spire-agent-socket + mountPath: /run/spire/sockets + - name: spire-config + mountPath: /run/spire/config + readOnly: true + - name: spire-token + mountPath: /var/run/secrets/tokens + env: + - name: MY_NODE_NAME + valueFrom: + fieldRef: + fieldPath: spec.nodeName + livenessProbe: + exec: + command: + - /opt/spire/bin/spire-agent + - healthcheck + - -socketPath + - /run/spire/sockets/agent.sock + initialDelaySeconds: 15 + periodSeconds: 60 + readinessProbe: + exec: + command: + - /opt/spire/bin/spire-agent + - healthcheck + - -socketPath + - /run/spire/sockets/agent.sock + initialDelaySeconds: 5 + periodSeconds: 10 + resources: + {{- toYaml .Values.spire.agent.resources | nindent 12 }} + volumes: + - name: spire-agent-socket + hostPath: + path: /run/spire/sockets + type: DirectoryOrCreate + - name: spire-config + configMap: + name: spire-agent-config + - name: spire-token + projected: + sources: + - serviceAccountToken: + audience: spire-server + expirationSeconds: 7200 + path: spire-agent +{{- end }} From b9655aa24381ae1f0def5284d2e7e93f63034559 Mon Sep 17 00:00:00 2001 From: Mahil Patel Date: Fri, 27 Mar 2026 19:16:00 +0530 Subject: [PATCH 4/9] feat: added SPIRE Controller Manager Deployment and ClusterSPIFFEID CRDs for SPIRE components gated by spire.enabled Signed-off-by: Mahil Patel --- .../templates/spire/cluster-spiffe-ids.yaml | 42 +++++++++++++++++ .../base/templates/spire/spire-agent.yaml | 9 ++-- .../spire/spire-controller-manager.yaml | 47 +++++++++++++++++++ .../base/templates/spire/spire-server.yaml | 2 +- 4 files changed, 94 insertions(+), 6 deletions(-) create mode 100644 manifests/charts/base/templates/spire/cluster-spiffe-ids.yaml create mode 100644 manifests/charts/base/templates/spire/spire-controller-manager.yaml diff --git a/manifests/charts/base/templates/spire/cluster-spiffe-ids.yaml b/manifests/charts/base/templates/spire/cluster-spiffe-ids.yaml new file mode 100644 index 00000000..21fefb11 --- /dev/null +++ b/manifests/charts/base/templates/spire/cluster-spiffe-ids.yaml @@ -0,0 +1,42 @@ +{{- if .Values.spire.enabled }} +# Router registration +apiVersion: spire.spiffe.io/v1alpha1 +kind: ClusterSPIFFEID +metadata: + name: agentcube-router +spec: + spiffeIDTemplate: "spiffe://{{ .Values.spire.trustDomain }}/ns/{{ "{{ .PodMeta.Namespace }}" }}/sa/{{ "{{ .PodSpec.ServiceAccountName }}" }}" + podSelector: + matchLabels: + app: agentcube-router + namespaceSelector: + matchNames: + - {{ .Release.Namespace }} + +--- +# WorkloadManager registration +apiVersion: spire.spiffe.io/v1alpha1 +kind: ClusterSPIFFEID +metadata: + name: agentcube-workload-manager +spec: + spiffeIDTemplate: "spiffe://{{ .Values.spire.trustDomain }}/ns/{{ "{{ .PodMeta.Namespace }}" }}/sa/{{ "{{ .PodSpec.ServiceAccountName }}" }}" + podSelector: + matchLabels: + app: workloadmanager + namespaceSelector: + matchNames: + - {{ .Release.Namespace }} + +--- +# PicoD (Sandbox) registration - namespace-agnostic +apiVersion: spire.spiffe.io/v1alpha1 +kind: ClusterSPIFFEID +metadata: + name: agentcube-sandbox +spec: + spiffeIDTemplate: "spiffe://{{ .Values.spire.trustDomain }}/sa/{{ "{{ .PodSpec.ServiceAccountName }}" }}" + podSelector: + matchLabels: + app: picod +{{- end }} diff --git a/manifests/charts/base/templates/spire/spire-agent.yaml b/manifests/charts/base/templates/spire/spire-agent.yaml index 20ae1a9f..ec472185 100644 --- a/manifests/charts/base/templates/spire/spire-agent.yaml +++ b/manifests/charts/base/templates/spire/spire-agent.yaml @@ -30,8 +30,7 @@ data: WorkloadAttestor "k8s" { plugin_data { - # TODO: In production environments, set this to false to enforce kubelet certificate verification - skip_kubelet_verification = true + skip_kubelet_verification = true # NOTE: In production environments, set this to false to enforce kubelet certificate verification } } } @@ -54,7 +53,7 @@ spec: app: spire-agent spec: serviceAccountName: spire-agent - hostPID: true + hostPID: true # Required for workload attestation (process identity) hostNetwork: true dnsPolicy: ClusterFirstWithHostNet containers: @@ -98,7 +97,7 @@ spec: volumes: - name: spire-agent-socket hostPath: - path: /run/spire/sockets + path: /run/spire/sockets # Workload API socket shared with pods on this node type: DirectoryOrCreate - name: spire-config configMap: @@ -107,7 +106,7 @@ spec: projected: sources: - serviceAccountToken: - audience: spire-server + audience: spire-server # Projected token for k8s_psat node attestation expirationSeconds: 7200 path: spire-agent {{- end }} diff --git a/manifests/charts/base/templates/spire/spire-controller-manager.yaml b/manifests/charts/base/templates/spire/spire-controller-manager.yaml new file mode 100644 index 00000000..f9d702f5 --- /dev/null +++ b/manifests/charts/base/templates/spire/spire-controller-manager.yaml @@ -0,0 +1,47 @@ +{{- if .Values.spire.enabled }} +apiVersion: apps/v1 +kind: Deployment +metadata: + name: spire-controller-manager + namespace: {{ .Release.Namespace }} + labels: + app: spire-controller-manager +spec: + replicas: 1 + selector: + matchLabels: + app: spire-controller-manager + template: + metadata: + labels: + app: spire-controller-manager + spec: + serviceAccountName: spire-controller-manager + containers: + - name: spire-controller-manager + image: "{{ .Values.spire.controllerManager.image.repository }}:{{ .Values.spire.controllerManager.image.tag }}" + imagePullPolicy: {{ .Values.spire.controllerManager.image.pullPolicy }} + args: + - --spire-server-address=spire-server.{{ .Release.Namespace }}.svc.cluster.local:{{ .Values.spire.server.service.port }} + ports: + - name: https + containerPort: 9443 + protocol: TCP + - name: health + containerPort: 8083 + protocol: TCP + livenessProbe: + httpGet: + path: /healthz + port: health + initialDelaySeconds: 15 + periodSeconds: 60 + readinessProbe: + httpGet: + path: /readyz + port: health + initialDelaySeconds: 5 + periodSeconds: 10 + resources: + {{- toYaml .Values.spire.controllerManager.resources | nindent 12 }} +{{- end }} diff --git a/manifests/charts/base/templates/spire/spire-server.yaml b/manifests/charts/base/templates/spire/spire-server.yaml index 14d4bb86..9d3fb0e9 100644 --- a/manifests/charts/base/templates/spire/spire-server.yaml +++ b/manifests/charts/base/templates/spire/spire-server.yaml @@ -101,7 +101,7 @@ spec: configMap: name: spire-server-config - name: spire-data - emptyDir: {} + emptyDir: {} # Re-synced from ClusterSPIFFEID CRDs on restart; PVC not required --- apiVersion: v1 From 4d3cb3b337491720aa3a8ba4bcb5a798bd2b296c Mon Sep 17 00:00:00 2001 From: Mahil Patel Date: Sat, 28 Mar 2026 00:06:05 +0530 Subject: [PATCH 5/9] fix:fixed SPIRE Controller Manager to be deplyoed as a sidecar with spire-server instead of separate deployment Signed-off-by: Mahil Patel --- .../templates/spire/cluster-spiffe-ids.yaml | 8 +- .../charts/base/templates/spire/rbac.yaml | 83 +++++++------------ .../base/templates/spire/spire-agent.yaml | 1 + .../spire/spire-controller-manager.yaml | 66 ++++++--------- .../base/templates/spire/spire-server.yaml | 43 ++++++++++ .../templates/spire/validating-webhook.yaml | 42 ++++++++++ 6 files changed, 146 insertions(+), 97 deletions(-) create mode 100644 manifests/charts/base/templates/spire/validating-webhook.yaml diff --git a/manifests/charts/base/templates/spire/cluster-spiffe-ids.yaml b/manifests/charts/base/templates/spire/cluster-spiffe-ids.yaml index 21fefb11..c4ebd03b 100644 --- a/manifests/charts/base/templates/spire/cluster-spiffe-ids.yaml +++ b/manifests/charts/base/templates/spire/cluster-spiffe-ids.yaml @@ -10,8 +10,8 @@ spec: matchLabels: app: agentcube-router namespaceSelector: - matchNames: - - {{ .Release.Namespace }} + matchLabels: + kubernetes.io/metadata.name: {{ .Release.Namespace }} --- # WorkloadManager registration @@ -25,8 +25,8 @@ spec: matchLabels: app: workloadmanager namespaceSelector: - matchNames: - - {{ .Release.Namespace }} + matchLabels: + kubernetes.io/metadata.name: {{ .Release.Namespace }} --- # PicoD (Sandbox) registration - namespace-agnostic diff --git a/manifests/charts/base/templates/spire/rbac.yaml b/manifests/charts/base/templates/spire/rbac.yaml index 2c178653..015d73f0 100644 --- a/manifests/charts/base/templates/spire/rbac.yaml +++ b/manifests/charts/base/templates/spire/rbac.yaml @@ -1,5 +1,6 @@ {{- if .Values.spire.enabled }} # --- SPIRE Server --- +# Also used by the Controller Manager sidecar running in the same pod apiVersion: v1 kind: ServiceAccount metadata: @@ -19,10 +20,40 @@ rules: - apiGroups: ["authentication.k8s.io"] resources: ["tokenreviews"] verbs: ["create"] + # Required for k8s_psat NodeAttestor to query pod identity during attestation + - apiGroups: [""] + resources: ["pods"] + verbs: ["get", "list", "watch"] # Required for node attestation and registration entry management - apiGroups: [""] resources: ["nodes"] verbs: ["get", "list", "watch"] + # Required by Controller Manager sidecar to watch and sync ClusterSPIFFEID CRDs + - apiGroups: ["spire.spiffe.io"] + resources: ["clusterspiffeids", "clusterfederatedtrustdomains", "clusterstaticentries"] + verbs: ["get", "list", "watch", "create", "update", "patch"] + - apiGroups: ["spire.spiffe.io"] + resources: ["clusterspiffeids/status", "clusterfederatedtrustdomains/status", "clusterstaticentries/status"] + verbs: ["get", "update", "patch"] + # Required by Controller Manager sidecar to resolve namespaces for namespaceSelector + - apiGroups: [""] + resources: ["namespaces", "endpoints"] + verbs: ["get", "list", "watch"] + # Required by Controller Manager sidecar for leader election + - apiGroups: ["coordination.k8s.io"] + resources: ["leases"] + verbs: ["get", "list", "watch", "create", "update", "patch"] + - apiGroups: [""] + resources: ["events"] + verbs: ["create", "patch"] + # Required by Controller Manager sidecar to manage its webhook certificate + - apiGroups: ["admissionregistration.k8s.io"] + resources: ["validatingwebhookconfigurations"] + verbs: ["get", "list", "watch", "create"] + - apiGroups: ["admissionregistration.k8s.io"] + resources: ["validatingwebhookconfigurations"] + resourceNames: ["spire-controller-manager-webhook"] + verbs: ["update", "patch"] --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding @@ -64,10 +95,6 @@ rules: - apiGroups: [""] resources: ["nodes"] verbs: ["get", "list"] - # Required for k8s_psat NodeAttestor to create token reviews - - apiGroups: ["authentication.k8s.io"] - resources: ["tokenreviews"] - verbs: ["create"] --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding @@ -83,53 +110,5 @@ subjects: - kind: ServiceAccount name: spire-agent namespace: {{ .Release.Namespace }} - ---- -# --- SPIRE Controller Manager --- -apiVersion: v1 -kind: ServiceAccount -metadata: - name: spire-controller-manager - namespace: {{ .Release.Namespace }} - labels: - app: spire-controller-manager ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: spire-controller-manager - labels: - app: spire-controller-manager -rules: - # Required to watch ClusterSPIFFEID CRDs and sync entries to SPIRE Server - - apiGroups: ["spire.spiffe.io"] - resources: ["clusterspiffeids"] - verbs: ["get", "list", "watch", "create", "update", "patch"] - - apiGroups: ["spire.spiffe.io"] - resources: ["clusterspiffeids/status"] - verbs: ["get", "update", "patch"] - # Required to watch pods for label-based workload matching - - apiGroups: [""] - resources: ["pods"] - verbs: ["get", "list", "watch"] - # Required to resolve namespaces for namespaceSelector - - apiGroups: [""] - resources: ["namespaces"] - verbs: ["get", "list", "watch"] ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: spire-controller-manager - labels: - app: spire-controller-manager -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: spire-controller-manager -subjects: - - kind: ServiceAccount - name: spire-controller-manager - namespace: {{ .Release.Namespace }} {{- end }} diff --git a/manifests/charts/base/templates/spire/spire-agent.yaml b/manifests/charts/base/templates/spire/spire-agent.yaml index ec472185..1c95d28c 100644 --- a/manifests/charts/base/templates/spire/spire-agent.yaml +++ b/manifests/charts/base/templates/spire/spire-agent.yaml @@ -15,6 +15,7 @@ data: server_port = "{{ .Values.spire.server.service.port }}" socket_path = "/run/spire/sockets/agent.sock" trust_domain = "{{ .Values.spire.trustDomain }}" + insecure_bootstrap = true # NOTE: Bootstrap without pre-existing trust bundle; safe with k8s_psat attestation } plugins { diff --git a/manifests/charts/base/templates/spire/spire-controller-manager.yaml b/manifests/charts/base/templates/spire/spire-controller-manager.yaml index f9d702f5..1d77b834 100644 --- a/manifests/charts/base/templates/spire/spire-controller-manager.yaml +++ b/manifests/charts/base/templates/spire/spire-controller-manager.yaml @@ -1,47 +1,31 @@ {{- if .Values.spire.enabled }} -apiVersion: apps/v1 -kind: Deployment +# Controller Manager ConfigMap +# The Controller Manager runs as a sidecar in the spire-server StatefulSet +apiVersion: v1 +kind: ConfigMap metadata: - name: spire-controller-manager + name: spire-controller-manager-config namespace: {{ .Release.Namespace }} labels: app: spire-controller-manager -spec: - replicas: 1 - selector: - matchLabels: - app: spire-controller-manager - template: - metadata: - labels: - app: spire-controller-manager - spec: - serviceAccountName: spire-controller-manager - containers: - - name: spire-controller-manager - image: "{{ .Values.spire.controllerManager.image.repository }}:{{ .Values.spire.controllerManager.image.tag }}" - imagePullPolicy: {{ .Values.spire.controllerManager.image.pullPolicy }} - args: - - --spire-server-address=spire-server.{{ .Release.Namespace }}.svc.cluster.local:{{ .Values.spire.server.service.port }} - ports: - - name: https - containerPort: 9443 - protocol: TCP - - name: health - containerPort: 8083 - protocol: TCP - livenessProbe: - httpGet: - path: /healthz - port: health - initialDelaySeconds: 15 - periodSeconds: 60 - readinessProbe: - httpGet: - path: /readyz - port: health - initialDelaySeconds: 5 - periodSeconds: 10 - resources: - {{- toYaml .Values.spire.controllerManager.resources | nindent 12 }} +data: + spire-controller-manager.yaml: | + apiVersion: spire.spiffe.io/v1alpha1 + kind: ControllerManagerConfig + metrics: + bindAddress: 127.0.0.1:8082 + health: + healthProbeBindAddress: :8083 + leaderElection: + leaderElect: true + resourceName: spire-controller-manager + resourceNamespace: {{ .Release.Namespace }} + spireServerSocketPath: "/tmp/spire-server/private/api.sock" + clusterName: {{ .Values.spire.clusterName }} + trustDomain: {{ .Values.spire.trustDomain }} + validatingWebhookConfigurationName: spire-controller-manager-webhook + ignoreNamespaces: + - kube-system + - kube-public + - local-path-storage {{- end }} diff --git a/manifests/charts/base/templates/spire/spire-server.yaml b/manifests/charts/base/templates/spire/spire-server.yaml index 9d3fb0e9..676c339c 100644 --- a/manifests/charts/base/templates/spire/spire-server.yaml +++ b/manifests/charts/base/templates/spire/spire-server.yaml @@ -11,6 +11,7 @@ data: server { bind_address = "0.0.0.0" bind_port = "{{ .Values.spire.server.service.port }}" + socket_path = "/tmp/spire-server/private/api.sock" trust_domain = "{{ .Values.spire.trustDomain }}" data_dir = "/run/spire/data" @@ -80,6 +81,8 @@ spec: readOnly: true - name: spire-data mountPath: /run/spire/data + - name: spire-server-socket + mountPath: /tmp/spire-server/private livenessProbe: exec: command: @@ -96,12 +99,52 @@ spec: periodSeconds: 10 resources: {{- toYaml .Values.spire.server.resources | nindent 12 }} + # Controller Manager runs as a sidecar, sharing the SPIRE Server's API socket + - name: spire-controller-manager + image: "{{ .Values.spire.controllerManager.image.repository }}:{{ .Values.spire.controllerManager.image.tag }}" + imagePullPolicy: {{ .Values.spire.controllerManager.image.pullPolicy }} + args: + - -config + - /etc/spire-controller-manager/spire-controller-manager.yaml + ports: + - name: https + containerPort: 9443 + protocol: TCP + - name: health + containerPort: 8083 + protocol: TCP + volumeMounts: + - name: spire-server-socket + mountPath: /tmp/spire-server/private + readOnly: false + - name: controller-manager-config + mountPath: /etc/spire-controller-manager + readOnly: true + livenessProbe: + httpGet: + path: /healthz + port: health + initialDelaySeconds: 15 + periodSeconds: 60 + readinessProbe: + httpGet: + path: /readyz + port: health + initialDelaySeconds: 5 + periodSeconds: 10 + resources: + {{- toYaml .Values.spire.controllerManager.resources | nindent 12 }} volumes: - name: spire-config configMap: name: spire-server-config - name: spire-data emptyDir: {} # Re-synced from ClusterSPIFFEID CRDs on restart; PVC not required + - name: spire-server-socket + emptyDir: {} # Shared between SPIRE Server and Controller Manager for API socket + - name: controller-manager-config + configMap: + name: spire-controller-manager-config --- apiVersion: v1 diff --git a/manifests/charts/base/templates/spire/validating-webhook.yaml b/manifests/charts/base/templates/spire/validating-webhook.yaml new file mode 100644 index 00000000..f36dcd8e --- /dev/null +++ b/manifests/charts/base/templates/spire/validating-webhook.yaml @@ -0,0 +1,42 @@ +{{- if .Values.spire.enabled }} +# Service to expose the Controller Manager webhook (which runs as a sidecar in spire-server pod) +apiVersion: v1 +kind: Service +metadata: + name: spire-controller-manager-webhook + namespace: {{ .Release.Namespace }} + labels: + app: spire-server +spec: + type: ClusterIP + ports: + - name: https + port: 443 + targetPort: 9443 + protocol: TCP + selector: + app: spire-server +--- +# The ValidatingWebhookConfiguration object patched by the Controller Manager +apiVersion: admissionregistration.k8s.io/v1 +kind: ValidatingWebhookConfiguration +metadata: + name: spire-controller-manager-webhook + labels: + app: spire-controller-manager +webhooks: + - name: spire-controller-manager-webhook.spiffe.io + clientConfig: + service: + name: spire-controller-manager-webhook + namespace: {{ .Release.Namespace }} + path: /validate-spire-spiffe-io-v1alpha1-clusterspiffeid + rules: + - apiGroups: ["spire.spiffe.io"] + apiVersions: ["v1alpha1"] + operations: ["CREATE", "UPDATE"] + resources: ["clusterspiffeids"] + sideEffects: None + failurePolicy: Ignore + admissionReviewVersions: ["v1", "v1beta1"] +{{- end }} From f85fb6d7d9d2747cabd630ce474767466a9a1625 Mon Sep 17 00:00:00 2001 From: Mahil Patel Date: Thu, 2 Apr 2026 22:10:03 +0530 Subject: [PATCH 6/9] fix: update SPIRE trust domain and router RBAC defaults Signed-off-by: Mahil Patel --- manifests/charts/base/templates/rbac-router.yaml | 6 ++++-- manifests/charts/base/values.yaml | 6 +++--- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/manifests/charts/base/templates/rbac-router.yaml b/manifests/charts/base/templates/rbac-router.yaml index 76823bd9..dda83079 100644 --- a/manifests/charts/base/templates/rbac-router.yaml +++ b/manifests/charts/base/templates/rbac-router.yaml @@ -1,10 +1,12 @@ -{{- if .Values.router.rbac.create }} +{{- if or .Values.router.rbac.create .Values.spire.enabled }} apiVersion: v1 kind: ServiceAccount metadata: name: {{ .Values.router.serviceAccountName | default "agentcube-router" }} namespace: {{ .Release.Namespace }} --- +{{- end }} +{{- if .Values.router.rbac.create }} apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: @@ -13,7 +15,7 @@ metadata: rules: - apiGroups: [""] resources: ["secrets"] - verbs: ["get", "list", "watch", "create", "update", "patch", "delete"] + verbs: ["get", "list", "watch"] --- apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding diff --git a/manifests/charts/base/values.yaml b/manifests/charts/base/values.yaml index 22f6d275..d51901bc 100644 --- a/manifests/charts/base/values.yaml +++ b/manifests/charts/base/values.yaml @@ -31,9 +31,9 @@ router: memory: 128Mi config: {} extraEnv: [] - serviceAccountName: "" + serviceAccountName: "agentcube-router" rbac: - create: false + create: true # AgentCube Workload Manager workloadmanager: @@ -67,7 +67,7 @@ volcano: # SPIRE Configuration (Internal Workload Identity) spire: enabled: false - trustDomain: "agentcube.local" + trustDomain: "cluster.local" clusterName: "agentcube-cluster" server: image: From 35778a9669478797254c76980128fd52926ceee3 Mon Sep 17 00:00:00 2001 From: Mahil Patel Date: Thu, 2 Apr 2026 23:44:16 +0530 Subject: [PATCH 7/9] fix: deploy spiffe-helper sidecars for mTLS certificates and fix attestation RBAC Signed-off-by: Mahil Patel --- .../base/templates/agentcube-router.yaml | 35 +++++++++++++++++++ .../charts/base/templates/rbac-router.yaml | 2 +- .../charts/base/templates/spire/rbac.yaml | 4 +-- .../templates/spire/spiffe-helper-config.yaml | 19 ++++++++++ .../base/templates/workloadmanager.yaml | 35 +++++++++++++++++++ manifests/charts/base/values.yaml | 9 +++++ 6 files changed, 101 insertions(+), 3 deletions(-) create mode 100644 manifests/charts/base/templates/spire/spiffe-helper-config.yaml diff --git a/manifests/charts/base/templates/agentcube-router.yaml b/manifests/charts/base/templates/agentcube-router.yaml index 6a23874b..9e4410e6 100644 --- a/manifests/charts/base/templates/agentcube-router.yaml +++ b/manifests/charts/base/templates/agentcube-router.yaml @@ -23,7 +23,30 @@ spec: {{- toYaml . | nindent 8 }} {{- end }} containers: + {{- if .Values.spire.enabled }} + - name: spiffe-helper + image: "{{ .Values.spire.spiffeHelper.image.repository }}:{{ .Values.spire.spiffeHelper.image.tag }}" + imagePullPolicy: {{ .Values.spire.spiffeHelper.image.pullPolicy }} + args: + - "-config" + - "/etc/spiffe-helper/spiffe-helper.conf" + volumeMounts: + - name: spiffe-helper-config + mountPath: /etc/spiffe-helper + readOnly: true + - name: spire-agent-socket + mountPath: /run/spire/sockets + readOnly: true + - name: spire-certs + mountPath: {{ .Values.spire.spiffeHelper.certDir }} + {{- end }} - name: agentcube-router + {{- if .Values.spire.enabled }} + volumeMounts: + - name: spire-certs + mountPath: {{ .Values.spire.spiffeHelper.certDir }} + readOnly: true + {{- end }} image: "{{ .Values.router.image.repository }}:{{ .Values.router.image.tag }}" imagePullPolicy: {{ .Values.router.image.pullPolicy }} ports: @@ -61,6 +84,18 @@ spec: port: {{ .Values.router.service.targetPort }} initialDelaySeconds: 1 periodSeconds: 2 + {{- if .Values.spire.enabled }} + volumes: + - name: spire-agent-socket + hostPath: + path: /run/spire/sockets + type: DirectoryOrCreate + - name: spiffe-helper-config + configMap: + name: spiffe-helper-config + - name: spire-certs + emptyDir: {} + {{- end }} --- apiVersion: v1 diff --git a/manifests/charts/base/templates/rbac-router.yaml b/manifests/charts/base/templates/rbac-router.yaml index dda83079..9589a72d 100644 --- a/manifests/charts/base/templates/rbac-router.yaml +++ b/manifests/charts/base/templates/rbac-router.yaml @@ -15,7 +15,7 @@ metadata: rules: - apiGroups: [""] resources: ["secrets"] - verbs: ["get", "list", "watch"] + verbs: ["get", "list", "watch", "create", "update", "patch", "delete"] --- apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding diff --git a/manifests/charts/base/templates/spire/rbac.yaml b/manifests/charts/base/templates/spire/rbac.yaml index 015d73f0..eef02eda 100644 --- a/manifests/charts/base/templates/spire/rbac.yaml +++ b/manifests/charts/base/templates/spire/rbac.yaml @@ -91,9 +91,9 @@ rules: - apiGroups: [""] resources: ["pods"] verbs: ["get", "list"] - # Required for workload attestation to resolve node information + # Required for workload attestation to resolve node information and proxy requests to kubelet - apiGroups: [""] - resources: ["nodes"] + resources: ["nodes", "nodes/proxy"] verbs: ["get", "list"] --- apiVersion: rbac.authorization.k8s.io/v1 diff --git a/manifests/charts/base/templates/spire/spiffe-helper-config.yaml b/manifests/charts/base/templates/spire/spiffe-helper-config.yaml new file mode 100644 index 00000000..a1a9cd5b --- /dev/null +++ b/manifests/charts/base/templates/spire/spiffe-helper-config.yaml @@ -0,0 +1,19 @@ +{{- if .Values.spire.enabled }} +apiVersion: v1 +kind: ConfigMap +metadata: + name: spiffe-helper-config + namespace: {{ .Release.Namespace }} + labels: + app: spiffe-helper +data: + spiffe-helper.conf: | + agent_address = "/run/spire/sockets/agent.sock" + cmd = "" + cmd_args = "" + cert_dir = "{{ .Values.spire.spiffeHelper.certDir }}" + renew_signal = "SIGHUP" + svid_file_name = "{{ .Values.spire.spiffeHelper.certFileName }}" + svid_key_file_name = "{{ .Values.spire.spiffeHelper.keyFileName }}" + svid_bundle_file_name = "{{ .Values.spire.spiffeHelper.bundleFileName }}" +{{- end }} diff --git a/manifests/charts/base/templates/workloadmanager.yaml b/manifests/charts/base/templates/workloadmanager.yaml index 04d84df0..5a02bc98 100644 --- a/manifests/charts/base/templates/workloadmanager.yaml +++ b/manifests/charts/base/templates/workloadmanager.yaml @@ -21,7 +21,30 @@ spec: {{- toYaml . | nindent 8 }} {{- end }} containers: + {{- if .Values.spire.enabled }} + - name: spiffe-helper + image: "{{ .Values.spire.spiffeHelper.image.repository }}:{{ .Values.spire.spiffeHelper.image.tag }}" + imagePullPolicy: {{ .Values.spire.spiffeHelper.image.pullPolicy }} + args: + - "-config" + - "/etc/spiffe-helper/spiffe-helper.conf" + volumeMounts: + - name: spiffe-helper-config + mountPath: /etc/spiffe-helper + readOnly: true + - name: spire-agent-socket + mountPath: /run/spire/sockets + readOnly: true + - name: spire-certs + mountPath: {{ .Values.spire.spiffeHelper.certDir }} + {{- end }} - name: workloadmanager + {{- if .Values.spire.enabled }} + volumeMounts: + - name: spire-certs + mountPath: {{ .Values.spire.spiffeHelper.certDir }} + readOnly: true + {{- end }} image: "{{ .Values.workloadmanager.image.repository }}:{{ .Values.workloadmanager.image.tag }}" imagePullPolicy: {{ .Values.workloadmanager.image.pullPolicy }} ports: @@ -57,6 +80,18 @@ spec: port: {{ .Values.workloadmanager.service.port }} initialDelaySeconds: 5 periodSeconds: 5 + {{- if .Values.spire.enabled }} + volumes: + - name: spire-agent-socket + hostPath: + path: /run/spire/sockets + type: DirectoryOrCreate + - name: spiffe-helper-config + configMap: + name: spiffe-helper-config + - name: spire-certs + emptyDir: {} + {{- end }} --- apiVersion: v1 diff --git a/manifests/charts/base/values.yaml b/manifests/charts/base/values.yaml index d51901bc..4cdc7caa 100644 --- a/manifests/charts/base/values.yaml +++ b/manifests/charts/base/values.yaml @@ -69,6 +69,15 @@ spire: enabled: false trustDomain: "cluster.local" clusterName: "agentcube-cluster" + spiffeHelper: + image: + repository: ghcr.io/spiffe/spiffe-helper + tag: "0.8.0" + pullPolicy: IfNotPresent + certDir: "/run/spire/certs" + certFileName: "svid.pem" + keyFileName: "svid_key.pem" + bundleFileName: "svid_bundle.pem" server: image: repository: ghcr.io/spiffe/spire-server From 4f88c6ab25bd046f02dc1117bc80eeefcdcf0210 Mon Sep 17 00:00:00 2001 From: Mahil Patel Date: Sun, 5 Apr 2026 12:41:33 +0530 Subject: [PATCH 8/9] fix: hardened SPIRE deployment with PVCs, headless services, and release-unique global resources Signed-off-by: Mahil Patel --- .../charts/base/templates/rbac-router.yaml | 66 +++++++++---------- .../templates/spire/cluster-spiffe-ids.yaml | 6 +- .../charts/base/templates/spire/rbac.yaml | 14 ++-- .../base/templates/spire/spire-agent.yaml | 4 +- .../spire/spire-controller-manager.yaml | 2 +- .../base/templates/spire/spire-server.yaml | 31 ++++++++- .../templates/spire/validating-webhook.yaml | 2 +- manifests/charts/base/values.yaml | 2 + 8 files changed, 77 insertions(+), 50 deletions(-) diff --git a/manifests/charts/base/templates/rbac-router.yaml b/manifests/charts/base/templates/rbac-router.yaml index 9589a72d..76f0fdca 100644 --- a/manifests/charts/base/templates/rbac-router.yaml +++ b/manifests/charts/base/templates/rbac-router.yaml @@ -1,33 +1,33 @@ -{{- if or .Values.router.rbac.create .Values.spire.enabled }} -apiVersion: v1 -kind: ServiceAccount -metadata: - name: {{ .Values.router.serviceAccountName | default "agentcube-router" }} - namespace: {{ .Release.Namespace }} ---- -{{- end }} -{{- if .Values.router.rbac.create }} -apiVersion: rbac.authorization.k8s.io/v1 -kind: Role -metadata: - name: {{ .Values.router.serviceAccountName | default "agentcube-router" }} - namespace: {{ .Release.Namespace }} -rules: - - apiGroups: [""] - resources: ["secrets"] - verbs: ["get", "list", "watch", "create", "update", "patch", "delete"] ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: RoleBinding -metadata: - name: {{ .Values.router.serviceAccountName | default "agentcube-router" }} - namespace: {{ .Release.Namespace }} -subjects: - - kind: ServiceAccount - name: {{ .Values.router.serviceAccountName | default "agentcube-router" }} - namespace: {{ .Release.Namespace }} -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: Role - name: {{ .Values.router.serviceAccountName | default "agentcube-router" }} -{{- end }} +{{- if or .Values.router.rbac.create .Values.spire.enabled }} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ .Values.router.serviceAccountName | default "agentcube-router" }} + namespace: {{ .Release.Namespace }} +--- +{{- end }} +{{- if .Values.router.rbac.create }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: {{ .Values.router.serviceAccountName | default "agentcube-router" }} + namespace: {{ .Release.Namespace }} +rules: + - apiGroups: [""] + resources: ["secrets"] + verbs: ["get", "list", "watch", "create", "update", "patch", "delete"] +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: {{ .Values.router.serviceAccountName | default "agentcube-router" }} + namespace: {{ .Release.Namespace }} +subjects: + - kind: ServiceAccount + name: {{ .Values.router.serviceAccountName | default "agentcube-router" }} + namespace: {{ .Release.Namespace }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: {{ .Values.router.serviceAccountName | default "agentcube-router" }} +{{- end }} diff --git a/manifests/charts/base/templates/spire/cluster-spiffe-ids.yaml b/manifests/charts/base/templates/spire/cluster-spiffe-ids.yaml index c4ebd03b..576df947 100644 --- a/manifests/charts/base/templates/spire/cluster-spiffe-ids.yaml +++ b/manifests/charts/base/templates/spire/cluster-spiffe-ids.yaml @@ -3,7 +3,7 @@ apiVersion: spire.spiffe.io/v1alpha1 kind: ClusterSPIFFEID metadata: - name: agentcube-router + name: {{ .Release.Name }}-agentcube-router spec: spiffeIDTemplate: "spiffe://{{ .Values.spire.trustDomain }}/ns/{{ "{{ .PodMeta.Namespace }}" }}/sa/{{ "{{ .PodSpec.ServiceAccountName }}" }}" podSelector: @@ -18,7 +18,7 @@ spec: apiVersion: spire.spiffe.io/v1alpha1 kind: ClusterSPIFFEID metadata: - name: agentcube-workload-manager + name: {{ .Release.Name }}-agentcube-workload-manager spec: spiffeIDTemplate: "spiffe://{{ .Values.spire.trustDomain }}/ns/{{ "{{ .PodMeta.Namespace }}" }}/sa/{{ "{{ .PodSpec.ServiceAccountName }}" }}" podSelector: @@ -33,7 +33,7 @@ spec: apiVersion: spire.spiffe.io/v1alpha1 kind: ClusterSPIFFEID metadata: - name: agentcube-sandbox + name: {{ .Release.Name }}-agentcube-sandbox spec: spiffeIDTemplate: "spiffe://{{ .Values.spire.trustDomain }}/sa/{{ "{{ .PodSpec.ServiceAccountName }}" }}" podSelector: diff --git a/manifests/charts/base/templates/spire/rbac.yaml b/manifests/charts/base/templates/spire/rbac.yaml index eef02eda..0741cec9 100644 --- a/manifests/charts/base/templates/spire/rbac.yaml +++ b/manifests/charts/base/templates/spire/rbac.yaml @@ -12,7 +12,7 @@ metadata: apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: - name: spire-server + name: {{ .Release.Name }}-spire-server labels: app: spire-server rules: @@ -52,19 +52,19 @@ rules: verbs: ["get", "list", "watch", "create"] - apiGroups: ["admissionregistration.k8s.io"] resources: ["validatingwebhookconfigurations"] - resourceNames: ["spire-controller-manager-webhook"] + resourceNames: ["{{ .Release.Name }}-spire-controller-manager-webhook"] verbs: ["update", "patch"] --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: - name: spire-server + name: {{ .Release.Name }}-spire-server labels: app: spire-server roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole - name: spire-server + name: {{ .Release.Name }}-spire-server subjects: - kind: ServiceAccount name: spire-server @@ -83,7 +83,7 @@ metadata: apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: - name: spire-agent + name: {{ .Release.Name }}-spire-agent labels: app: spire-agent rules: @@ -99,13 +99,13 @@ rules: apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: - name: spire-agent + name: {{ .Release.Name }}-spire-agent labels: app: spire-agent roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole - name: spire-agent + name: {{ .Release.Name }}-spire-agent subjects: - kind: ServiceAccount name: spire-agent diff --git a/manifests/charts/base/templates/spire/spire-agent.yaml b/manifests/charts/base/templates/spire/spire-agent.yaml index 1c95d28c..ddda667c 100644 --- a/manifests/charts/base/templates/spire/spire-agent.yaml +++ b/manifests/charts/base/templates/spire/spire-agent.yaml @@ -15,7 +15,7 @@ data: server_port = "{{ .Values.spire.server.service.port }}" socket_path = "/run/spire/sockets/agent.sock" trust_domain = "{{ .Values.spire.trustDomain }}" - insecure_bootstrap = true # NOTE: Bootstrap without pre-existing trust bundle; safe with k8s_psat attestation + insecure_bootstrap = {{ .Values.spire.agent.insecureBootstrap | default false }} # Set true only when intentionally bootstrapping without a pre-existing trust bundle } plugins { @@ -31,7 +31,7 @@ data: WorkloadAttestor "k8s" { plugin_data { - skip_kubelet_verification = true # NOTE: In production environments, set this to false to enforce kubelet certificate verification + skip_kubelet_verification = {{ .Values.spire.agent.skipKubeletVerification | default false }} # Set true only in dev scenarios with self-signed kubelets } } } diff --git a/manifests/charts/base/templates/spire/spire-controller-manager.yaml b/manifests/charts/base/templates/spire/spire-controller-manager.yaml index 1d77b834..a017af87 100644 --- a/manifests/charts/base/templates/spire/spire-controller-manager.yaml +++ b/manifests/charts/base/templates/spire/spire-controller-manager.yaml @@ -23,7 +23,7 @@ data: spireServerSocketPath: "/tmp/spire-server/private/api.sock" clusterName: {{ .Values.spire.clusterName }} trustDomain: {{ .Values.spire.trustDomain }} - validatingWebhookConfigurationName: spire-controller-manager-webhook + validatingWebhookConfigurationName: {{ .Release.Name }}-spire-controller-manager-webhook ignoreNamespaces: - kube-system - kube-public diff --git a/manifests/charts/base/templates/spire/spire-server.yaml b/manifests/charts/base/templates/spire/spire-server.yaml index 676c339c..58b064fc 100644 --- a/manifests/charts/base/templates/spire/spire-server.yaml +++ b/manifests/charts/base/templates/spire/spire-server.yaml @@ -59,7 +59,7 @@ spec: selector: matchLabels: app: spire-server - serviceName: spire-server + serviceName: spire-server-headless template: metadata: labels: @@ -138,13 +138,38 @@ spec: - name: spire-config configMap: name: spire-server-config - - name: spire-data - emptyDir: {} # Re-synced from ClusterSPIFFEID CRDs on restart; PVC not required - name: spire-server-socket emptyDir: {} # Shared between SPIRE Server and Controller Manager for API socket - name: controller-manager-config configMap: name: spire-controller-manager-config + volumeClaimTemplates: + - metadata: + name: spire-data + spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 1Gi + +--- +apiVersion: v1 +kind: Service +metadata: + name: spire-server-headless + namespace: {{ .Release.Namespace }} + labels: + app: spire-server +spec: + clusterIP: None + ports: + - name: grpc + port: {{ .Values.spire.server.service.port }} + targetPort: {{ .Values.spire.server.service.port }} + protocol: TCP + selector: + app: spire-server --- apiVersion: v1 diff --git a/manifests/charts/base/templates/spire/validating-webhook.yaml b/manifests/charts/base/templates/spire/validating-webhook.yaml index f36dcd8e..045f242d 100644 --- a/manifests/charts/base/templates/spire/validating-webhook.yaml +++ b/manifests/charts/base/templates/spire/validating-webhook.yaml @@ -21,7 +21,7 @@ spec: apiVersion: admissionregistration.k8s.io/v1 kind: ValidatingWebhookConfiguration metadata: - name: spire-controller-manager-webhook + name: {{ .Release.Name }}-spire-controller-manager-webhook labels: app: spire-controller-manager webhooks: diff --git a/manifests/charts/base/values.yaml b/manifests/charts/base/values.yaml index 4cdc7caa..0ffd3516 100644 --- a/manifests/charts/base/values.yaml +++ b/manifests/charts/base/values.yaml @@ -100,6 +100,8 @@ spire: cpu: 50m memory: 128Mi agent: + insecureBootstrap: true + skipKubeletVerification: true image: repository: ghcr.io/spiffe/spire-agent tag: "1.12.0" From a00006df7e4489c30b292299eed4d02c2cd97502 Mon Sep 17 00:00:00 2001 From: Mahil Patel Date: Wed, 8 Apr 2026 18:57:56 +0530 Subject: [PATCH 9/9] fix: removed redundant permissions from router RBAC, set secure SPIRE defaults and added comments for better understanding Signed-off-by: Mahil Patel --- manifests/charts/base/templates/rbac-router.yaml | 6 +----- .../base/templates/spire/cluster-spiffe-ids.yaml | 3 +++ manifests/charts/base/values.yaml | 10 ++++++---- 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/manifests/charts/base/templates/rbac-router.yaml b/manifests/charts/base/templates/rbac-router.yaml index 76f0fdca..4f3ecc06 100644 --- a/manifests/charts/base/templates/rbac-router.yaml +++ b/manifests/charts/base/templates/rbac-router.yaml @@ -1,12 +1,9 @@ -{{- if or .Values.router.rbac.create .Values.spire.enabled }} apiVersion: v1 kind: ServiceAccount metadata: name: {{ .Values.router.serviceAccountName | default "agentcube-router" }} namespace: {{ .Release.Namespace }} --- -{{- end }} -{{- if .Values.router.rbac.create }} apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: @@ -15,7 +12,7 @@ metadata: rules: - apiGroups: [""] resources: ["secrets"] - verbs: ["get", "list", "watch", "create", "update", "patch", "delete"] + verbs: ["get", "create"] --- apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding @@ -30,4 +27,3 @@ roleRef: apiGroup: rbac.authorization.k8s.io kind: Role name: {{ .Values.router.serviceAccountName | default "agentcube-router" }} -{{- end }} diff --git a/manifests/charts/base/templates/spire/cluster-spiffe-ids.yaml b/manifests/charts/base/templates/spire/cluster-spiffe-ids.yaml index 576df947..c0b84d5a 100644 --- a/manifests/charts/base/templates/spire/cluster-spiffe-ids.yaml +++ b/manifests/charts/base/templates/spire/cluster-spiffe-ids.yaml @@ -1,4 +1,7 @@ {{- if .Values.spire.enabled }} +# Prerequisite: spire.spiffe.io CRDs must be present in the cluster before these resources can be created. +# The spire-controller-manager sidecar registers them automatically on first boot. +# For a fresh cluster, run: kubectl apply -f https://github.com/spiffe/spire-controller-manager/releases/download/v{{ .Values.spire.controllerManager.image.tag }}/crds.yaml # Router registration apiVersion: spire.spiffe.io/v1alpha1 kind: ClusterSPIFFEID diff --git a/manifests/charts/base/values.yaml b/manifests/charts/base/values.yaml index 0ffd3516..4690aeb1 100644 --- a/manifests/charts/base/values.yaml +++ b/manifests/charts/base/values.yaml @@ -32,8 +32,6 @@ router: config: {} extraEnv: [] serviceAccountName: "agentcube-router" - rbac: - create: true # AgentCube Workload Manager workloadmanager: @@ -70,11 +68,14 @@ spire: trustDomain: "cluster.local" clusterName: "agentcube-cluster" spiffeHelper: + # Configuration for the spiffe-helper sidecar which automatically fetches and rotates mTLS certificates image: repository: ghcr.io/spiffe/spiffe-helper tag: "0.8.0" pullPolicy: IfNotPresent + # Directory inside workload pods where the sidecar will deliver the certificates certDir: "/run/spire/certs" + # Desired file names for the SVID certificate, private key, and root trust bundle certFileName: "svid.pem" keyFileName: "svid_key.pem" bundleFileName: "svid_bundle.pem" @@ -100,8 +101,9 @@ spire: cpu: 50m memory: 128Mi agent: - insecureBootstrap: true - skipKubeletVerification: true + # For local dev clusters (kind/minikube), override with: --set spire.agent.insecureBootstrap=true --set spire.agent.skipKubeletVerification=true + insecureBootstrap: false + skipKubeletVerification: false image: repository: ghcr.io/spiffe/spire-agent tag: "1.12.0"