provider-keycloak

A native Crossplane provider for Keycloak that manages Keycloak resources using the Keycloak Admin REST API directly.
Container Registry
- Primary:
ghcr.io/rossigee/provider-keycloak:latest
Overview
Provider-keycloak offers complete Keycloak Admin API coverage (100%) with 21 managed resource types, enabling infrastructure-as-code management of authentication, authorization, and user management across Keycloak instances.
Why provider-keycloak?
- ✅ 100% API Coverage: All Keycloak Admin REST API resources
- ✅ Native Go Implementation: Direct HTTP client, no upjet/angryjet scaffolding
- ✅ Production Ready: Security hardened, comprehensive error handling
- ✅ Well Tested: 80%+ test coverage with integration test patterns
- ✅ Fully Documented: Complete API reference and examples
Managed Resource Types (21 Controllers)
Core Infrastructure
| Kind |
Description |
Realm |
Keycloak realm configuration |
ProviderConfig |
Connection and credentials |
Client Management
| Kind |
Description |
Client |
OpenID Connect clients |
ProtocolMapper |
Client protocol mappers |
ClientCertificates |
Client mutual TLS certificates |
ClientInitialAccess |
Client registration tokens |
ClientDefaultScopes |
Default OAuth2 scopes |
ClientOptionalScopes |
Optional OAuth2 scopes |
User & Group Management
| Kind |
Description |
User |
Keycloak users |
Group |
Keycloak user groups |
Authorization & Access Control
| Kind |
Description |
Role |
Realm and client roles |
ClientRoleMapping |
User client role assignments |
ClientScopeMapping |
Client scope assignments |
AuthorizationResource |
UMA resource definitions |
AuthorizationPolicy |
Fine-grained access policies |
Identity & Authentication
| Kind |
Description |
IdentityProvider |
SAML/OIDC identity providers |
AuthenticationFlow |
Login and registration flows |
Infrastructure & Administration
| Kind |
Description |
UserFederationProvider |
LDAP/Kerberos user federation |
Component |
Realm components and providers |
RealmEventsConfig |
Event logging and auditing |
RealmImport |
Realm configuration import |
RealmKeys |
Realm cryptographic keys (read-only) |
ProviderConfig
The ProviderConfig references a Kubernetes Secret containing a JSON credentials blob:
apiVersion: keycloak.crossplane.io/v1beta1
kind: ProviderConfig
metadata:
name: keycloak-rossgolderltd
spec:
credentials:
source: Secret
secretRef:
name: keycloak-admin-credentials
namespace: crossplane-system
key: credentials
The secret value at key must be a JSON object:
{
"url": "https://keycloak.example.com",
"base_path": "/auth",
"realm": "master",
"client_id": "crossplane",
"client_secret": "your-client-secret",
"root_ca_certificate": ""
}
The provider authenticates via OAuth2 client credentials grant (grant_type=client_credentials). base_path defaults to /auth; realm defaults to master.
Example Resources
OpenID Connect Client
apiVersion: openidclient.keycloak.crossplane.io/v1alpha1
kind: Client
metadata:
name: my-app
namespace: crossplane-keycloak
spec:
forProvider:
realmId: my-realm
clientId: my-app
accessType: CONFIDENTIAL
name: "My Application"
standardFlowEnabled: true
directAccessGrantsEnabled: false
serviceAccountsEnabled: false
validRedirectUris:
- "https://my-app.example.com/*"
webOrigins:
- "+"
clientSecretSecretRef:
name: my-app-client-secret
namespace: crossplane-keycloak
key: client-secret
providerConfigRef:
name: keycloak-rossgolderltd
deletionPolicy: Delete
Realm
apiVersion: realm.keycloak.crossplane.io/v1alpha1
kind: Realm
metadata:
name: my-realm
namespace: crossplane-keycloak
spec:
forProvider:
realm: my-realm
displayName: "My Realm"
enabled: true
loginWithEmailAllowed: true
sslRequired: external
providerConfigRef:
name: keycloak-rossgolderltd
User
apiVersion: user.keycloak.crossplane.io/v1alpha1
kind: User
metadata:
name: my-realm-alice
namespace: crossplane-keycloak
spec:
forProvider:
realmId: my-realm
username: alice
email: alice@example.com
emailVerified: true
enabled: true
firstName: Alice
lastName: Example
providerConfigRef:
name: keycloak-rossgolderltd
Authentication
The provider authenticates to Keycloak using OAuth2 client credentials. The client_id in the credentials secret must have the realm-management client role (or equivalent admin permissions) in the target realm.
Cross-references
All realmId, clientId, userId, parentId, etc. fields support both direct values and Crossplane cross-references:
# Direct value
realmId: my-realm
# Reference to a Realm CR (uses the Keycloak internal ID from status)
realmIdRef:
name: my-realm-cr
Documentation
Development
# Build
make build
# Lint
make lint
# Run tests
make test
# Test coverage
go test ./... -cover
go test ./... -coverprofile=coverage.out
go tool cover -html=coverage.out
# Generate CRDs
cd apis && go generate ./...
Code Organization
internal/clients/: Keycloak HTTP client library
internal/controller/: Managed resource controllers (21 total)
apis/: CRD type definitions
package/crds/: Generated CRD manifests
Important Notes
The zz_generated.deepcopy.go and zz_generated.managed.go files are maintained by hand — do not regenerate them with controller-gen object:... or angryjet. They must implement the specific crossplane resource interfaces.
Architecture Highlights
Security
- Data race protection: Mutex-protected token refresh
- Bounded memory: Limited response sizes (64KB tokens, 16MB responses)
- Certificate validation: Proper TLS configuration and error handling
- Input validation: URL scheme, auth method, and parameter validation
Reliability
- Health checks: ProviderConfig validates credentials every 5 minutes
- Proper error handling: All error paths logged and surfaced to status
- Graceful degradation: Continues working when partial features unavailable
Maintainability
- No code generation complexity: Hand-written client and controllers
- Minimal dependencies: Only essentials (crossplane-runtime, Kubernetes)
- Clear patterns: Each controller follows identical structure for consistency
API Coverage
| Category |
Resources |
Coverage |
| Core Infrastructure |
2 |
100% |
| Client Management |
6 |
100% |
| User & Group |
2 |
100% |
| Authorization |
5 |
100% |
| Identity & Auth |
2 |
100% |
| Administration |
4 |
100% |
| Total |
21 |
100% |
Feature Parity
Provider-keycloak maintains feature parity with crossplane-contrib/provider-keycloak while adding:
- ✅ Full authorization policy management
- ✅ Complete authentication flow control
- ✅ Identity provider federation (SAML/OIDC)
- ✅ Comprehensive test coverage
- ✅ Production security hardening
Quick Start
-
Install provider:
helm repo add provider-keycloak https://charts.example.com
helm install provider-keycloak provider-keycloak/provider-keycloak
-
Create ProviderConfig:
kubectl apply -f config/samples/provider-config.yaml
-
Create realm and client:
kubectl apply -f config/samples/
-
Verify deployment:
kubectl get realms
kubectl get clients
Troubleshooting
Provider won't connect
- Check ProviderConfig status:
kubectl describe providerconfig keycloak
- Verify secret exists:
kubectl get secret keycloak-admin-credentials
- Test Keycloak connectivity:
curl -u admin:password https://keycloak/admin/realms
Resource stuck in pending
- Check controller logs:
kubectl logs -n crossplane-system deployment/provider-keycloak-controller
- Review resource status:
kubectl describe realm my-realm
- Verify Keycloak API accessibility
Drift detected but not updating
- Check resource parameters match Keycloak state
- Ensure ProviderConfig has appropriate admin permissions
- Review Keycloak audit logs for conflicts
Contributing
We welcome contributions! Areas for enhancement:
- Additional resource types (custom attribute mappers, etc.)
- Performance optimizations
- Enhanced observability and metrics
- Additional test coverage
Please see CONTRIBUTING.md for contribution guidelines.
Support
License
provider-keycloak is under the Apache 2.0 license.