Compare commits

..

5 Commits

Author SHA1 Message Date
Andrew Stoltz
30e04a10c6 security(guacamole): scope guacd Kubernetes exec RBAC 2026-06-18 15:05:43 -05:00
Andrew Stoltz
fc24102fb9 docs(agent-zero): align kubectl tool text with SEC-6 RBAC 2026-06-18 14:47:04 -05:00
Andrew Stoltz
a77fbd0381 security(agent-zero): remove cluster RBAC entirely + no token mount (operator directive — MCP only)
Operator: agent-zero must reach the cluster ONLY through gated MCP tools, not a
service account with cluster roles for raw kubectl. Removed the read-only
ClusterRole/ClusterRoleBinding entirely (SA now has zero cluster perms) and set
automountServiceAccountToken: false so no K8s API token is mounted at all.
Applied live (SA secrets/exec/pods/namespaces -> all Forbidden); this makes it
durable so ArgoCD selfHeal won't re-create any role.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-18 14:46:07 -05:00
Andrew Stoltz
191eb91642 security(agent-zero): replace cluster-admin with least-privilege read-only RBAC (SEC-6/RBAC-001)
agent-zero is an LLM agent; cluster-admin let raw kubectl bypass the MCP layer to
read every Secret / exec any pod. Swap for a read-only ClusterRole (no secrets/
configmaps/exec/writes) so sensitive + mutating actions go through gated MCP tools.
Already applied live + verified (secrets/exec/write -> Forbidden, observe stays);
this makes it durable so ArgoCD selfHeal doesn't revert to cluster-admin.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-18 14:46:07 -05:00
e4e03643a4 Merge PR #46: Harden UpdateCenter public route methods
P0 public-host containment: keep update.flowercore.io GET/HEAD only and preserve regression tests.
2026-06-18 15:38:59 +00:00
3 changed files with 285 additions and 23 deletions

View File

@@ -75,19 +75,12 @@ metadata:
name: agent-zero
namespace: agent-zero
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: agent-zero-cluster-admin
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: cluster-admin
subjects:
- kind: ServiceAccount
name: agent-zero
namespace: agent-zero
# SEC-6 / audit RBAC-001 (operator directive 2026-06-17): agent-zero is an LLM
# agent and must reach the cluster ONLY through gated MCP tools — NOT raw kubectl.
# It therefore has NO ClusterRole/ClusterRoleBinding at all, and the pod sets
# automountServiceAccountToken: false (below) so no Kubernetes API token is even
# mounted. History: cluster-admin -> read-only -> (now) no cluster RBAC / no token.
# Detail: FlowerCore.Notes docs/security/sec-6-agent-zero-rbac-remediation.md.
# =============================================================================
# Agent Zero — AI Agent Web UI (NUC Edition, Blue Jay Profile)
@@ -189,6 +182,9 @@ spec:
app: agent-zero
spec:
serviceAccountName: agent-zero
# SEC-6: no Kubernetes API token mounted — agent-zero reaches the cluster
# only via gated MCP tools, never raw kubectl. (RBAC is also removed above.)
automountServiceAccountToken: false
initContainers:
# Wait for fc-llm-bridge to be reachable before starting Agent Zero.
- name: wait-for-llm-bridge

View File

@@ -3616,7 +3616,8 @@ data:
kubectl_manager.py: |
# Kubernetes Cluster Management Tool
# Manages Kubernetes resources via kubectl on a Rancher Desktop (k3s) cluster.
# The pod runs with a cluster-admin ServiceAccount so all operations are permitted.
# SEC-6: the pod has no mounted Kubernetes API token and no cluster RBAC.
# Cluster operations must go through gated FlowerCore MCP tools instead.
# kubectl is located at /usr/local/bin/kubectl.
import subprocess
@@ -4442,7 +4443,8 @@ data:
### Notes
- The Agent Zero pod has `cluster-admin` privileges; all kubectl operations are permitted.
- The Agent Zero pod has no mounted Kubernetes API token and no cluster RBAC.
- Cluster operations must go through gated FlowerCore MCP tools instead of raw kubectl.
- kubectl is located at `/usr/local/bin/kubectl`.
- Long outputs are truncated to 4000 characters to avoid flooding.
- The `exec_command` action has a 30-second timeout.

View File

@@ -225,8 +225,7 @@ spec:
- "--port=8001"
- "--address=127.0.0.1"
- "--accept-hosts=.*"
- "--accept-paths=.*"
- "--disable-filter=true"
- "--accept-paths=^/api/v1/namespaces/(argocd|gitea|telephony|traefik-system|zabbix|matrix|irc|mail|selenium)/pods(/[^/]+(/(exec|attach))?)?$"
- "--v=2"
resources:
requests:
@@ -526,10 +525,13 @@ metadata:
name: guacd-exec
namespace: guacamole
---
# Namespace-scoped exec/list rights for the Kubernetes protocol and sync job.
# Keep this allowlist in lockstep with TARGET_NAMESPACES below.
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
kind: Role
metadata:
name: guacd-pod-exec
namespace: argocd
labels:
app.kubernetes.io/component: proxy
app.kubernetes.io/name: guacd
@@ -540,20 +542,282 @@ rules:
- apiGroups: [""]
resources: ["pods/exec", "pods/attach"]
verbs: ["create", "get"]
- apiGroups: [""]
resources: ["namespaces"]
verbs: ["list", "get"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
kind: RoleBinding
metadata:
name: guacd-pod-exec
namespace: argocd
labels:
app.kubernetes.io/component: proxy
app.kubernetes.io/name: guacd
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
kind: Role
name: guacd-pod-exec
subjects:
- kind: ServiceAccount
name: guacd-exec
namespace: guacamole
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: guacd-pod-exec
namespace: gitea
labels:
app.kubernetes.io/component: proxy
app.kubernetes.io/name: guacd
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "list"]
- apiGroups: [""]
resources: ["pods/exec", "pods/attach"]
verbs: ["create", "get"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: guacd-pod-exec
namespace: gitea
labels:
app.kubernetes.io/component: proxy
app.kubernetes.io/name: guacd
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: guacd-pod-exec
subjects:
- kind: ServiceAccount
name: guacd-exec
namespace: guacamole
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: guacd-pod-exec
namespace: telephony
labels:
app.kubernetes.io/component: proxy
app.kubernetes.io/name: guacd
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "list"]
- apiGroups: [""]
resources: ["pods/exec", "pods/attach"]
verbs: ["create", "get"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: guacd-pod-exec
namespace: telephony
labels:
app.kubernetes.io/component: proxy
app.kubernetes.io/name: guacd
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: guacd-pod-exec
subjects:
- kind: ServiceAccount
name: guacd-exec
namespace: guacamole
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: guacd-pod-exec
namespace: traefik-system
labels:
app.kubernetes.io/component: proxy
app.kubernetes.io/name: guacd
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "list"]
- apiGroups: [""]
resources: ["pods/exec", "pods/attach"]
verbs: ["create", "get"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: guacd-pod-exec
namespace: traefik-system
labels:
app.kubernetes.io/component: proxy
app.kubernetes.io/name: guacd
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: guacd-pod-exec
subjects:
- kind: ServiceAccount
name: guacd-exec
namespace: guacamole
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: guacd-pod-exec
namespace: zabbix
labels:
app.kubernetes.io/component: proxy
app.kubernetes.io/name: guacd
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "list"]
- apiGroups: [""]
resources: ["pods/exec", "pods/attach"]
verbs: ["create", "get"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: guacd-pod-exec
namespace: zabbix
labels:
app.kubernetes.io/component: proxy
app.kubernetes.io/name: guacd
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: guacd-pod-exec
subjects:
- kind: ServiceAccount
name: guacd-exec
namespace: guacamole
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: guacd-pod-exec
namespace: matrix
labels:
app.kubernetes.io/component: proxy
app.kubernetes.io/name: guacd
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "list"]
- apiGroups: [""]
resources: ["pods/exec", "pods/attach"]
verbs: ["create", "get"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: guacd-pod-exec
namespace: matrix
labels:
app.kubernetes.io/component: proxy
app.kubernetes.io/name: guacd
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: guacd-pod-exec
subjects:
- kind: ServiceAccount
name: guacd-exec
namespace: guacamole
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: guacd-pod-exec
namespace: irc
labels:
app.kubernetes.io/component: proxy
app.kubernetes.io/name: guacd
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "list"]
- apiGroups: [""]
resources: ["pods/exec", "pods/attach"]
verbs: ["create", "get"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: guacd-pod-exec
namespace: irc
labels:
app.kubernetes.io/component: proxy
app.kubernetes.io/name: guacd
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: guacd-pod-exec
subjects:
- kind: ServiceAccount
name: guacd-exec
namespace: guacamole
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: guacd-pod-exec
namespace: mail
labels:
app.kubernetes.io/component: proxy
app.kubernetes.io/name: guacd
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "list"]
- apiGroups: [""]
resources: ["pods/exec", "pods/attach"]
verbs: ["create", "get"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: guacd-pod-exec
namespace: mail
labels:
app.kubernetes.io/component: proxy
app.kubernetes.io/name: guacd
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: guacd-pod-exec
subjects:
- kind: ServiceAccount
name: guacd-exec
namespace: guacamole
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: guacd-pod-exec
namespace: selenium
labels:
app.kubernetes.io/component: proxy
app.kubernetes.io/name: guacd
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "list"]
- apiGroups: [""]
resources: ["pods/exec", "pods/attach"]
verbs: ["create", "get"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: guacd-pod-exec
namespace: selenium
labels:
app.kubernetes.io/component: proxy
app.kubernetes.io/name: guacd
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: guacd-pod-exec
subjects:
- kind: ServiceAccount