Skip to content

Latest commit

 

History

History
203 lines (159 loc) · 8.12 KB

File metadata and controls

203 lines (159 loc) · 8.12 KB

AGENTS.md

OpenShift operator that manages OAuth Server and OAuth API Server for cluster authentication.

What This Operator Does

This operator manages the authentication infrastructure for OpenShift clusters:

  • OAuth Server (openshift-authentication namespace) - Handles user authentication via identity providers (HTPasswd, LDAP, OIDC, Request Header, etc.)
  • OAuth API Server (openshift-oauth-apiserver namespace) - Manages OAuth API resources and client registrations
  • Controllers - Each controller watches specific cluster resources and reconciles authentication state
  • Token Encryption - Manages encryption of OAuth tokens at rest with key rotation support
  • Identity Provider Configuration - Syncs IdP configs from openshift-config to the OAuth server

The operator runs in openshift-authentication-operator namespace and orchestrates both OAuth components.

External OIDC Mode: Recent development focuses on external OIDC support. When external OIDC is enabled (via Authentication.config.openshift.io/cluster spec), the operator disables the default OAuth stack and configures the cluster to use an external OIDC provider instead. See pkg/controllers/externaloidc/ for implementation. Future feature development should be focused on external OIDC support, and the existing OAuth stack is considered feature complete.

The following feature gates control External OIDC behavior and conditionally enable controllers/resources:

  • ExternalOIDC — enables External OIDC mode itself
  • ExternalOIDCWithUIDAndExtraClaimMappings — enables additional claim mappings (UID, extra claims) for OIDC providers
  • ExternalOIDCWithUpstreamParity — enables upstream-parity features for OIDC authentication
  • ExternalOIDCExternalClaimsSourcing — when enabled, preserves the oauth-apiserver under OIDC (instead of deleting it) and enables external claims sourcing

Commands

# Build and verify
make build
make verify
make verify-bindata

# Testing
make test-unit                          # Fast unit tests
make test-e2e                           # E2E tests (1h)
make run-e2e-test WHAT=TestCustomRoute  # Specific test

# NEVER run encryption tests in parallel
make test-e2e-encryption                # Serial only, 4h timeout

# Update embedded assets
make update-bindata                     # After modifying bindata/ YAML files
make verify-bindata                     # Verify bindata is current

# Dependencies
go get <module>@<version>
go mod tidy && go mod vendor
make verify

# If carrying patches on vendored code
make update-deps-overrides

Tech Stack

  • Go - See go.mod for version
  • OpenShift library-go - Controller factory, resourceapply, operatorhelpers
  • OpenShift api - Authentication/OAuth CRDs
  • klog/v2 - Structured logging

Always Do

  • Use informers and listers - Never make direct API calls in controller sync loops
  • Run make update-bindata after updating vendored CRDs that are copied into bindata/ (e.g. the RoleBindingRestriction CRD). Editing YAML files directly in bindata/ does not require this step — they are embedded via //go:embed
  • Use resourceapply helpers - ApplyDeployment(), ApplyService(), etc. from library-go
  • Propagate context.Context - When a function accepts or has access to a context.Context, pass it through to downstream calls that accept one. Never discard a context or substitute context.Background()/context.TODO() when a context is already available
  • Return errors from sync() to trigger automatic retry
  • Use table-driven tests for unit tests
  • Log with klog - Use structured logging with klog.V() levels
  • Reference files with line numbers - Format: pkg/controllers/deployment/controller.go:123

Ask First

  • Adding new controllers - Must register in pkg/operator/starter.go and add RBAC to manifests
  • Changing RBAC permissions - Update manifests/ files
  • Modifying encryption logic - Impacts security and requires encryption test validation
  • Changing operator namespaces - Multiple namespaces involved (see below)
  • Adding new CRD dependencies - Check vendoring and bindata requirements

Never Do

  • Never commit secrets or credentials to the repo
  • Never modify vendor/ directly without updating deps.diff - Use go get, go mod tidy, and go mod vendor. If carrying patches on vendored code, run make update-deps-overrides
  • Never skip encryption tests - They're serial and slow (4h) but critical
  • Never make direct API calls in controllers - Always use informers/listers for performance
  • Never modify bindata/ CRDs sourced from vendor without running make update-bindata
  • Never run encryption tests in parallel - They must run serially (-p 1 -parallel 1)
  • Never use generic "helpful assistant" code - Follow OpenShift operator patterns

Controller Pattern

All controllers follow the library-go factory pattern:

import (
    "github.com/openshift/library-go/pkg/controller/factory"
    "github.com/openshift/library-go/pkg/operator/v1helpers"
)

func NewMyController(
    operatorClient v1helpers.OperatorClient,
    kubeInformers informers.SharedInformerFactory,
    recorder events.Recorder,
) factory.Controller {
    c := &myController{
        operatorClient: operatorClient,
        lister:        kubeInformers.Apps().V1().Deployments().Lister(),
    }

    return factory.New().
        WithInformers(kubeInformers.Apps().V1().Deployments().Informer()).
        WithSync(c.sync).
        ToController("MyController", recorder)
}

func (c *myController) sync(ctx context.Context, syncCtx factory.SyncContext) error {
    // Use listers, never direct API calls
    deployment, err := c.lister.Deployments("namespace").Get("name")
    if err != nil {
        return err // Return error to trigger retry
    }

    // Use resourceapply for declarative updates
    _, _, err = resourceapply.ApplyDeployment(
        ctx,
        c.client,
        recorder,
        requiredDeployment,
        expectedGeneration,
    )
    return err
}

Key File Locations

pkg/operator/starter.go              # Register new controllers here
pkg/controllers/<name>/              # Controller implementations
pkg/operator/configobservation/      # Config observers
pkg/operator/workload/               # OAuth API Server workload
bindata/oauth-openshift/             # OAuth server manifests (14 YAML files)
bindata/oauth-apiserver/             # OAuth API server manifests (10 YAML files)
manifests/                           # Operator RBAC and deployment
test/e2e/                           # E2E tests
test/library/                       # Shared test utilities

Namespaces

  • openshift-authentication-operator - This operator runs here
  • openshift-authentication - OAuth server runs here
  • openshift-oauth-apiserver - OAuth API server runs here
  • openshift-config - User-provided configuration (secrets/configmaps for IdPs, TLS certs, CA bundles, etc.)
  • openshift-config-managed - Operator-managed configuration

Common Workflows

Add a Controller

  1. Create pkg/controllers/<name>/<name>_controller.go
  2. Implement factory pattern with sync() method
  3. Register in pkg/operator/starter.go
  4. Add RBAC to manifests/ if needed
  5. Add unit tests in *_test.go

Modify Embedded Manifests

YAML files under bindata/ are embedded via //go:embed — edit them directly, no generation step needed. The only exception is CRDs copied from vendor/ (e.g. the RoleBindingRestriction CRD):

# After updating vendored CRDs
make update-bindata
make verify-bindata

Add a Test

// Unit test - co-located with source
func TestMyController_Sync(t *testing.T) {
    tests := []struct {
        name    string
        setup   func(*fakeClient)
        wantErr bool
    }{
        // Table-driven test cases
    }
    for _, tt := range tests {
        t.Run(tt.name, func(t *testing.T) {
            // Test implementation
        })
    }
}

Security Notes

  • This operator manages cluster authentication - security is critical
  • OAuth tokens encrypted at rest with key rotation support
  • Never log secrets or credentials
  • Validate all external IdP configurations