Skip to content

feat: AuthorizationRule CRD to customize auth.conf #511

Description

@slauger

Motivation

Custom auth.conf rules can currently only be managed inline via Config.Spec.PuppetServer.AuthorizationRules[] (api/v1alpha1/config_types.go:121). This works well for single-team setups but has limits:

  • All rules live on one Config object → merge conflicts under GitOps when multiple teams/modules contribute rules.
  • No RBAC separation: managing auth.conf rules requires edit rights on the entire Config.
  • No independent reuse/lifecycle per rule set.

The operator already has an established pattern for "discrete policy fragments aggregated into a rendered file": NodeClassifier, ReportProcessor, SigningPolicy. A standalone AuthorizationRule CRD fits right in.

Proposal

A new, additive AuthorizationRule CRD modeled on ReportProcessor — the existing inline field stays as-is.

type AuthorizationRuleSpec struct {
    ConfigRef         string `json:"configRef"`   // back-reference, analogous to ReportProcessor.Spec.ConfigRef
    AuthorizationRule `json:",inline"`            // existing struct: Name, MatchRequest, Allow, AllowUnauthenticated, Deny, SortOrder
}

Implementation sketch

  • Binding: back-reference via Spec.ConfigRef (consistent with ReportProcessor/SigningPolicy).
  • Discovery/watch: findAuthorizationRules(configRef) analogous to internal/controller/config_reports.go:23; enqueue via enqueueConfigsForAuthorizationRule analogous to config_reports.go:254.
  • Rendering: inline rules plus the CRD objects found by configRef go into one combined list, sorted globally by SortOrder, rendered in renderAuthConf() (config_rendering.go:248) between builtinAuthRules() and the final deny \"*\" rule. Both sources share the existing AuthorizationRule struct (no type duplication).
  • Rollout: no new mount/secret needed — auth.conf already lives in the Config ConfigMap, whose hash annotation rolls the Server pods. The extra watch source only triggers a re-render.

Invariants

  • Built-in rules and the trailing deny \"*\" stay untouchable — CRD rules are only inserted between them.
  • allowUnauthenticated gets no special handling for now and is left fully to RBAC — consistent with today's inline behavior. Protection is enforced via RBAC on the authorizationrules resource.

Open questions

  • Surface SortOrder collisions (same order + path) in the CRD Status, but don't hard-reject them.
  • Decide whether SortOrder == 0 still means "unset → 500" (config_rendering.go:273) or whether a pointer field should distinguish "intentionally 0" from "unset".

Scope

  • AuthorizationRule CRD type (+ deepcopy, CRD manifest, RBAC)
  • Aggregate inline and CRD rules in renderAuthConf()
  • Watch/enqueue AuthorizationRule → Config
  • E2E test (create rule via CRD → auth.conf contains rule → Server pod rolls)
  • Docs

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions