SiamCafe · Blog
Crossplane Composition RBAC ABAC Policy —
บทความ

Crossplane Composition RBAC ABAC Policy —

เผยแพร่ 28 พฤษภาคม 2569

Crossplane RBAC ABAC

Crossplane Composition RBAC ABAC Policy Infrastructure as Code Kubernetes CRD Claim Multi-tenant OPA Kyverno Access Control Platform API Cloud Resources

Policy EngineLanguageComplexityK8s Nativeเหมาะกับ
OPA GatekeeperRegoสูงAdmissionComplex Policy
KyvernoYAMLต่ำAdmission + MutationSimple Policy
K8s RBACYAMLต่ำBuilt-inWho can do what
CELExpressionปานกลางValidatingAdmissionPolicySimple Validation

Crossplane Composition

=== Crossplane Composition ===

CompositeResourceDefinition (XRD)

apiVersion: apiextensions.crossplane.io/v1

kind: CompositeResourceDefinition

metadata:

name: databases.platform.example.com

spec:

group: platform.example.com

names:

kind: Database

plural: databases

claimNames:

kind: DatabaseClaim

plural: databaseclaims

versions:

  • name: v1alpha1

served: true

reachable: true

schema:

openAPIV3Schema:

type: object

properties:

spec:

type: object

properties:

engine:

type: string

enum: [postgres, mysql]

size:

type: string

enum: [small, medium, large]

environment:

type: string

enum: [dev, staging, prod]

Composition

apiVersion: apiextensions.crossplane.io/v1

kind: Composition

metadata:

name: database-aws

spec:

compositeTypeRef:

apiVersion: platform.example.com/v1alpha1

kind: Database

resources:

  • name: rds-instance

base:

apiVersion: rds.aws.upbound.io/v1beta1

kind: Instance

spec:

forProvider:

engine: postgres

instanceClass: db.t3.medium

allocatedStorage: 20

  • name: security-group

base:

apiVersion: ec2.aws.upbound.io/v1beta1

kind: SecurityGroup

Claim (Developer uses this)

apiVersion: platform.example.com/v1alpha1

kind: DatabaseClaim

metadata:

name: my-app-db

namespace: team-alpha

spec:

engine: postgres

size: medium

environment: dev

from dataclasses import dataclass

@dataclass

class Composition:

name: str

resources: int

providers: str

claims: int

teams: int

compositions = [

Composition("Database", 4, "AWS RDS, SG, Subnet, SSM", 12, 5),

Composition("Kubernetes Cluster", 8, "EKS, VPC, IAM, NodeGroup", 3, 2),

Composition("Storage Bucket", 2, "S3, IAM Policy", 25, 8),

Composition("Redis Cache", 3, "ElastiCache, SG, Subnet", 8, 4),

Composition("VPC Network", 6, "VPC, Subnet, IGW, NAT, RT", 5, 3),

]

print("=== Compositions ===")

for c in compositions:

print(f" [{c.name}] {c.resources} resources")

print(f" Providers: {c.providers}")

print(f" Active Claims: {c.claims} | Teams: {c.teams}")

RBAC ABAC Policy

=== RBAC + ABAC Policy ===

Kubernetes RBAC for Crossplane Claims

apiVersion: rbac.authorization.k8s.io/v1

kind: Role

metadata:

name: database-user

namespace: team-alpha

rules:

  • apiGroups: ["platform.example.com"]

resources: ["databaseclaims"]

verbs: ["get", "list", "create", "update", "delete"]

  • apiGroups: ["platform.example.com"]

resources: ["storagebucketclaims"]

verbs: ["get", "list", "create"]

Kyverno Policy — Enforce Labels and Limits

apiVersion: kyverno.io/v1

kind: ClusterPolicy

metadata:

name: crossplane-claim-policy

spec:

rules:

  • name: require-team-label

match:

resources:

kinds: ["DatabaseClaim", "StorageBucketClaim"]

validate:

message: "Claims must have team and cost-center labels"

pattern:

metadata:

labels:

team: "?*"

cost-center: "?*"

  • name: restrict-prod-size

match:

resources:

kinds: ["DatabaseClaim"]

preconditions:

  • key: "{{request.object.spec.environment}}"

operator: Equals

value: "dev"

validate:

message: "Dev environment only allows small/medium"

pattern:

spec:

size: "small | medium"

@dataclass

class PolicyRule:

name: str

type: str

scope: str

action: str

violations_30d: int

policies = [

PolicyRule("Require Team Label", "Validation", "All Claims", "Block", 5),

PolicyRule("Dev Size Limit", "Validation", "DatabaseClaim (dev)", "Block", 8),

PolicyRule("Prod Approval Required", "Validation", "All Claims (prod)", "Block + Alert", 2),

PolicyRule("Budget Limit per Team", "ABAC", "All Claims", "Block at limit", 3),

PolicyRule("Naming Convention", "Mutation", "All Claims", "Auto-fix", 15),

PolicyRule("Auto-add Tags", "Mutation", "All Resources", "Inject tags", 0),

]

print("\n=== Policy Rules ===")

for p in policies:

print(f" [{p.type}] {p.name}")

print(f" Scope: {p.scope} | Action: {p.action} | Violations: {p.violations_30d}")

Multi-tenant Architecture

# === Multi-tenant Crossplane ===

# Namespace per Team
# kubectl create namespace team-alpha
# kubectl create namespace team-beta
# kubectl create namespace team-gamma

# RoleBinding per Team
# apiVersion: rbac.authorization.k8s.io/v1
# kind: RoleBinding
# metadata:
#   name: team-alpha-db-access
#   namespace: team-alpha
# subjects:
#   - kind: Group
#     name: team-alpha
#     apiGroup: rbac.authorization.k8s.io
# roleRef:
#   kind: Role
#   name: database-user
#   apiGroup: rbac.authorization.k8s.io

# Budget Tracking per Team
# OPA Rego Policy:
# package crossplane.budget
# deny[msg] {
#   input.review.object.kind == "DatabaseClaim"
#   team := input.review.object.metadata.labels.team
#   current_cost := data.budgets[team].current
#   limit := data.budgets[team].limit
#   current_cost > limit
#   msg := sprintf("Team %s exceeded budget: $%d/$%d", [team, current_cost, limit])
# }

@dataclass
class TeamQuota:
    team: str
    namespace: str
    db_limit: int
    db_used: int
    budget: float
    spent: float
    members: int

teams = [
    TeamQuota("Alpha", "team-alpha", 5, 3, 5000, 3200, 8),
    TeamQuota("Beta", "team-beta", 3, 2, 3000, 1800, 5),
    TeamQuota("Gamma", "team-gamma", 10, 7, 10000, 7500, 15),
    TeamQuota("Platform", "team-platform", 20, 12, 20000, 14000, 10),
]

print("Multi-tenant Dashboard:")
for t in teams:
    db_pct = t.db_used / t.db_limit * 100
    budget_pct = t.spent / t.budget * 100
    print(f"  [{t.team}] ns: {t.namespace} | Members: {t.members}")
    print(f"    DB: {t.db_used}/{t.db_limit} ({db_pct:.0f}%) | Budget: / ({budget_pct:.0f}%)")

audit_checklist = [
    "RBAC: แต่ละ Team ใช้ได้เฉพาะ Namespace ตัวเอง",
    "Policy: บังคับ Labels Team Cost-center ทุก Claim",
    "Quota: จำกัด Resource ต่อ Team",
    "Budget: Alert เมื่อใช้ 80% Block เมื่อ 100%",
    "Audit: Log ทุก Create/Update/Delete Resource",
    "Network: แยก VPC/Subnet ต่อ Environment",
    "Encryption: เข้ารหัส Secrets ทุกตัว",
]

print(f"\n\nAudit Checklist:")
for i, c in enumerate(audit_checklist, 1):
    print(f"  {i}. {c}")

เคล็ดลับ

  • Composition: สร้าง Composition ซ่อนความซับซ้อนจาก Dev
  • RBAC: ใช้ K8s RBAC จำกัดสิทธิ์ต่อ Namespace
  • Kyverno: ใช้ Kyverno สำหรับ Policy ง่ายกว่า OPA
  • Labels: บังคับ Labels ทุก Claim สำหรับ Cost Tracking
  • Budget: ตั้ง Budget Limit ต่อ Team ป้องกันบานปลาย

Crossplane Composition คืออะไร

รวม Cloud Resources เป็น API เดียว CRD Claim Developer ไม่ต้องรู้ Cloud RDS SG Subnet SSM Platform API Kubernetes