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:
- ✅ Design multi-tenant platform architectures
- ✅ Implement robust RBAC systems
- ✅ Create security boundaries and isolation
- ✅ Manage namespace strategies at scale
- ✅ Implement policy enforcement with OPA
- ✅ Design quota and resource management
- ✅ 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
-
What's the lightest multi-tenancy model?
-
[x] Namespace-per-team
- [ ] vCluster
- [ ] Cluster-per-team
-
[ ] Virtual machines
-
What does RBAC stand for?
-
[ ] Resource-Based Access Control
- [x] Role-Based Access Control
- [ ] Rule-Based Access Control
-
[ ] Rights-Based Access Control
-
Which is cluster-scoped?
-
[ ] Role
- [x] ClusterRole
- [ ] RoleBinding
-
[ ] ResourceQuota
-
What does OPA stand for?
-
[ ] Optimal Policy Agent
- [x] Open Policy Agent
- [ ] Orchestrated Policy Administration
-
[ ] Operational Policy Automation
-
What enforces resource limits per namespace?
-
[ ] NetworkPolicy
- [ ] PodSecurityPolicy
- [x] ResourceQuota
-
[ ] RBAC
-
Default network policy should be:
-
[x] Deny all, whitelist specific traffic
- [ ] Allow all, blacklist bad traffic
- [ ] No policy needed
-
[ ] Allow within cluster only
-
What does vCluster provide?
-
[ ] Virtual machines
- [ ] Virtual networks
- [x] Virtual Kubernetes control planes
-
[ ] Virtual storage
-
Priority Classes are used for:
- [ ] Security levels
- [ ] Network priority
- [x] Pod scheduling priority during resource contention
- [ ] 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
- Choose tenancy model wisely - Balance isolation, cost, complexity
- RBAC is foundational - Get permissions right from day one
- Automate tenant lifecycle - Manual provisioning doesn't scale
- Deny by default - Whitelist only necessary access
- Policy as code - OPA enables declarative governance
- Monitor quota usage - Prevent resource exhaustion
- 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
- vCluster - Virtual Kubernetes clusters
- OPA Gatekeeper
- Hierarchical Namespaces
- Kyverno - Alternative to OPA
- Capsule - Multi-tenancy operator
Documentation
Books & Articles
- Kubernetes Security - Liz Rice & Michael Hausenblas
- Multi-Tenancy in Kubernetes
🏅 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! 🎉