Namespace isolation¶
The three principal customer namespaces at Golem Trust are royal-bank, patricians-office, and merchants-guild. Adora Belle negotiated the contracts; Ludmilla built the technical isolation. The Royal Bank’s requirements are the strictest: their namespace must be provably isolated from all other customer namespaces at the network, resource, and RBAC layers simultaneously. The Patrician’s Office requires similar guarantees, and has additionally requested that their namespace not appear in any shared audit log visible to other customers. This runbook covers how each namespace is created, labelled, quota-bounded, and isolated, and how customer service accounts are scoped.
Namespace creation and labelling¶
Create the namespace with the labels that Calico, Gatekeeper, and Istio policies use for targeting:
apiVersion: v1
kind: Namespace
metadata:
name: royal-bank
labels:
golemtrust.am/customer: royal-bank
golemtrust.am/tier: enterprise
pod-security.kubernetes.io/enforce: restricted
pod-security.kubernetes.io/enforce-version: v1.29
istio-injection: enabled
Apply the same pattern for patricians-office and merchants-guild, substituting the appropriate customer label value.
ResourceQuota¶
Each namespace has a ResourceQuota that prevents a single customer from consuming excessive cluster resources. The values below are for the royal-bank namespace; adjust for other customers according to their contract:
apiVersion: v1
kind: ResourceQuota
metadata:
name: royal-bank-quota
namespace: royal-bank
spec:
hard:
requests.cpu: "40"
requests.memory: 80Gi
limits.cpu: "80"
limits.memory: 160Gi
persistentvolumeclaims: "50"
services.loadbalancers: "5"
pods: "200"
Mr. Bent reviews the quota figures at each quarterly audit. If a customer reports pods being rejected due to quota, check the quota status before assuming there is a scheduling problem:
kubectl describe resourcequota royal-bank-quota -n royal-bank
LimitRange for default resource limits¶
Even with Gatekeeper enforcing that resource limits are set, a LimitRange provides sensible defaults for any case where a developer forgets (Gatekeeper will catch the deployment, but the LimitRange acts as a backstop during the remediation window):
apiVersion: v1
kind: LimitRange
metadata:
name: royal-bank-limits
namespace: royal-bank
spec:
limits:
- type: Container
default:
cpu: "500m"
memory: 512Mi
defaultRequest:
cpu: "100m"
memory: 128Mi
max:
cpu: "4"
memory: 8Gi
min:
cpu: "50m"
memory: 64Mi
NetworkPolicy for namespace isolation¶
Apply the default-deny policy first (see the calico-deployment runbook), then add explicit allow rules only for traffic that is required. The following example permits the royal-bank namespace to reach the shared platform namespace for log shipping and metrics scraping only:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-egress-to-platform
namespace: royal-bank
spec:
podSelector: {}
policyTypes:
- Egress
egress:
- to:
- namespaceSelector:
matchLabels:
golemtrust.am/customer: platform
ports:
- protocol: TCP
port: 5044
- protocol: TCP
port: 9091
Traffic between royal-bank and patricians-office is denied by default and there is no allow rule for it. This is intentional. If a developer requests such a policy, escalate to Adora Belle before creating it.
RBAC: customer-scoped service accounts¶
Each customer namespace gets its own service account with permissions scoped to that namespace. No cluster-wide roles are granted:
apiVersion: v1
kind: ServiceAccount
metadata:
name: royal-bank-deployer
namespace: royal-bank
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: royal-bank-deployer-role
namespace: royal-bank
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", "delete"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: royal-bank-deployer-binding
namespace: royal-bank
subjects:
- kind: ServiceAccount
name: royal-bank-deployer
namespace: royal-bank
roleRef:
kind: Role
name: royal-bank-deployer-role
apiGroup: rbac.authorization.k8s.io
Customer CI/CD pipelines use this service account token. They cannot read resources from other namespaces, cannot create cluster-scoped resources, and cannot modify RBAC itself.
Verifying isolation¶
Carrot’s post-provisioning checklist:
# Confirm quota is in place
kubectl get resourcequota -n royal-bank
# Confirm default-deny NetworkPolicy exists
kubectl get networkpolicy default-deny-all -n royal-bank
# Confirm pod security standard is enforced
kubectl get namespace royal-bank -o jsonpath='{.metadata.labels}' | jq .
# Attempt cross-namespace service account access (should be denied)
kubectl auth can-i get pods -n patricians-office \
--as system:serviceaccount:royal-bank:royal-bank-deployer
The last command must return no. If it returns yes, there is an unintended ClusterRole or ClusterRoleBinding that needs to be removed immediately and logged as a security incident.