2021-10 Pluggable Authenticators
Introduce Pluggable Authenticators
- Owners
- @tareqmamari
TL; DR
We propose a pluggable authenticator approach to support plugging in custom authenticators in a self-registering manner.
Why
This proposed approach allows the adopters of Observatorium to use their own custom authenticator’s implementation other than the current OIDC, mTLS or Openshift authenticators.
Goals
- Provide a common interface for the authenticators, so that the adopters can use it to implement their own.
- Provide a self-registering mechanism for authenticators so that the adopters do not need to patch the current codebase to introduce their own authenticators.
- Adopters should be able to configure the tenants such that they can specify which authenticator type to use for each tenant.
- The new changes must be backward-compatible. In other words, the current authentication implementation and configuration must not be broken by this change.
How
Currently, Observatorium API supports only OIDC and mTLS based authentication, however, there are adopters who do not use standard OIDC or mTLS, instead, they use for example JWT-based access tokens with special handling that is done using private Go modules owned by those adopters.
We propose to refactor the current way of initializing the authenticators to introduce a common interface, which means all new authenticators have the same basic functions, which adopters need to implement for their custom authenticators. In addition, in this proposal, we aim to provide a self-registering mechanism, so that introducing any new authenticator does not necessarily require any additional patch/change to the existing codebase, instead, only the plugin’s Go source file is needed other than patching the other source files to add the plugin. For that, we propose to use Go’s importing for side-effects, where a protected map of authenticator types and their factories can be used.
Implementation Options
- Importing for Side-Effects
- Go Plugin Module
- OAuth2 Providers
1. Importing for Side-Effects
In this approach, importing for Go’s side-effects is used to enable each authenticator to register itself through a map of authenticator types and their factories.
To onboard a new authenticator, the following is needed:
- Implement the corresponding interface.
- Implement a factory.
- Register the factory in the authenticators' factories map.
With this approach, an example tenant configuration would look like:
- name: test-oidc
id: 1610b0c3-c509-4592-a256-a1871353dbfa
authenticator:
type: oidc
config:
clientID: test
clientSecret: xyz
issuerCAPath: ./tmp/certs/ca.pem
issuerURL: http://127.0.0.1:5556/dex
redirectURL: https://localhost:8443/oidc/test-oidc/callback
usernameClaim: email
rateLimits:
- endpoint: "/api/metrics/v1/.+/api/v1/receive"
limit: 100
window: 1s
- endpoint: "/api/logs/v1/.*"
limit: 100
window: 1s
2. Go Plugin Module
In this approach, a generic interface for authentication providers (authenticators) is introduced. authentication providers then implement that interface in a Go plugin. This plugin will be built and loaded at run time by the Observatorium API. How and where to load the plugin module is defined by the tenants configuration file.
This approach is easy to implement, very flexible in terms of adding more authenticators without any additional implementation and integration complexity. However, there are few concerns when it comes to trust and security, since the Observatorium API would consume a pre-built plugin binary as an authenticator.
Reference: Go Plugin Package
3. OAuth2 Providers
Similar to the generic OAuth2 providers in grafana, OAuth2 providers are pre-registered in a static list of supported providers alongside the current implementation of OIDC and mTLS. While this approach provides flexibility and can be considered to be an elegant and clean way of introducing more authenticators support, it requires a lot of changes in the Observatorium API.
However, introducing a new authenticator with private or custom implementation would require changing/patching existing Go source files in the Observatorium API. As a result, adopters need to re-apply their patch whenever migrating to a new Observatorium API release with risk of being affected by merge conflicts that must be resolved manually.
Conclusion
We propose to use the first approach (importing for side-effects), as it appears to be the most flexible approach to follow and requires no additional changes to onboard a new authenticator or additional resources to manage.
It worth mentioning that the new changes must be backward-compatible, in other words, they must not break neither the existing configuration nor the current authentication flows.
Migration Plan
The current configuration format will not be broken but will be deprecated, so immediate migration is not necessary. Tenants configured to use the old authenticators, namely OIDC, mTLS, and OpenShift, should eventually be migrated to use the new configuration format.
Current OIDC authentication configuration:
oidc:
clientID: test
clientSecret: ZXhhbXBsZS1hcHAtc2VjcmV0
issuerCAPath: ./tmp/certs/ca.pem
issuerURL: http://127.0.0.1:5556/dex
redirectURL: https://localhost:8443/OIDC/test-OIDC/callback
usernameClaim: email
Proposed new OIDC authenticator configuration:
authenticator:
type: oidc
config:
clientID: test
clientSecret: ZXhhbXBsZS1hcHAtc2VjcmV0
issuerCAPath: ./tmp/certs/ca.pem
issuerURL: http://127.0.0.1:5556/dex
redirectURL: https://localhost:8443/oidc/test-oidc/callback
usernameClaim: email
Current mTLS authentication configuration:
mtls:
caPath: ./tmp/certs/ca.pem
Proposed new mTLS authenticator configuration:
authenticator:
type: mtls
config:
caPath: ./tmp/certs/ca.pem
Action plan
- Review and finalize this proposal document.
- Provide a Proof of Concept (PoC) for both pluggable authenticators.
- The community to review and provide feedback on the PoC Pull Requests.
- Apply any feedback and finalize the PRs to be merged.
- Merge the PRs and release a new Observatorium API release.