feat: add operational RBAC — scoped ServiceAccounts for scripts
All checks were successful
AI Review / AI Code Review (pull_request) Successful in 4s
PR Checks / Validate & Security Scan (pull_request) Successful in 8s

Create least-privilege ServiceAccounts for k8s-audit, drift-check,
and keycloak-secrets-manager instead of sharing admin kubeconfig.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
root 2026-02-17 21:12:02 +01:00
parent d3dac72f96
commit 1ab66afa5f
4 changed files with 236 additions and 0 deletions

View File

@ -0,0 +1,67 @@
apiVersion: v1
kind: ServiceAccount
metadata:
name: drift-check
namespace: kube-system
---
apiVersion: v1
kind: Secret
metadata:
name: drift-check-token
namespace: kube-system
annotations:
kubernetes.io/service-account.name: drift-check
type: kubernetes.io/service-account-token
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: drift-check
rules:
# kubectl get pods -n {dev,staging,prod} -l ... -o jsonpath
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "list"]
---
# Namespace-scoped bindings — only dev, staging, prod
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: drift-check
namespace: dev
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: drift-check
subjects:
- kind: ServiceAccount
name: drift-check
namespace: kube-system
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: drift-check
namespace: staging
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: drift-check
subjects:
- kind: ServiceAccount
name: drift-check
namespace: kube-system
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: drift-check
namespace: prod
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: drift-check
subjects:
- kind: ServiceAccount
name: drift-check
namespace: kube-system

View File

@ -0,0 +1,61 @@
apiVersion: v1
kind: ServiceAccount
metadata:
name: k8s-audit
namespace: kube-system
---
apiVersion: v1
kind: Secret
metadata:
name: k8s-audit-token
namespace: kube-system
annotations:
kubernetes.io/service-account.name: k8s-audit
type: kubernetes.io/service-account-token
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: k8s-audit
rules:
# kubectl get pods -A -o wide
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "list"]
# kubectl logs (kube-bench pod)
- apiGroups: [""]
resources: ["pods/log"]
verbs: ["get"]
# kubectl get clusterrolebindings
- apiGroups: ["rbac.authorization.k8s.io"]
resources: ["clusterrolebindings"]
verbs: ["get", "list"]
# kubectl get networkpolicies -A
- apiGroups: ["networking.k8s.io"]
resources: ["networkpolicies"]
verbs: ["get", "list"]
# kubectl get namespaces --show-labels
- apiGroups: [""]
resources: ["namespaces"]
verbs: ["get", "list"]
# kubectl get nodes -o wide
- apiGroups: [""]
resources: ["nodes"]
verbs: ["get", "list"]
# kubectl get vulnerabilityreports -A (Trivy CRD)
- apiGroups: ["aquasecurity.github.io"]
resources: ["vulnerabilityreports"]
verbs: ["get", "list"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: k8s-audit
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: k8s-audit
subjects:
- kind: ServiceAccount
name: k8s-audit
namespace: kube-system

View File

@ -0,0 +1,87 @@
apiVersion: v1
kind: ServiceAccount
metadata:
name: keycloak-secrets-manager
namespace: kube-system
---
apiVersion: v1
kind: Secret
metadata:
name: keycloak-secrets-manager-token
namespace: kube-system
annotations:
kubernetes.io/service-account.name: keycloak-secrets-manager
type: kubernetes.io/service-account-token
---
# ClusterRole for namespace get/create (cluster-scoped operation)
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: keycloak-secrets-manager
rules:
- apiGroups: [""]
resources: ["namespaces"]
verbs: ["get", "create"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: keycloak-secrets-manager
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: keycloak-secrets-manager
subjects:
- kind: ServiceAccount
name: keycloak-secrets-manager
namespace: kube-system
---
# Secrets management in keycloak namespace
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: keycloak-secrets-manager
namespace: keycloak
rules:
- apiGroups: [""]
resources: ["secrets"]
verbs: ["get", "create", "update", "patch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: keycloak-secrets-manager
namespace: keycloak
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: keycloak-secrets-manager
subjects:
- kind: ServiceAccount
name: keycloak-secrets-manager
namespace: kube-system
---
# Secrets management in argocd namespace
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: keycloak-secrets-manager
namespace: argocd
rules:
- apiGroups: [""]
resources: ["secrets"]
verbs: ["get", "create", "update", "patch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: keycloak-secrets-manager
namespace: argocd
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: keycloak-secrets-manager
subjects:
- kind: ServiceAccount
name: keycloak-secrets-manager
namespace: kube-system

View File

@ -0,0 +1,21 @@
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: operational-rbac
namespace: argocd
finalizers:
- resources-finalizer.argocd.argoproj.io
spec:
project: default
source:
repoURL: http://10.10.10.1:3000/claude/k8s-apps.git
targetRevision: main
path: apps/operational-rbac
destination:
server: https://kubernetes.default.svc
syncPolicy:
automated:
prune: true
selfHeal: true
syncOptions:
- CreateNamespace=false