MATIH Platform is in active MVP development. Documentation reflects current implementation status.
17. Kubernetes & Helm
Security
RBAC

RBAC

Role-Based Access Control (RBAC) in the MATIH platform restricts Kubernetes API access based on the principle of least privilege. Each service runs with a dedicated ServiceAccount that has only the permissions required for its operation, and administrative access is controlled through namespaced Roles and ClusterRoles.


RBAC Architecture

User/ServiceAccount --> RoleBinding/ClusterRoleBinding --> Role/ClusterRole --> API Resources

ServiceAccount Strategy

Each service deployment uses a dedicated ServiceAccount:

ServiceServiceAccountNamespacePurpose
AI Serviceai-servicematih-data-planeAccess ConfigMaps, Secrets
Query Enginequery-enginematih-data-planeAccess ConfigMaps
API Gatewayapi-gatewaymatih-systemAccess Endpoints, Services
Tenant Servicetenant-servicematih-systemCreate Namespaces, Secrets, Deployments
cert-managercert-managercert-managerManage Certificates, DNS
Prometheusprometheusmatih-monitoringRead all namespace metrics

Role Types

TypeScopeUse Case
RoleNamespaceService-specific permissions within its namespace
ClusterRoleCluster-wideCross-namespace or cluster-level permissions
RoleBindingNamespaceBinds a Role/ClusterRole to a subject in a namespace
ClusterRoleBindingCluster-wideBinds a ClusterRole to a subject globally

Standard Service Role

Most data plane services need minimal permissions:

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: ai-service
  namespace: matih-data-plane
rules:
  - apiGroups: [""]
    resources: ["configmaps"]
    verbs: ["get", "list", "watch"]
  - apiGroups: [""]
    resources: ["secrets"]
    resourceNames: ["ai-service-secrets"]
    verbs: ["get"]

Tenant Service Role (Elevated)

The Tenant Service requires elevated permissions for tenant provisioning:

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: tenant-provisioner
rules:
  - apiGroups: [""]
    resources: ["namespaces"]
    verbs: ["create", "get", "list", "delete"]
  - apiGroups: [""]
    resources: ["secrets", "configmaps", "services"]
    verbs: ["create", "get", "list", "update", "delete"]
  - apiGroups: ["apps"]
    resources: ["deployments", "statefulsets"]
    verbs: ["create", "get", "list", "update", "delete"]
  - apiGroups: ["networking.k8s.io"]
    resources: ["networkpolicies", "ingresses"]
    verbs: ["create", "get", "list", "update", "delete"]

Monitoring ServiceAccount

Prometheus requires read access across all namespaces for metric scraping:

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: prometheus-reader
rules:
  - apiGroups: [""]
    resources: ["pods", "endpoints", "services"]
    verbs: ["get", "list", "watch"]
  - apiGroups: [""]
    resources: ["nodes/metrics"]
    verbs: ["get"]
  - nonResourceURLs: ["/metrics"]
    verbs: ["get"]

Human Access Roles

RoleScopePermissions
Platform AdminClusterFull cluster access (limited to break-glass)
OperatorClusterRead all, write to specific namespaces
DeveloperNamespaceRead pods, logs, exec into dev pods
ViewerNamespaceRead-only access to resources

Developer Role

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: developer
  namespace: matih-data-plane
rules:
  - apiGroups: [""]
    resources: ["pods", "pods/log"]
    verbs: ["get", "list", "watch"]
  - apiGroups: [""]
    resources: ["pods/exec"]
    verbs: ["create"]
  - apiGroups: ["apps"]
    resources: ["deployments"]
    verbs: ["get", "list"]

RBAC Best Practices

PracticeImplementation
Least privilegeEach service only gets permissions it needs
Namespace scopingPrefer Roles over ClusterRoles
Named resourcesUse resourceNames to restrict to specific secrets
No wildcardsAvoid * in resources or verbs
Audit loggingEnable Kubernetes audit logging for RBAC decisions
Regular reviewQuarterly review of all ClusterRoleBindings

Helm Integration

ServiceAccounts and RBAC resources are created by Helm charts:

# values.yaml
serviceAccount:
  create: true
  name: ai-service
  annotations:
    azure.workload.identity/client-id: "CLIENT_ID"
 
rbac:
  create: true
  rules:
    - apiGroups: [""]
      resources: ["configmaps"]
      verbs: ["get", "list"]

Troubleshooting

IssueSymptomResolution
Forbidden errorUser cannot get resourceAdd missing RBAC rule
Secret access deniedPod cannot read secretVerify Role includes secret access
Cross-namespace deniedCannot access resource in other namespaceUse ClusterRole + RoleBinding
ServiceAccount missingPod uses default SAVerify serviceAccountName in deployment