Skip to content

Fawkes Dojo Module 18: Multi-Tenancy & RBAC

🎯 Module Overview

Belt Level: ⚫ Black Belt - Platform Architecture Module: 2 of 4 (Black Belt) Duration: 90 minutes Difficulty: Expert Prerequisites:

  • Module 17: Platform Architecture complete
  • Deep Kubernetes knowledge
  • Security fundamentals
  • Understanding of identity systems

📚 Learning Objectives

By the end of this module, you will:

  1. ✅ Design multi-tenant platform architectures
  2. ✅ Implement robust RBAC systems
  3. ✅ Create security boundaries and isolation
  4. ✅ Manage namespace strategies at scale
  5. ✅ Implement policy enforcement with OPA
  6. ✅ Design quota and resource management
  7. ✅ Handle tenant lifecycle management

DORA Capabilities Addressed:

  • ✓ Security & Compliance
  • ✓ Access Control
  • ✓ Team Autonomy (with guardrails)
  • ✓ Resource Efficiency

📖 Part 1: Multi-Tenancy Fundamentals

What is Multi-Tenancy?

Definition: Multiple teams (tenants) sharing a platform while maintaining isolation

Isolation Levels:

┌─────────────────────────────────────────────────┐
│  Isolation Level            Cost    Security    │
├─────────────────────────────────────────────────┤
│  Soft (Namespace)           Low     Basic       │
│  Medium (vCluster)          Medium  Good        │
│  Hard (Separate Clusters)   High    Excellent   │
└─────────────────────────────────────────────────┘

Tenancy Models

Model 1: Namespace-per-Team

Cluster: production
├─ Namespace: team-alpha-prod
│  ├─ Deployment: service-a
│  ├─ Service: service-a
│  └─ ResourceQuota: team-alpha-quota
├─ Namespace: team-beta-prod
│  ├─ Deployment: service-b
│  └─ ResourceQuota: team-beta-quota
└─ Namespace: team-gamma-prod
   └─ Deployment: service-c

Pros:

  • ✅ Simple to implement
  • ✅ Low overhead
  • ✅ Easy cross-team communication

Cons:

  • ❌ Shared control plane (noisy neighbor)
  • ❌ Limited isolation
  • ❌ Version lock (same K8s version)

Best For: Internal teams, trusted tenants

Model 2: Virtual Clusters (vCluster)

Host Cluster
├─ Namespace: vcluster-team-alpha
│  └─ Virtual Control Plane
│     └─ Virtual Namespace: default
│        └─ Pods (run in host namespace)
├─ Namespace: vcluster-team-beta
│  └─ Virtual Control Plane
│     └─ Virtual Namespace: default
└─ Namespace: vcluster-team-gamma

Pros:

  • ✅ Full Kubernetes API per tenant
  • ✅ Different versions possible
  • ✅ Better isolation
  • ✅ Admin-level access per tenant

Cons:

  • ❌ More complex
  • ❌ Higher resource overhead
  • ❌ Cross-vCluster networking tricky

Best For: Agencies, managed services, dev environments

Model 3: Cluster-per-Team

┌──────────────┐  ┌──────────────┐  ┌──────────────┐
│ Team Alpha   │  │ Team Beta    │  │ Team Gamma   │
│ Cluster      │  │ Cluster      │  │ Cluster      │
│              │  │              │  │              │
│ Full Control │  │ Full Control │  │ Full Control │
└──────────────┘  └──────────────┘  └──────────────┘

Pros:

  • ✅ Complete isolation
  • ✅ Full autonomy
  • ✅ Blast radius contained

Cons:

  • ❌ High cost
  • ❌ Management overhead
  • ❌ Shared services duplication

Best For: Large enterprises, critical workloads, external customers

Security Boundaries

┌─────────────────────────────────────────────┐
│           Security Layers                    │
├─────────────────────────────────────────────┤
│  1. Network Policies (L3/L4)                │
│     └─ Block cross-namespace traffic        │
├─────────────────────────────────────────────┤
│  2. RBAC (API Access)                       │
│     └─ Who can do what                      │
├─────────────────────────────────────────────┤
│  3. Pod Security Standards                  │
│     └─ What containers can do               │
├─────────────────────────────────────────────┤
│  4. Policy Enforcement (OPA)                │
│     └─ Custom rules and validation          │
├─────────────────────────────────────────────┤
│  5. Resource Quotas                         │
│     └─ Prevent resource exhaustion          │
├─────────────────────────────────────────────┤
│  6. Service Mesh (mTLS)                     │
│     └─ Encrypted service-to-service         │
└─────────────────────────────────────────────┘

🔐 Part 2: Kubernetes RBAC Deep Dive

RBAC Components

User/ServiceAccount
        │
        │ (binds to)
        ▼
      Role/ClusterRole
        │
        │ (defines)
        ▼
    Permissions
  (verbs on resources)

Example RBAC Setup

1. Developer Role (Namespace-scoped)

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: developer
  namespace: team-alpha-prod
rules:
  # Read access to most resources
  - apiGroups: [""]
    resources: ["pods", "services", "configmaps", "secrets"]
    verbs: ["get", "list", "watch"]

  # Write access to deployments
  - apiGroups: ["apps"]
    resources: ["deployments", "replicasets"]
    verbs: ["get", "list", "watch", "create", "update", "patch"]

  # Execute into pods for debugging
  - apiGroups: [""]
    resources: ["pods/exec"]
    verbs: ["create"]

  # View logs
  - apiGroups: [""]
    resources: ["pods/log"]
    verbs: ["get"]

2. Admin Role (Namespace-scoped)

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: team-admin
  namespace: team-alpha-prod
rules:
  # Full access to namespace resources
  - apiGroups: ["*"]
    resources: ["*"]
    verbs: ["*"]

3. Platform Admin Role (Cluster-scoped)

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: platform-admin
rules:
  # Full cluster access
  - apiGroups: ["*"]
    resources: ["*"]
    verbs: ["*"]

  # Access to cluster-scoped resources
  - nonResourceURLs: ["*"]
    verbs: ["*"]

4. Read-Only Role (Cluster-scoped)

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: read-only
rules:
  - apiGroups: ["*"]
    resources: ["*"]
    verbs: ["get", "list", "watch"]

RoleBinding Examples

# Bind developer role to user
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: alice-developer
  namespace: team-alpha-prod
subjects:
  - kind: User
    name: alice@company.com
    apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: Role
  name: developer
  apiGroup: rbac.authorization.k8s.io

---
# Bind admin role to group
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: team-alpha-admins
  namespace: team-alpha-prod
subjects:
  - kind: Group
    name: team-alpha-leads
    apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: Role
  name: team-admin
  apiGroup: rbac.authorization.k8s.io

---
# Bind cluster role with ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: platform-admins
subjects:
  - kind: Group
    name: platform-team
    apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: ClusterRole
  name: platform-admin
  apiGroup: rbac.authorization.k8s.io

Service Account RBAC

# Service account for CI/CD
apiVersion: v1
kind: ServiceAccount
metadata:
  name: ci-deployer
  namespace: team-alpha-prod

---
# Role for deployment
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: deployer
  namespace: team-alpha-prod
rules:
  - apiGroups: ["apps"]
    resources: ["deployments"]
    verbs: ["get", "list", "update", "patch"]
  - apiGroups: [""]
    resources: ["pods"]
    verbs: ["get", "list"]

---
# Bind role to service account
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: ci-deployer-binding
  namespace: team-alpha-prod
subjects:
  - kind: ServiceAccount
    name: ci-deployer
    namespace: team-alpha-prod
roleRef:
  kind: Role
  name: deployer
  apiGroup: rbac.authorization.k8s.io

🏗️ Part 3: Namespace Strategy

Naming Convention

<team>-<environment>-<region>

Examples:
- team-alpha-prod-us-east
- team-alpha-staging-us-east
- team-alpha-dev-us-east
- team-beta-prod-eu-west
- platform-core-prod-us-east

Namespace Template

apiVersion: v1
kind: Namespace
metadata:
  name: team-alpha-prod
  labels:
    team: alpha
    environment: production
    region: us-east
    cost-center: "1234"
  annotations:
    description: "Team Alpha production workloads"
    owner: "alice@company.com"

---
# Resource Quota
apiVersion: v1
kind: ResourceQuota
metadata:
  name: team-alpha-quota
  namespace: team-alpha-prod
spec:
  hard:
    requests.cpu: "100"
    requests.memory: 200Gi
    limits.cpu: "200"
    limits.memory: 400Gi
    persistentvolumeclaims: "20"
    services.loadbalancers: "3"

---
# Limit Range (default limits)
apiVersion: v1
kind: LimitRange
metadata:
  name: team-alpha-limits
  namespace: team-alpha-prod
spec:
  limits:
    - max:
        cpu: "4"
        memory: "8Gi"
      min:
        cpu: "10m"
        memory: "10Mi"
      default:
        cpu: "500m"
        memory: "512Mi"
      defaultRequest:
        cpu: "100m"
        memory: "128Mi"
      type: Container

---
# Network Policy (deny all by default)
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny-all
  namespace: team-alpha-prod
spec:
  podSelector: {}
  policyTypes:
    - Ingress
    - Egress

Automated Namespace Provisioning

# namespace_provisioner.py
import kubernetes
from jinja2 import Template

class NamespaceProvisioner:
    def __init__(self, k8s_config):
        kubernetes.config.load_kube_config(k8s_config)
        self.api = kubernetes.client.CoreV1Api()
        self.rbac_api = kubernetes.client.RbacAuthorizationV1Api()

    def create_tenant_namespace(self, tenant_config):
        """
        Create namespace with all required resources

        Args:
            tenant_config: dict with team, environment, quotas, etc.
        """
        namespace_name = f"{tenant_config['team']}-{tenant_config['environment']}"

        # 1. Create namespace
        self._create_namespace(namespace_name, tenant_config)

        # 2. Create resource quota
        self._create_resource_quota(namespace_name, tenant_config['quotas'])

        # 3. Create limit ranges
        self._create_limit_range(namespace_name, tenant_config['limits'])

        # 4. Create network policies
        self._create_network_policies(namespace_name)

        # 5. Create RBAC roles
        self._create_rbac(namespace_name, tenant_config['members'])

        # 6. Create service accounts
        self._create_service_accounts(namespace_name)

        return namespace_name

    def _create_namespace(self, name, config):
        """Create namespace with labels and annotations"""
        namespace = kubernetes.client.V1Namespace(
            metadata=kubernetes.client.V1ObjectMeta(
                name=name,
                labels={
                    'team': config['team'],
                    'environment': config['environment'],
                    'managed-by': 'platform-automation'
                },
                annotations={
                    'owner': config['owner'],
                    'cost-center': config['cost_center'],
                    'created-by': 'namespace-provisioner'
                }
            )
        )
        self.api.create_namespace(namespace)
        print(f"✅ Created namespace: {name}")

    def _create_resource_quota(self, namespace, quotas):
        """Create resource quota"""
        quota = kubernetes.client.V1ResourceQuota(
            metadata=kubernetes.client.V1ObjectMeta(name="tenant-quota"),
            spec=kubernetes.client.V1ResourceQuotaSpec(
                hard={
                    'requests.cpu': quotas['cpu_requests'],
                    'requests.memory': quotas['memory_requests'],
                    'limits.cpu': quotas['cpu_limits'],
                    'limits.memory': quotas['memory_limits'],
                    'persistentvolumeclaims': str(quotas['pvc_count'])
                }
            )
        )
        self.api.create_namespaced_resource_quota(namespace, quota)
        print(f"✅ Created resource quota in {namespace}")

    def _create_rbac(self, namespace, members):
        """Create roles and role bindings for team members"""

        # Developer role
        dev_role = kubernetes.client.V1Role(
            metadata=kubernetes.client.V1ObjectMeta(name="developer"),
            rules=[
                kubernetes.client.V1PolicyRule(
                    api_groups=[""],
                    resources=["pods", "services", "configmaps"],
                    verbs=["get", "list", "watch"]
                ),
                kubernetes.client.V1PolicyRule(
                    api_groups=["apps"],
                    resources=["deployments"],
                    verbs=["get", "list", "watch", "update", "patch"]
                )
            ]
        )
        self.rbac_api.create_namespaced_role(namespace, dev_role)

        # Bind developers
        for member in members.get('developers', []):
            binding = kubernetes.client.V1RoleBinding(
                metadata=kubernetes.client.V1ObjectMeta(
                    name=f"{member}-developer"
                ),
                subjects=[
                    kubernetes.client.V1Subject(
                        kind="User",
                        name=member,
                        api_group="rbac.authorization.k8s.io"
                    )
                ],
                role_ref=kubernetes.client.V1RoleRef(
                    kind="Role",
                    name="developer",
                    api_group="rbac.authorization.k8s.io"
                )
            )
            self.rbac_api.create_namespaced_role_binding(namespace, binding)

        print(f"✅ Created RBAC in {namespace}")

# Usage
config = {
    'team': 'alpha',
    'environment': 'production',
    'owner': 'alice@company.com',
    'cost_center': '1234',
    'quotas': {
        'cpu_requests': '100',
        'memory_requests': '200Gi',
        'cpu_limits': '200',
        'memory_limits': '400Gi',
        'pvc_count': 20
    },
    'limits': {
        'default_cpu': '500m',
        'default_memory': '512Mi'
    },
    'members': {
        'developers': ['alice@company.com', 'bob@company.com'],
        'admins': ['carol@company.com']
    }
}

provisioner = NamespaceProvisioner('/path/to/kubeconfig')
namespace = provisioner.create_tenant_namespace(config)

🛡️ Part 4: Policy Enforcement with OPA

What is Open Policy Agent (OPA)?

Policy engine for cloud-native environments. Write policies as code.

OPA Gatekeeper

Kubernetes admission controller using OPA.

Installation

kubectl apply -f https://raw.githubusercontent.com/open-policy-agent/gatekeeper/master/deploy/gatekeeper.yaml

Example Policies

Policy 1: Require Labels

apiVersion: templates.gatekeeper.sh/v1
kind: ConstraintTemplate
metadata:
  name: k8srequiredlabels
spec:
  crd:
    spec:
      names:
        kind: K8sRequiredLabels
      validation:
        openAPIV3Schema:
          type: object
          properties:
            labels:
              type: array
              items:
                type: string
  targets:
    - target: admission.k8s.gatekeeper.sh
      rego: |
        package k8srequiredlabels

        violation[{"msg": msg, "details": {"missing_labels": missing}}] {
          provided := {label | input.review.object.metadata.labels[label]}
          required := {label | label := input.parameters.labels[_]}
          missing := required - provided
          count(missing) > 0
          msg := sprintf("Missing required labels: %v", [missing])
        }

---
# Apply the constraint
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sRequiredLabels
metadata:
  name: require-team-label
spec:
  match:
    kinds:
      - apiGroups: [""]
        kinds: ["Namespace"]
  parameters:
    labels: ["team", "environment", "cost-center"]

Policy 2: Block Privileged Containers

apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sPSPPrivilegedContainer
metadata:
  name: block-privileged-containers
spec:
  match:
    kinds:
      - apiGroups: [""]
        kinds: ["Pod"]
    excludedNamespaces:
      - kube-system
      - platform-core

Policy 3: Enforce Resource Limits

apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sContainerLimits
metadata:
  name: container-must-have-limits
spec:
  match:
    kinds:
      - apiGroups: [""]
        kinds: ["Pod"]
  parameters:
    cpu: "4"
    memory: "8Gi"

Policy 4: Restrict Registry Sources

apiVersion: templates.gatekeeper.sh/v1
kind: ConstraintTemplate
metadata:
  name: k8sallowedrepos
spec:
  crd:
    spec:
      names:
        kind: K8sAllowedRepos
  targets:
    - target: admission.k8s.gatekeeper.sh
      rego: |
        package k8sallowedrepos

        violation[{"msg": msg}] {
          container := input.review.object.spec.containers[_]
          satisfied := [good | repo = input.parameters.repos[_]
                              good = startswith(container.image, repo)]
          not any(satisfied)
          msg := sprintf("Container image %v not from approved registry", [container.image])
        }

---
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sAllowedRepos
metadata:
  name: allowed-registries
spec:
  match:
    kinds:
      - apiGroups: [""]
        kinds: ["Pod"]
  parameters:
    repos:
      - "harbor.company.com/"
      - "gcr.io/company/"

💰 Part 5: Resource Management

Resource Quotas by Team

# Small team
apiVersion: v1
kind: ResourceQuota
metadata:
  name: small-team-quota
  namespace: team-small-prod
spec:
  hard:
    requests.cpu: "20"
    requests.memory: 40Gi
    limits.cpu: "40"
    limits.memory: 80Gi
    pods: "50"
    services: "10"
    persistentvolumeclaims: "10"

---
# Medium team
apiVersion: v1
kind: ResourceQuota
metadata:
  name: medium-team-quota
  namespace: team-medium-prod
spec:
  hard:
    requests.cpu: "100"
    requests.memory: 200Gi
    limits.cpu: "200"
    limits.memory: 400Gi
    pods: "200"
    services: "50"
    persistentvolumeclaims: "50"

---
# Large team
apiVersion: v1
kind: ResourceQuota
metadata:
  name: large-team-quota
  namespace: team-large-prod
spec:
  hard:
    requests.cpu: "500"
    requests.memory: 1Ti
    limits.cpu: "1000"
    limits.memory: 2Ti
    pods: "1000"
    services: "200"
    persistentvolumeclaims: "200"

Priority Classes

# Critical workloads
apiVersion: scheduling.k8s.io/v1
kind: PriorityClass
metadata:
  name: critical
value: 1000000
globalDefault: false
description: "Critical production workloads"

---
# High priority
apiVersion: scheduling.k8s.io/v1
kind: PriorityClass
metadata:
  name: high
value: 100000
description: "High priority production workloads"

---
# Normal priority
apiVersion: scheduling.k8s.io/v1
kind: PriorityClass
metadata:
  name: normal
value: 10000
globalDefault: true
description: "Normal priority workloads"

---
# Low priority
apiVersion: scheduling.k8s.io/v1
kind: PriorityClass
metadata:
  name: low
value: 1000
description: "Low priority batch jobs"

Usage in Pod:

apiVersion: v1
kind: Pod
metadata:
  name: critical-app
spec:
  priorityClassName: critical
  containers:
    - name: app
      image: myapp:v1.0

🔒 Part 6: Network Isolation

Network Policies

Default Deny All

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny-all
  namespace: team-alpha-prod
spec:
  podSelector: {}
  policyTypes:
    - Ingress
    - Egress

Allow Within Namespace

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-same-namespace
  namespace: team-alpha-prod
spec:
  podSelector: {}
  policyTypes:
    - Ingress
  ingress:
    - from:
        - podSelector: {}

Allow from Ingress

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-from-ingress
  namespace: team-alpha-prod
spec:
  podSelector:
    matchLabels:
      role: frontend
  policyTypes:
    - Ingress
  ingress:
    - from:
        - namespaceSelector:
            matchLabels:
              name: ingress-nginx
      ports:
        - protocol: TCP
          port: 8080

Allow Egress to DNS and External

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-dns-and-external
  namespace: team-alpha-prod
spec:
  podSelector: {}
  policyTypes:
    - Egress
  egress:
    # Allow DNS
    - to:
        - namespaceSelector:
            matchLabels:
              name: kube-system
      ports:
        - protocol: UDP
          port: 53
    # Allow external HTTPS
    - to:
        - podSelector: {}
      ports:
        - protocol: TCP
          port: 443

💪 Part 7: Hands-On Lab - Build Multi-Tenant Platform

Scenario

Design multi-tenancy for 10 engineering teams.

Requirements:

  • Namespace isolation
  • RBAC for developers and admins
  • Resource quotas per team
  • Network policies (zero-trust)
  • Policy enforcement (OPA)
  • Cost allocation per team

Tasks

Task 1: Design Tenancy Model

  • [ ] Choose model (namespace/vcluster/cluster)
  • [ ] Define namespace naming convention
  • [ ] Create namespace template

Task 2: Implement RBAC

  • [ ] Create developer role
  • [ ] Create admin role
  • [ ] Create read-only role
  • [ ] Set up RoleBindings

Task 3: Configure Resource Management

  • [ ] Define quota tiers (small/medium/large)
  • [ ] Create LimitRanges
  • [ ] Set up PriorityClasses

Task 4: Implement Network Isolation

  • [ ] Default deny all traffic
  • [ ] Allow intra-namespace
  • [ ] Allow from ingress
  • [ ] Allow DNS and external

Task 5: Policy Enforcement

  • [ ] Require labels policy
  • [ ] Block privileged containers
  • [ ] Enforce resource limits
  • [ ] Restrict image registries

Task 6: Automation

  • [ ] Namespace provisioning script
  • [ ] RBAC automation
  • [ ] Onboarding documentation

Validation:

  • [ ] Namespace isolation working
  • [ ] RBAC permissions correct
  • [ ] Resource quotas enforced
  • [ ] Network policies blocking unauthorized traffic
  • [ ] OPA policies validating resources
  • [ ] Cost allocation labels present

🎓 Part 8: Knowledge Check

  1. What's the lightest multi-tenancy model?

  2. [x] Namespace-per-team

  3. [ ] vCluster
  4. [ ] Cluster-per-team
  5. [ ] Virtual machines

  6. What does RBAC stand for?

  7. [ ] Resource-Based Access Control

  8. [x] Role-Based Access Control
  9. [ ] Rule-Based Access Control
  10. [ ] Rights-Based Access Control

  11. Which is cluster-scoped?

  12. [ ] Role

  13. [x] ClusterRole
  14. [ ] RoleBinding
  15. [ ] ResourceQuota

  16. What does OPA stand for?

  17. [ ] Optimal Policy Agent

  18. [x] Open Policy Agent
  19. [ ] Orchestrated Policy Administration
  20. [ ] Operational Policy Automation

  21. What enforces resource limits per namespace?

  22. [ ] NetworkPolicy

  23. [ ] PodSecurityPolicy
  24. [x] ResourceQuota
  25. [ ] RBAC

  26. Default network policy should be:

  27. [x] Deny all, whitelist specific traffic

  28. [ ] Allow all, blacklist bad traffic
  29. [ ] No policy needed
  30. [ ] Allow within cluster only

  31. What does vCluster provide?

  32. [ ] Virtual machines

  33. [ ] Virtual networks
  34. [x] Virtual Kubernetes control planes
  35. [ ] Virtual storage

  36. Priority Classes are used for:

  37. [ ] Security levels
  38. [ ] Network priority
  39. [x] Pod scheduling priority during resource contention
  40. [ ] RBAC levels

Answers: 1-A, 2-B, 3-B, 4-B, 5-C, 6-A, 7-C, 8-C


🎯 Part 9: Module Summary & Next Steps

What You Learned

Multi-Tenancy Models: Namespace, vCluster, cluster-per-tenant ✅ RBAC Deep Dive: Roles, bindings, service accounts ✅ Namespace Strategy: Naming, templates, automation ✅ Policy Enforcement: OPA Gatekeeper policies ✅ Resource Management: Quotas, limits, priorities ✅ Network Isolation: NetworkPolicies, zero-trust

Key Takeaways

  1. Choose tenancy model wisely - Balance isolation, cost, complexity
  2. RBAC is foundational - Get permissions right from day one
  3. Automate tenant lifecycle - Manual provisioning doesn't scale
  4. Deny by default - Whitelist only necessary access
  5. Policy as code - OPA enables declarative governance
  6. Monitor quota usage - Prevent resource exhaustion
  7. Document everything - Clear ownership and boundaries

Real-World Impact

"After implementing proper multi-tenancy:

  • Onboarding time: 2 weeks → 1 hour (automation)
  • Security incidents: 12/year → 1/year (isolation)
  • Resource waste: 40% → 10% (quotas)
  • Cost allocation: Impossible → Precise (labels)
  • Team autonomy: Limited → High (self-service)
  • Compliance: Manual → Automated (OPA)

We scaled from 5 teams to 50 teams without increasing platform team size."

  • Platform Director, Tech Unicorn

📚 Additional Resources

Tools

Documentation

Books & Articles


🏅 Module Completion

Assessment Checklist

  • [ ] Conceptual Understanding

  • [ ] Explain tenancy models

  • [ ] Understand RBAC components
  • [ ] Know isolation strategies

  • [ ] Practical Skills

  • [ ] Design namespace strategy

  • [ ] Implement RBAC
  • [ ] Create OPA policies
  • [ ] Configure network policies
  • [ ] Automate provisioning

  • [ ] Hands-On Lab

  • [ ] Multi-tenant platform designed

  • [ ] RBAC implemented correctly
  • [ ] Policies enforcing rules
  • [ ] Isolation verified

  • [ ] Quiz

  • [ ] Score 80% or higher (6/8 questions)

Certification Credit

Upon completion, you earn:

  • 10 points toward Black Belt certification (50% complete)
  • Badge: "Multi-Tenancy Architect"
  • Skill Unlocked: Enterprise Platform Design

🎖️ Black Belt Progress

Black Belt: Platform Architecture
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Module 17: Platform Architecture   ████████░░░░ 25% ✓
Module 18: Multi-Tenancy & RBAC    ████████░░░░ 50% ✓
Module 19: Cost Optimization       ░░░░░░░░░░░░  0%
Module 20: Platform Leadership     ░░░░░░░░░░░░  0%
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

Halfway to Black Belt! 🎉

Next Module Preview: Module 19 - Cost Optimization (FinOps, right-sizing, cloud efficiency)


Fawkes Dojo - Where Platform Engineers Are Forged Version 1.0 | Last Updated: October 2025 License: MIT | https://github.com/paruff/fawkes

🎉 Module 18 Complete - Multi-Tenancy Mastery Achieved! 🎉