fix(ci): M1 split tailscale RBAC out of app manifests, drop deployer rolebinding grant
The dashboard/dagster manifests bundled the tailscale-sidecar SA+Role+RoleBinding, which forced the webhook-triggered fxhnt-ci-deployer SA to hold create/update/patch on roles/rolebindings in its own namespace — a privilege-escalation primitive. Move those 6 objects to infra/k8s/rbac/tailscale-sidecars.yaml, applied once out-of-band (not by CI); trim the deployer Role to drop rbac.authorization.k8s.io entirely, and drop serviceaccounts too since neither CI-applied manifest creates one anymore. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -53,22 +53,20 @@ rules:
|
||||
- apiGroups: [""]
|
||||
resources: ["pods"]
|
||||
verbs: ["get", "list", "watch"]
|
||||
# the fxhnt-dashboard + dagster manifests also bundle ConfigMaps + ServiceAccounts (the tailscale sidecar
|
||||
# serve-config + its identity) — kubectl apply of the whole file must be able to read/apply them.
|
||||
# the fxhnt-dashboard + dagster manifests also bundle ConfigMaps (the tailscale sidecar serve-config) —
|
||||
# kubectl apply of the whole file must be able to read/apply them. NOTE (CI review M1): the tailscale
|
||||
# ServiceAccount + Role + RoleBinding objects were MOVED out of these app manifests into
|
||||
# infra/k8s/rbac/tailscale-sidecars.yaml (applied once, out-of-band, by a human) specifically so this
|
||||
# deployer SA does not need roles/rolebindings/serviceaccounts create-update-patch — that combination on a
|
||||
# webhook-triggered SA is a privilege-escalation primitive. Neither manifest applied by CI creates a
|
||||
# ServiceAccount anymore, so `serviceaccounts` is dropped from this grant too.
|
||||
- apiGroups: [""]
|
||||
resources: ["configmaps", "serviceaccounts"]
|
||||
resources: ["configmaps"]
|
||||
verbs: ["get", "list", "watch", "create", "update", "patch"]
|
||||
# the manifests apply NetworkPolicies (fxhnt-cockpit.yaml + dagster's).
|
||||
- apiGroups: ["networking.k8s.io"]
|
||||
resources: ["networkpolicies"]
|
||||
verbs: ["get", "list", "watch", "create", "update", "patch"]
|
||||
# the dashboard + dagster manifests bundle the tailscale-sidecar Role/RoleBinding. NOTE: granting a deployer
|
||||
# SA rbac-management in its own namespace is privilege-escalation-adjacent — it is deliberately scoped to the
|
||||
# foxhunt namespace only (no cluster-wide roles) and exists solely because the app manifests co-locate this
|
||||
# RBAC with the Deployment. Kept minimal (no escalate/bind verbs beyond what apply needs).
|
||||
- apiGroups: ["rbac.authorization.k8s.io"]
|
||||
resources: ["roles", "rolebindings"]
|
||||
verbs: ["get", "list", "watch", "create", "update", "patch"]
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: RoleBinding
|
||||
|
||||
@@ -115,36 +115,6 @@ data:
|
||||
}
|
||||
}
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata: { name: tailscale-dagster, namespace: foxhunt }
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: Role
|
||||
metadata: { name: tailscale-dagster, namespace: foxhunt }
|
||||
rules:
|
||||
- apiGroups: [""]
|
||||
resources: ["secrets"]
|
||||
verbs: ["create", "get", "update", "patch", "list", "watch"]
|
||||
# K8sRunLauncher: the daemon launches each Dagster run as its OWN K8s Job (own memory) so the heavy
|
||||
# bybit_book_precompute asset (6-8Gi) never OOMs the 4Gi daemon. Needs to manage Jobs + read their pods/logs.
|
||||
- apiGroups: ["batch"]
|
||||
resources: ["jobs"]
|
||||
verbs: ["create", "get", "list", "watch", "delete"]
|
||||
- apiGroups: [""]
|
||||
resources: ["pods", "pods/log"]
|
||||
verbs: ["get", "list", "watch"]
|
||||
- apiGroups: [""]
|
||||
resources: ["events"]
|
||||
verbs: ["get", "list", "watch"]
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: RoleBinding
|
||||
metadata: { name: tailscale-dagster, namespace: foxhunt }
|
||||
subjects:
|
||||
- { kind: ServiceAccount, name: tailscale-dagster, namespace: foxhunt }
|
||||
roleRef: { kind: Role, name: tailscale-dagster, apiGroup: rbac.authorization.k8s.io }
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
|
||||
72
infra/k8s/rbac/tailscale-sidecars.yaml
Normal file
72
infra/k8s/rbac/tailscale-sidecars.yaml
Normal file
@@ -0,0 +1,72 @@
|
||||
# Tailscale sidecar RBAC (ServiceAccount + Role + RoleBinding) for the fxhnt-dashboard and dagster
|
||||
# Deployments. Moved out of infra/k8s/services/fxhnt-dashboard.yaml and infra/k8s/orchestration/dagster.yaml
|
||||
# (CI review M1): those app manifests are applied every deploy by the fxhnt-ci-deployer ServiceAccount via
|
||||
# the kubectl-deploy Argo template, and having RBAC objects bundled in there meant the deployer SA needed
|
||||
# create/update/patch on roles/rolebindings in its own namespace — a privilege-escalation primitive on a
|
||||
# webhook-triggered SA. This file is STATIC and applied ONCE, out-of-band, by a human:
|
||||
#
|
||||
# kubectl apply -f infra/k8s/rbac/tailscale-sidecars.yaml
|
||||
#
|
||||
# It is NOT applied by the CI pipeline. The Deployments still reference these ServiceAccounts via
|
||||
# `serviceAccountName: tailscale-dashboard` / `tailscale-dagster` — that reference resolves because the
|
||||
# SAs are managed here, separately, not because the app manifests create them anymore.
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
name: tailscale-dashboard
|
||||
namespace: foxhunt
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: Role
|
||||
metadata:
|
||||
name: tailscale-dashboard
|
||||
namespace: foxhunt
|
||||
rules:
|
||||
- apiGroups: [""]
|
||||
resources: ["secrets"]
|
||||
verbs: ["create", "get", "update", "patch", "list", "watch"]
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: RoleBinding
|
||||
metadata:
|
||||
name: tailscale-dashboard
|
||||
namespace: foxhunt
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: tailscale-dashboard
|
||||
namespace: foxhunt
|
||||
roleRef:
|
||||
kind: Role
|
||||
name: tailscale-dashboard
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata: { name: tailscale-dagster, namespace: foxhunt }
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: Role
|
||||
metadata: { name: tailscale-dagster, namespace: foxhunt }
|
||||
rules:
|
||||
- apiGroups: [""]
|
||||
resources: ["secrets"]
|
||||
verbs: ["create", "get", "update", "patch", "list", "watch"]
|
||||
# K8sRunLauncher: the daemon launches each Dagster run as its OWN K8s Job (own memory) so the heavy
|
||||
# bybit_book_precompute asset (6-8Gi) never OOMs the 4Gi daemon. Needs to manage Jobs + read their pods/logs.
|
||||
- apiGroups: ["batch"]
|
||||
resources: ["jobs"]
|
||||
verbs: ["create", "get", "list", "watch", "delete"]
|
||||
- apiGroups: [""]
|
||||
resources: ["pods", "pods/log"]
|
||||
verbs: ["get", "list", "watch"]
|
||||
- apiGroups: [""]
|
||||
resources: ["events"]
|
||||
verbs: ["get", "list", "watch"]
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: RoleBinding
|
||||
metadata: { name: tailscale-dagster, namespace: foxhunt }
|
||||
subjects:
|
||||
- { kind: ServiceAccount, name: tailscale-dagster, namespace: foxhunt }
|
||||
roleRef: { kind: Role, name: tailscale-dagster, apiGroup: rbac.authorization.k8s.io }
|
||||
@@ -112,33 +112,3 @@ metadata:
|
||||
spec:
|
||||
selector: { app.kubernetes.io/name: fxhnt-dashboard }
|
||||
ports: [{ port: 80, targetPort: 8080, name: http }]
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
name: tailscale-dashboard
|
||||
namespace: foxhunt
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: Role
|
||||
metadata:
|
||||
name: tailscale-dashboard
|
||||
namespace: foxhunt
|
||||
rules:
|
||||
- apiGroups: [""]
|
||||
resources: ["secrets"]
|
||||
verbs: ["create", "get", "update", "patch", "list", "watch"]
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: RoleBinding
|
||||
metadata:
|
||||
name: tailscale-dashboard
|
||||
namespace: foxhunt
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: tailscale-dashboard
|
||||
namespace: foxhunt
|
||||
roleRef:
|
||||
kind: Role
|
||||
name: tailscale-dashboard
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
|
||||
Reference in New Issue
Block a user