Copy """
Generate RBAC resources for platform teams.
"""
from dataclasses import dataclass
from typing import List, Dict, Any
import yaml
@dataclass
class TeamConfig:
"""Configuration for a platform team."""
name: str
namespace: str
admin_group: str
developer_group: str
readonly_group: str
allowed_resources: List[str]
class RBACGenerator:
"""Generate Kubernetes RBAC resources."""
def __init__(self, team: TeamConfig):
self.team = team
def generate_all(self) -> List[Dict[str, Any]]:
"""Generate all RBAC resources for a team."""
resources = []
# Namespace
resources.append(self._generate_namespace())
# Roles
resources.append(self._generate_admin_role())
resources.append(self._generate_developer_role())
resources.append(self._generate_readonly_role())
# RoleBindings
resources.append(self._generate_admin_binding())
resources.append(self._generate_developer_binding())
resources.append(self._generate_readonly_binding())
# NetworkPolicy for namespace isolation
resources.append(self._generate_network_policy())
# ResourceQuota
resources.append(self._generate_resource_quota())
return resources
def _generate_namespace(self) -> Dict[str, Any]:
return {
"apiVersion": "v1",
"kind": "Namespace",
"metadata": {
"name": self.team.namespace,
"labels": {
"team": self.team.name,
"managed-by": "platform",
},
},
}
def _generate_admin_role(self) -> Dict[str, Any]:
return {
"apiVersion": "rbac.authorization.k8s.io/v1",
"kind": "Role",
"metadata": {
"name": "team-admin",
"namespace": self.team.namespace,
},
"rules": [
{
"apiGroups": ["", "apps", "batch"],
"resources": ["*"],
"verbs": ["*"],
},
{
"apiGroups": ["platform.example.com"],
"resources": self.team.allowed_resources,
"verbs": ["*"],
},
],
}
def _generate_developer_role(self) -> Dict[str, Any]:
return {
"apiVersion": "rbac.authorization.k8s.io/v1",
"kind": "Role",
"metadata": {
"name": "team-developer",
"namespace": self.team.namespace,
},
"rules": [
{
"apiGroups": ["apps"],
"resources": ["deployments", "replicasets"],
"verbs": ["get", "list", "watch", "create", "update", "patch"],
},
{
"apiGroups": [""],
"resources": ["pods", "services", "configmaps"],
"verbs": ["get", "list", "watch", "create", "update", "patch"],
},
{
"apiGroups": [""],
"resources": ["pods/log", "pods/exec"],
"verbs": ["get", "create"],
},
{
"apiGroups": ["platform.example.com"],
"resources": self.team.allowed_resources,
"verbs": ["get", "list", "watch", "create", "update"],
},
],
}
def _generate_readonly_role(self) -> Dict[str, Any]:
return {
"apiVersion": "rbac.authorization.k8s.io/v1",
"kind": "Role",
"metadata": {
"name": "team-readonly",
"namespace": self.team.namespace,
},
"rules": [
{
"apiGroups": ["", "apps", "batch"],
"resources": ["*"],
"verbs": ["get", "list", "watch"],
},
],
}
def _generate_admin_binding(self) -> Dict[str, Any]:
return {
"apiVersion": "rbac.authorization.k8s.io/v1",
"kind": "RoleBinding",
"metadata": {
"name": "team-admin-binding",
"namespace": self.team.namespace,
},
"subjects": [{
"kind": "Group",
"name": self.team.admin_group,
"apiGroup": "rbac.authorization.k8s.io",
}],
"roleRef": {
"kind": "Role",
"name": "team-admin",
"apiGroup": "rbac.authorization.k8s.io",
},
}
def _generate_developer_binding(self) -> Dict[str, Any]:
return {
"apiVersion": "rbac.authorization.k8s.io/v1",
"kind": "RoleBinding",
"metadata": {
"name": "team-developer-binding",
"namespace": self.team.namespace,
},
"subjects": [{
"kind": "Group",
"name": self.team.developer_group,
"apiGroup": "rbac.authorization.k8s.io",
}],
"roleRef": {
"kind": "Role",
"name": "team-developer",
"apiGroup": "rbac.authorization.k8s.io",
},
}
def _generate_readonly_binding(self) -> Dict[str, Any]:
return {
"apiVersion": "rbac.authorization.k8s.io/v1",
"kind": "RoleBinding",
"metadata": {
"name": "team-readonly-binding",
"namespace": self.team.namespace,
},
"subjects": [{
"kind": "Group",
"name": self.team.readonly_group,
"apiGroup": "rbac.authorization.k8s.io",
}],
"roleRef": {
"kind": "Role",
"name": "team-readonly",
"apiGroup": "rbac.authorization.k8s.io",
},
}
def _generate_network_policy(self) -> Dict[str, Any]:
"""Default deny with allow same-namespace and system."""
return {
"apiVersion": "networking.k8s.io/v1",
"kind": "NetworkPolicy",
"metadata": {
"name": "default-deny-with-exceptions",
"namespace": self.team.namespace,
},
"spec": {
"podSelector": {},
"policyTypes": ["Ingress", "Egress"],
"ingress": [
# Allow from same namespace
{"from": [{"podSelector": {}}]},
# Allow from ingress controller
{"from": [{"namespaceSelector": {"matchLabels": {"name": "ingress-nginx"}}}]},
# Allow from monitoring
{"from": [{"namespaceSelector": {"matchLabels": {"name": "monitoring"}}}]},
],
"egress": [
# Allow to same namespace
{"to": [{"podSelector": {}}]},
# Allow DNS
{"to": [{"namespaceSelector": {}}], "ports": [{"port": 53, "protocol": "UDP"}]},
# Allow to platform services
{"to": [{"namespaceSelector": {"matchLabels": {"name": "platform-system"}}}]},
],
},
}
def _generate_resource_quota(self) -> Dict[str, Any]:
"""Default resource quota for namespace."""
return {
"apiVersion": "v1",
"kind": "ResourceQuota",
"metadata": {
"name": "team-quota",
"namespace": self.team.namespace,
},
"spec": {
"hard": {
"requests.cpu": "10",
"requests.memory": "20Gi",
"limits.cpu": "20",
"limits.memory": "40Gi",
"persistentvolumeclaims": "10",
"services.loadbalancers": "2",
},
},
}
# Usage
team = TeamConfig(
name="checkout",
namespace="checkout-team",
admin_group="checkout-admins",
developer_group="checkout-developers",
readonly_group="checkout-viewers",
allowed_resources=["applications", "databases", "caches"],
)
generator = RBACGenerator(team)
resources = generator.generate_all()
for resource in resources:
print(yaml.dump(resource, default_flow_style=False))
print("---")