pub const BINDY_ROLE_YAML: &str = "# Copyright (c) 2025 Erick Bourgeois, firestoned\n# SPDX-License-Identifier: MIT\n---\napiVersion: rbac.authorization.k8s.io/v1\nkind: ClusterRole\nmetadata:\n name: bindy-role\n labels:\n app.kubernetes.io/name: bindy\n app.kubernetes.io/component: rbac\n annotations:\n # Trivy suppressions - see inline justifications at affected rules\n trivy.aquasecurity.com/ignore: KSV-0041,KSV-0056\nrules:\n # Bind9Instance resources\n - apiGroups: [\"bindy.firestoned.io\"]\n resources: [\"bind9instances\"]\n verbs: [\"get\", \"list\", \"watch\", \"create\", \"update\", \"patch\", \"delete\"]\n # Permissions needed:\n # - \"get\", \"list\", \"watch\": Read instances for status updates\n # - \"create\": Create instances for Bind9Cluster scaling\n # - \"update\", \"patch\": Update instance configuration\n # - \"delete\": Scale down instances (Bind9Cluster reconciler) and finalizer cleanup\n\n # Bind9Instance status subresource (separate permissions for least privilege)\n - apiGroups: [\"bindy.firestoned.io\"]\n resources: [\"bind9instances/status\"]\n verbs: [\"get\", \"update\", \"patch\"]\n # Status updates only need get/update/patch, not create/delete\n\n # Bind9Cluster resources\n - apiGroups: [\"bindy.firestoned.io\"]\n resources: [\"bind9clusters\"]\n verbs: [\"get\", \"list\", \"watch\", \"create\", \"update\", \"patch\", \"delete\"]\n # Permissions needed:\n # - \"get\", \"list\", \"watch\": Read clusters for status updates\n # - \"create\": Create clusters for ClusterBind9Provider\n # - \"update\", \"patch\": Update cluster configuration\n # - \"delete\": Clean up clusters (ClusterBind9Provider finalizer cleanup)\n\n # Bind9Cluster status subresource (separate permissions for least privilege)\n - apiGroups: [\"bindy.firestoned.io\"]\n resources: [\"bind9clusters/status\"]\n verbs: [\"get\", \"update\", \"patch\"]\n # Status updates only need get/update/patch, not create/delete\n\n # ClusterBind9Provider resources - cluster-scoped, NO DELETE (least privilege)\n - apiGroups: [\"bindy.firestoned.io\"]\n resources: [\"clusterbind9providers\"]\n verbs: [\"get\", \"list\", \"watch\", \"create\", \"update\", \"patch\"]\n # Removed: \"delete\" - Use bindy-admin-role for deletions\n\n # ClusterBind9Provider status subresource (separate permissions for least privilege)\n - apiGroups: [\"bindy.firestoned.io\"]\n resources: [\"clusterbind9providers/status\"]\n verbs: [\"get\", \"update\", \"patch\"]\n # Status updates only need get/update/patch, not create/delete\n\n # DNSZone resources - NO DELETE (least privilege)\n - apiGroups: [\"bindy.firestoned.io\"]\n resources: [\"dnszones\"]\n verbs: [\"get\", \"list\", \"watch\", \"create\", \"update\", \"patch\"]\n # Removed: \"delete\" - Use bindy-admin-role for deletions\n\n # DNSZone status subresource (separate permissions for least privilege)\n - apiGroups: [\"bindy.firestoned.io\"]\n resources: [\"dnszones/status\"]\n verbs: [\"get\", \"update\", \"patch\"]\n # Status updates only need get/update/patch, not create/delete\n\n # Record resources - NO DELETE (least privilege)\n - apiGroups: [\"bindy.firestoned.io\"]\n resources:\n - \"arecords\"\n - \"aaaarecords\"\n - \"txtrecords\"\n - \"cnamerecords\"\n - \"mxrecords\"\n - \"nsrecords\"\n - \"srvrecords\"\n - \"caarecords\"\n verbs: [\"get\", \"list\", \"watch\", \"create\", \"update\", \"patch\"]\n # Removed: \"delete\" - Use bindy-admin-role for deletions\n\n # Record status subresources (separate permissions for least privilege)\n - apiGroups: [\"bindy.firestoned.io\"]\n resources:\n - \"arecords/status\"\n - \"aaaarecords/status\"\n - \"txtrecords/status\"\n - \"cnamerecords/status\"\n - \"mxrecords/status\"\n - \"nsrecords/status\"\n - \"srvrecords/status\"\n - \"caarecords/status\"\n verbs: [\"get\", \"update\", \"patch\"]\n # Status updates only need get/update/patch, not create/delete\n\n # Kubernetes Deployments\n - apiGroups: [\"apps\"]\n resources: [\"deployments\"]\n verbs: [\"get\", \"list\", \"watch\", \"create\", \"update\", \"patch\", \"delete\"]\n # Permissions needed:\n # - \"get\", \"list\", \"watch\": Read deployment status\n # - \"create\": Create deployments for Bind9Instance\n # - \"update\", \"patch\": Update deployment configuration\n # - \"delete\": Finalizer cleanup (Bind9Instance reconciler)\n # Note: Owner references provide automatic GC, but finalizer explicitly deletes\n\n # Kubernetes Services\n # trivy:ignore:KSV-0056\n # Suppression Justification (KSV-0056 - Services/Endpoints Access):\n # REQUIRED FOR CORE FUNCTIONALITY - DNS operator MUST manage Services to expose BIND9 servers.\n # Mitigation Strategy:\n # 1. Namespace-scoped via RoleBinding - cannot intercept traffic in other namespaces\n # 2. Owner references - Services are bound to Bind9Instance resources (automatic cleanup)\n # 3. Finalizers - Explicit deletion only when parent Bind9Instance is deleted\n # 4. Service selectors - Only route traffic to pods owned by this operator\n # 5. NetworkPolicy enforcement - Traffic interception prevented by cluster NetworkPolicies\n # Risk Acceptance: Service management is fundamental to DNS server operation. Network policies\n # and namespace isolation provide defense-in-depth against traffic interception.\n # Compliance: NIST SP 800-190 (container orchestration security), CIS Kubernetes Benchmark 5.1.5\n - apiGroups: [\"\"]\n resources: [\"services\"]\n verbs: [\"get\", \"list\", \"watch\", \"create\", \"update\", \"patch\", \"delete\"]\n # Permissions needed:\n # - \"get\", \"list\", \"watch\": Read service status and endpoints\n # - \"create\": Create services for Bind9Instance\n # - \"update\", \"patch\": Update service configuration (preserves clusterIP)\n # - \"delete\": Finalizer cleanup (Bind9Instance reconciler)\n # Note: Owner references provide automatic GC, but finalizer explicitly deletes\n\n # Kubernetes ConfigMaps\n - apiGroups: [\"\"]\n resources: [\"configmaps\"]\n verbs: [\"get\", \"list\", \"watch\", \"create\", \"update\", \"patch\", \"delete\"]\n # Permissions needed:\n # - \"get\", \"list\", \"watch\": Read configuration data\n # - \"create\": Create ConfigMaps for Bind9Instance configuration\n # - \"update\", \"patch\": Update BIND9 configuration (zone changes)\n # - \"delete\": Finalizer cleanup (Bind9Instance reconciler)\n # Note: Owner references provide automatic GC, but finalizer explicitly deletes\n\n # Kubernetes Secrets - RNDC key management (CRITICAL: least privilege for sensitive data)\n # trivy:ignore:KSV-0041\n # Suppression Justification (KSV-0041 - Secrets Access):\n # REQUIRED FOR CORE FUNCTIONALITY - DNS operator MUST read RNDC secrets across the\n # namespaces it watches for BIND9 authentication.\n # B-5 hardening (2026-06-09): cluster-wide access is now READ-ONLY. The mutating verbs\n # (create/update/patch/delete) have been moved out of this ClusterRole into the\n # namespaced Role `bindy-secrets-writer` (see secrets-role.yaml), bound only in the\n # operator namespace. This removes cluster-wide Secret WRITE \u{2014} a compromised operator\n # can no longer create, modify, or delete Secrets in other namespaces (e.g. kube-system).\n # For multi-namespace deployments, replicate the `bindy-secrets-writer` Role/RoleBinding\n # into each target namespace.\n # Mitigation Strategy:\n # 1. Read-only cluster-wide; write verbs namespaced to the operator namespace only\n # 2. Purpose-specific secrets - only manages secrets with the \"-rndc-key\" suffix\n # 3. Audit logging enabled - all secret operations logged for compliance (PCI-DSS 10.2)\n # 4. RBAC separation - admin role required for cluster-wide destructive secret access\n # Risk Acceptance: Cluster-wide Secret READ is required by the controller\'s owned-Secret\n # watch (`.owns(Api::<Secret>::all)`), which RBAC cannot filter by name/label.\n # Compliance: PCI-DSS 7.1.2 (minimal permissions), NIST SP 800-190 (container secrets management)\n - apiGroups: [\"\"]\n resources: [\"secrets\"]\n verbs: [\"get\", \"list\", \"watch\"]\n # Cluster-wide, READ-ONLY:\n # - \"get\": Load RNDC keys for zone updates (DNSZone reconciler)\n # - \"list\": Check if RNDC secrets exist (Bind9Cluster reconciler)\n # - \"watch\": Monitor RNDC secret changes (Bind9Instance .owns(Secret) watch)\n # Mutating verbs (create/update/patch/delete) live in the namespaced\n # bindy-secrets-writer Role (secrets-role.yaml) \u{2014} operator namespace only.\n\n # Kubernetes ServiceAccounts\n - apiGroups: [\"\"]\n resources: [\"serviceaccounts\"]\n verbs: [\"get\", \"list\", \"watch\", \"create\", \"update\", \"patch\", \"delete\"]\n # Permissions needed:\n # - \"get\", \"list\", \"watch\": Read service account status\n # - \"create\": Create service accounts for Bind9Instance pods\n # - \"update\", \"patch\": Update service account configuration\n # - \"delete\": Finalizer cleanup (Bind9Instance reconciler)\n # Note: Owner references provide automatic GC, but finalizer explicitly deletes\n\n # Kubernetes Pods - READ-ONLY (for discovery and status)\n - apiGroups: [\"\"]\n resources: [\"pods\"]\n verbs: [\"get\", \"list\", \"watch\"]\n\n # Kubernetes Endpoints - READ-ONLY (for service discovery)\n - apiGroups: [\"\"]\n resources: [\"endpoints\"]\n verbs: [\"get\", \"list\", \"watch\"]\n\n # Events for logging (no delete needed)\n - apiGroups: [\"\"]\n resources: [\"events\"]\n verbs: [\"create\", \"patch\"]\n\n # Leases for leader election (no delete needed for HA)\n - apiGroups: [\"coordination.k8s.io\"]\n resources: [\"leases\"]\n verbs: [\"get\", \"create\", \"update\", \"patch\"]\n";Expand description
Embedded RBAC YAML files — compiled into the binary so bootstrap is self-contained.