OpenShift operator that manages OAuth Server and OAuth API Server for cluster authentication.
This operator manages the authentication infrastructure for OpenShift clusters:
- OAuth Server (
openshift-authenticationnamespace) - Handles user authentication via identity providers (HTPasswd, LDAP, OIDC, Request Header, etc.) - OAuth API Server (
openshift-oauth-apiservernamespace) - 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-configto 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.
# 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
make verify- Go - Check
go.modfor current version - Kubernetes client-go - Check
go.modfor current version - OpenShift library-go - Controller factory, resourceapply, operatorhelpers
- OpenShift api - Authentication/OAuth CRDs
- klog/v2 - Structured logging
- Cobra - CLI framework
- Use informers and listers - Never make direct API calls in controller sync loops
- Run
make update-bindataafter modifying any YAML inbindata/oauth-openshift/orbindata/oauth-apiserver/ - Use
resourceapplyhelpers -ApplyDeployment(),ApplyService(), etc. from library-go - 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
- Adding new controllers - Must register in
pkg/operator/starter.goand 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 commit secrets or credentials to the repo
- Never modify
vendor/directly - Usego getandgo mod tidy - 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/ 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
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,
)
return err
}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
openshift-authentication-operator- This operator runs hereopenshift-authentication- OAuth server runs hereopenshift-oauth-apiserver- OAuth API server runs hereopenshift-config- User-provided configuration (secrets/configmaps for IdPs, TLS certs, CA bundles, etc.)openshift-config-managed- Operator-managed configuration
- Create
pkg/controllers/<name>/<name>_controller.go - Implement factory pattern with
sync()method - Register in
pkg/operator/starter.go - Add RBAC to
manifests/if needed - Add unit tests in
*_test.go
# Edit YAML
vim bindata/oauth-openshift/deployment.yaml
# Update embedded Go code
make update-bindata
# Verify
make verify-bindata// 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
})
}
}- 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