Skip to content

Commit d3cb30e

Browse files
feat: add MTLSReady condition logic to AgentRuntime reconciler
Implement T006 from the mTLS transport security spec. The controller now evaluates SPIRE availability on each reconcile and sets the MTLSReady condition on AgentRuntime status: - SPIREAvailable (True): spire-agent-socket or svid-output volumes detected in the workload's pod template - SPIREUnavailable (False): mTLS mode is permissive/strict but no SPIRE volumes found; emits a Warning Event with actionable guidance - MTLSDisabled (True): mTLSMode explicitly set to disabled - SPIREAssumed (True): Sandbox workloads where PodSpec is not available; SPIRE injection handled by webhook at pod CREATE MTLSReady=False does NOT block Ready=True — it is informational so operators can track mTLS rollout progress across the fleet. Jira: RHAIENG-4928 Signed-off-by: Varsha Prasad Narsing <varshaprasad96@gmail.com> Assisted-By: Claude (Anthropic AI) <noreply@anthropic.com>
1 parent f938380 commit d3cb30e

2 files changed

Lines changed: 85 additions & 21 deletions

File tree

kagenti-operator/config/rbac/role.yaml

Lines changed: 11 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -41,15 +41,6 @@ rules:
4141
- ""
4242
resources:
4343
- serviceaccounts
44-
verbs:
45-
- create
46-
- get
47-
- list
48-
- update
49-
- watch
50-
- apiGroups:
51-
- ""
52-
resources:
5344
- services
5445
verbs:
5546
- create
@@ -168,17 +159,6 @@ rules:
168159
- get
169160
- list
170161
- watch
171-
- apiGroups:
172-
- k8s.keycloak.org
173-
resources:
174-
- keycloakrealmimports
175-
- keycloaks
176-
verbs:
177-
- create
178-
- get
179-
- list
180-
- patch
181-
- update
182162
- apiGroups:
183163
- datasciencecluster.opendatahub.io
184164
resources:
@@ -195,6 +175,17 @@ rules:
195175
- get
196176
- list
197177
- watch
178+
- apiGroups:
179+
- k8s.keycloak.org
180+
resources:
181+
- keycloakrealmimports
182+
- keycloaks
183+
verbs:
184+
- create
185+
- get
186+
- list
187+
- patch
188+
- update
198189
- apiGroups:
199190
- kuadrant.io
200191
resources:

kagenti-operator/internal/controller/agentruntime_controller.go

Lines changed: 74 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,10 @@ const (
8888

8989
// AnnotationRestartPendingValue is the value set on AnnotationRestartPending.
9090
AnnotationRestartPendingValue = "true"
91+
92+
// SPIRE volume names injected by the webhook when mTLS is enabled.
93+
VolumeSpireAgentSocket = "spire-agent-socket"
94+
VolumeSVIDOutput = "svid-output"
9195
)
9296

9397
var sandboxGVK = schema.GroupVersionKind{
@@ -212,7 +216,10 @@ func (r *AgentRuntimeReconciler) Reconcile(ctx context.Context, req ctrl.Request
212216
fmt.Sprintf("Namespace %s opted out of Istio mesh enrollment", rt.Namespace))
213217
}
214218

215-
// 4.7. Ensure SCC RoleBinding exists in the namespace.
219+
// 4.7. Evaluate MTLSReady condition based on resolved mTLSMode and SPIRE availability.
220+
r.evaluateMTLSReady(ctx, rt)
221+
222+
// 4.8. Ensure SCC RoleBinding exists in the namespace.
216223
// Creates a RoleBinding granting all ServiceAccounts in the namespace
217224
// access to the kagenti-authbridge SCC. No-op on non-OpenShift clusters.
218225
// On OpenShift, a transient failure is retried via requeue to prevent
@@ -763,6 +770,72 @@ func (r *AgentRuntimeReconciler) handleDeletion(ctx context.Context, rt *agentv1
763770
return ctrl.Result{}, nil
764771
}
765772

773+
// evaluateMTLSReady sets the MTLSReady condition based on the resolved
774+
// mTLSMode and whether SPIRE infrastructure is available on the workload.
775+
// This is informational — MTLSReady=False does NOT block Ready=True.
776+
func (r *AgentRuntimeReconciler) evaluateMTLSReady(ctx context.Context, rt *agentv1alpha1.AgentRuntime) {
777+
logger := log.FromContext(ctx)
778+
779+
mtlsMode := rt.Spec.MTLSMode
780+
if mtlsMode == "" {
781+
mtlsMode = "permissive"
782+
}
783+
784+
if mtlsMode == "disabled" {
785+
r.setCondition(rt, ConditionTypeMTLSReady, metav1.ConditionTrue, "MTLSDisabled",
786+
"mTLS explicitly disabled on this AgentRuntime")
787+
return
788+
}
789+
790+
// Check if workload has SPIRE infrastructure by looking for
791+
// spire-agent-socket or svid-output volumes in the pod template.
792+
acc, ok := newRuntimePodTemplateAccessor(rt.Spec.TargetRef.Kind)
793+
if !ok {
794+
r.setCondition(rt, ConditionTypeMTLSReady, metav1.ConditionFalse, "UnsupportedKind",
795+
fmt.Sprintf("Cannot check SPIRE availability for workload kind %s", rt.Spec.TargetRef.Kind))
796+
return
797+
}
798+
799+
key := types.NamespacedName{Name: rt.Spec.TargetRef.Name, Namespace: rt.Namespace}
800+
if err := r.Get(ctx, key, acc.obj); err != nil {
801+
logger.V(1).Info("Cannot read workload for SPIRE check", "error", err)
802+
r.setCondition(rt, ConditionTypeMTLSReady, metav1.ConditionFalse, "WorkloadNotFound",
803+
fmt.Sprintf("Cannot verify SPIRE availability: %v", err))
804+
return
805+
}
806+
807+
podSpec := acc.getPodSpec(acc.obj)
808+
if podSpec == nil {
809+
// Sandbox workloads don't expose a typed PodSpec; assume SPIRE
810+
// is available since the webhook handles injection at pod CREATE.
811+
r.setCondition(rt, ConditionTypeMTLSReady, metav1.ConditionTrue, "SPIREAssumed",
812+
"Sandbox workload; SPIRE availability assumed (webhook handles injection)")
813+
return
814+
}
815+
816+
spireDetected := false
817+
for _, v := range podSpec.Volumes {
818+
if v.Name == VolumeSpireAgentSocket || v.Name == VolumeSVIDOutput {
819+
spireDetected = true
820+
break
821+
}
822+
}
823+
824+
if spireDetected {
825+
r.setCondition(rt, ConditionTypeMTLSReady, metav1.ConditionTrue, "SPIREAvailable",
826+
fmt.Sprintf("SPIRE volumes detected on workload %s; mTLS mode: %s", rt.Spec.TargetRef.Name, mtlsMode))
827+
} else {
828+
msg := "mTLS requires SPIRE; either deploy SPIRE or set mTLSMode: disabled"
829+
r.setCondition(rt, ConditionTypeMTLSReady, metav1.ConditionFalse, "SPIREUnavailable", msg)
830+
if r.Recorder != nil {
831+
r.Recorder.Eventf(rt, nil, corev1.EventTypeWarning, "SPIREUnavailable",
832+
"MTLSReadyCheck", msg)
833+
}
834+
logger.Info("SPIRE not detected for mTLS-enabled workload",
835+
"workload", rt.Spec.TargetRef.Name, "mtlsMode", mtlsMode)
836+
}
837+
}
838+
766839
func (r *AgentRuntimeReconciler) setCondition(rt *agentv1alpha1.AgentRuntime, condType string, status metav1.ConditionStatus, reason, message string) {
767840
meta.SetStatusCondition(&rt.Status.Conditions, metav1.Condition{
768841
Type: condType,

0 commit comments

Comments
 (0)