Skip to content

Group Binding Strategies & Semantics

Vì Sao Quantum Trọng

Group-based access control là backbone để scalable RBAC di large organizations:

  • Individual user binding scales poorly — mỗi hire/departure membutuhkan manual binding updates
  • Team-based access lebih natural — "grant engineering-team access to prod" vs. enumerating individual engineers
  • Directory integration (LDAP, OIDC) populates groups từ authoritative source, reducing manual overhead
  • Cross-team collaboration easier với groups — "grant site-reliability-engineers access to X" covers current and future engineers

Nhưng group semantics trong Kubernetes punya subtle implications:

  • System groups vs. custom groups punya different semantics
  • Group membership populated bởi authentication layer, không authorization
  • Understanding group extraction từ tokens crucial để debugging
  • Over-relying vào groups without explicit binding lead đến privilege creep

System Groups

Built-in System Groups

Kubernetes define special system groups automatically injected để every request:

GroupMembersScope
system:authenticatedAll authenticated users & SAsEvery request với valid token/cert
system:unauthenticatedRequests tanpa authenticationRequests tanpa token/cert (rare)
system:serviceaccountsAll SAs cluster-wideKubelet, in-cluster clients
system:serviceaccounts:<namespace>SAs trong namespace cụ thểPod trong namespace đó
system:masters(Not membership; special case)Bootstrap, apiserver self-auth

Example: system:authenticated Group

Mỗi authenticated request automatically trong system:authenticated group:

yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: basic-viewer
rules:
# Accessible để everyone authenticated
- apiGroups: [""]
  resources: ["namespaces"]
  verbs: ["list"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: authenticated-viewers
roleRef:
  kind: ClusterRole
  name: basic-viewer
subjects:
- kind: Group
  name: system:authenticated

Tất cả users và SAs (mà authenticated) có thể list namespaces.

Implementation:

Authenticator processes request, sets request.groups = [... user's groups ..., "system:authenticated"]
Authorization checks: "user trong system:authenticated?" → YES
→ Grant permissions trong binding

system:serviceaccounts Group

Mỗi service account automatically trong hai groups:

system:serviceaccounts                    # cluster-wide SAs group
system:serviceaccounts:<namespace>        # namespace-specific SAs group

Jadi SA prometheus di namespace monitoring:

Username: system:serviceaccount:monitoring:prometheus
Groups:
  - system:serviceaccounts
  - system:serviceaccounts:monitoring
  - system:authenticated

Có thể use để grant permissions đến all SAs hoặc namespace-specific SAs:

yaml
# Grant to ALL SAs in cluster
subjects:
- kind: Group
  name: system:serviceaccounts

# Grant to ALL SAs in monitoring namespace
subjects:
- kind: Group
  name: system:serviceaccounts:monitoring

system:masters Special Case

system:masters không phải normal group. Members automatically bypass all authorization:

yaml
# Subject với system:masters trong groups
subjects:
- kind: Group
  name: system:masters

→ User trong group này skip authorization checks entirely. Dangerous, chỉ để bootstrap.

Custom Groups from Authentication

OIDC Integration

OIDC provider (Google, Auth0, Keycloak) có thể populate groups trong token claims:

json
{
  "sub": "alice@example.com",
  "email": "alice@example.com",
  "groups": ["engineering", "platform-team", "oncall"],
  "org": "acme-corp"
}

OIDC authenticator trong API server:

bash
kube-apiserver \
  --oidc-issuer-url=https://accounts.google.com \
  --oidc-client-id=xxx \
  --oidc-groups-claim=groups

Authenticator extracts groups claim từ token, sets request.groups:

Token claims: groups = ["engineering", "platform-team", "oncall"]
Authenticator sets: request.groups = ["engineering", "platform-team", "oncall", "system:authenticated"]

Authorization có thể match terhadap custom groups:

yaml
subjects:
- kind: Group
  name: engineering
---
# Hoặc
subjects:
- kind: Group
  name: platform-team

LDAP Integration via External Authenticator

LDAP authenticator có thể query LDAP directory để group membership:

User: alice@example.com
LDAP query: what groups does alice belong to?
LDAP response: ["engineering", "sre", "deployment-approvers"]
Authenticator sets: request.groups = ["engineering", "sre", "deployment-approvers", "system:authenticated"]

RBAC binding có thể target LDAP groups:

yaml
subjects:
- kind: Group
  name: deployment-approvers  # From LDAP

Group Extraction & Debugging

How Groups Are Populated

Request Flow:

Authenticator (OIDC, LDAP, x509, etc.)

Extracts groups claim/attribute

Sets request.groups = [user's groups, "system:authenticated", ...]

Authorization checks group membership

Key insight: Groups extracted bởi authenticator, not authorization. Authorization only consumes groups; doesn't generate.

Debugging Missing Groups

Nếu user không punya expected group access:

1. Check token/credentials:

Nếu OIDC:

bash
# Decode token, check groups claim
jq '.groups' <(echo $TOKEN | cut -d. -f2 | base64 -d)

Nếu LDAP:

bash
# Query LDAP directly
ldapsearch -x "uid=alice" memberOf

2. Check authenticator configuration:

bash
# Verify API server OIDC config
kubectl describe pod kube-apiserver-xxx -n kube-system | grep oidc-

# Verify OIDC provider returning groups

3. Check audit log để actual groups:

bash
# Search audit log
grep "alice" /var/log/audit.log | jq '.user.groups'

Audit log cho thấy exactly apa groups diset bởi authenticator.

4. Check RBAC bindings:

bash
# Find all bindings để group
kubectl get rolebindings,clusterrolebindings -A -o wide | grep engineering

# Verify binding's role punya necessary permissions
kubectl get rolebinding engineering-deployers -n production -o yaml

Group Binding Patterns

Pattern 1: Org-Wide Permissions via Group

yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: engineers-read-all
roleRef:
  kind: ClusterRole
  name: view  # read-only access
subjects:
- kind: Group
  name: engineering  # All engineers, from OIDC/LDAP

Mỗi engineer (member từ engineering group trong OIDC) automatically có thể read all resources.

Pattern 2: Team-Specific Access

yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  namespace: platform-team
  name: platform-admins
roleRef:
  kind: ClusterRole
  name: admin
subjects:
- kind: Group
  name: platform-team  # Custom group from LDAP/OIDC

---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  namespace: data-team
  name: data-admins
roleRef:
  kind: ClusterRole
  name: admin
subjects:
- kind: Group
  name: data-team

Teams có thể self-manage own namespace.

Pattern 3: Role-Based Access Control (RBAC + Groups)

yaml
# Deployment approvers (manually curated list trong LDAP)
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: deployment-approver
  namespace: production
rules:
- resources: ["deployments"]
  verbs: ["update", "patch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: deployment-approvers-binding
  namespace: production
roleRef:
  kind: Role
  name: deployment-approver
subjects:
- kind: Group
  name: deployment-approvers  # Curated LDAP group

Only members từ deployment-approvers group có thể approve deployments.

Constraints & Limitations

Limitation 1: Groups Are Strings

Group names arbitrary strings, no validation:

yaml
subjects:
- kind: Group
  name: "typo-in-grpup"  # Misspelled! Won't match anyone

No warning, silently no match. Debugging requires checking audit log.

Limitation 2: Case Sensitivity

Group names case-sensitive:

yaml
- kind: Group
  name: "Engineering"  # Capital E
---
- kind: Group
  name: "engineering"  # Lowercase e

Hai bindings terpisah. Nếu OIDC returns lowercase "engineering" nhưng binding punya "Engineering", no match.

Limitation 3: Group Membership Opaque to Authorization

Authorization layer chỉ checks nếu group trong request.groups list. Không có thể:

  • Query nested group membership ("if alice trong group X and X nested trong Y, grant Y permissions")
  • Dynamic group membership checks ("grant permissions nếu group size > 10")
  • Conditional group checks ("grant nếu alice trong engineering AND trong tier-1")

Tất cả group logic phải di authenticator layer.

Limitation 4: No Negative Constraints

Không có thể say "grant access EXCEPT group X":

yaml
# NOT POSSIBLE
subjects:
- kind: Group
  name: "NOT contractors"

Must use explicit include list hoặc separate RBAC layer.

Multi-Directory Integration

Scenario: Multiple OIDC Providers

Nếu organization punya multiple identity providers (Google workspace, GitHub SAML):

bash
# API server support multiple OIDC issuers via webhook
kube-apiserver \
  --authentication-token-webhook-config=/etc/auth/webhook-config.yaml

Webhook có thể:

  1. Validate token từ multiple issuers
  2. Extract groups từ different claim paths
  3. Map external groups đến internal Kubernetes groups

Example: Bridging External & Internal Groups

yaml
# Webhook logic
if issuer == "google.com":
  groups = token.groups
  add_group("google-employees")
  
if issuer == "github.com":
  groups = token.organizations
  add_group("github-community")

# Result: user trong google.com AND github.com punya:
# request.groups = [
#   "engineering" (từ google),
#   "kubernetes-sigs" (từ github),
#   "google-employees",
#   "github-community",
#   "system:authenticated"
# ]

RBAC có thể target mana saja từ extracted groups.

Group Size & Scalability

Performance: Large Groups

Nếu group punya ribuan members:

Per-request authorization latency ~ O(num_bindings × num_group_members)

Không directly — authorization chỉ checks "is user trong group X", not iterating members.

Nhưng nếu cluster punya nhiều groups (thousands):

Number of bindings × number of groups → slower matching

Mitigation:

  • Keep number of bindings reasonable (< 1000 per cluster)
  • Use hierarchical groups (nested trong LDAP) at identity provider level, not Kubernetes

Storage: Group Names in Audit

Audit log stores every user's groups per request:

json
{
  "user": {
    "username": "alice",
    "groups": ["engineering", "platform-team", "deployment-approvers", "system:authenticated"]
  }
}

10,000 requests/sec × 4 groups = 40K group entries/sec trong audit log. Có thể cause audit log bloat.

Mitigation:

  • Limit group count per user (< 10)
  • Compress audit logs, hoặc use audit backend mà support grouping

Best Practices

Best Practice 1: Minimize Group Count per User

Each group increases:

  • Token size (OIDC claims)
  • Audit log size
  • Authorization decision latency (slightly)

Keep to ~5-10 groups per user.

Best Practice 2: Consistent Naming Convention

✓ engineering
✓ platform-team
✓ data-sre

✗ Engineering (inconsistent case)
✗ eng (ambiguous)
✗ "group-123" (opaque)

Clear naming để easier debugging và audit.

Best Practice 3: Document Group-to-Role Mappings

yaml
# In Kubernetes namespace README hoặc ConfigMap
# RBAC Group Mappings
# - engineering → view (all namespaces), admin (dev/staging)
# - platform-team → admin (platform namespaces)
# - deployment-approvers → approver role (production)

Makes source-of-truth explicit.

Best Practice 4: Regular Group Membership Audits

bash
# Extract all groups từ audit log
grep -o '"groups":\[[^]]*\]' /var/log/audit.log | sort -u

# Check nếu orphaned groups (no matching bindings)

Detect stale group references.

Summary

Groups trong Kubernetes RBAC:

  • System groups automatically included (system:authenticated, system:serviceaccounts:*)
  • Custom groups extracted từ authentication provider (OIDC, LDAP)
  • Group matching opaque string comparison — no hierarchy or nesting
  • Scoping via RoleBinding/ClusterRoleBinding, same as users/SAs

Smart group usage:

  • Use groups để team-based access, not individual binding
  • Extract từ authoritative identity provider
  • Keep group count per user minimal
  • Document mappings clearly

Tham Khảo