Skip to content

Commit

Permalink
Enforce configuring an authentication option by default
Browse files Browse the repository at this point in the history
Security should be enabled by default in projects. We hence
enforce that any of the available authentication options are
configured before delivering the metrics as a response.
If none of the authentication options are viable, authentication
can be disabled all together, although that is surely not
recommended.
  • Loading branch information
sirkrypt0 committed Apr 30, 2023
1 parent 63baed6 commit 08898bd
Show file tree
Hide file tree
Showing 3 changed files with 26 additions and 4 deletions.
13 changes: 11 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -108,9 +108,9 @@ The endpoint for the metrics is `<url>/<http_relative_path>/realms/<realm>/metri

### External Access

By default, the metrics endpoint is accessible to **everyone** with access to your Keycloak instance.
By default, the metrics endpoint returns HTTP Forbidden responses until authentication has been configured.

Make sure to enable one of the following settings depending on your setup.
To activate the metrics endpoint, one of the following settings depending on your setup must be enabled.

#### Bearer Authentication

Expand All @@ -132,6 +132,15 @@ Once set, requests in which the header 'X-Forwarded-Host' header is set will be
Thus, to disable access to the metrics the header must be set in a request on your proxy.
This is enabled by default on HA Proxy on Openshift.

#### Disable Authentication

**NOT recommended**.

If you are sure what you do and have considered the other authentication options, you can disable authentication completely.
However, this will make your endpoint accessible to everyone with access to your Keycloak instance, if the metrics route is not otherwise protected.

To disable the authentication, set the `KC_SPI_REALM_RESTAPI_EXTENSION_METRICS_AUTHENTICATION_DISABLED` environment variable (or corresponding command line argument) to `true`.

### Enable metrics-listener event

- To enable the event listener via the GUI interface, go to _Manage -> Events -> Config_. The _Event Listeners_ configuration should have an entry named `metrics-listener`.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,15 @@ public class MetricsEndpoint implements RealmResourceProvider {

private final static Logger logger = Logger.getLogger(MetricsEndpoint.class);

private Boolean authenticationDisabled;
private Boolean bearerEnabled;
private String role;
private AuthResult auth;

public MetricsEndpoint(KeycloakSession session, Boolean bearerEnabled, String realm, String role) {
public MetricsEndpoint(KeycloakSession session, Boolean authenticationDisabled, Boolean bearerEnabled, String realm, String role) {
super();

this.authenticationDisabled = authenticationDisabled;
this.bearerEnabled = bearerEnabled;
if (this.bearerEnabled) {
RealmModel realmModel = session.realms().getRealmByName(realm);
Expand Down Expand Up @@ -82,7 +84,15 @@ private void checkAuthentication(HttpHeaders headers) {
} else if (this.auth.getToken().getRealmAccess() == null || !this.auth.getToken().getRealmAccess().isUserInRole(this.role)) {
throw new ForbiddenException("Missing required realm role");
}
return;
}

if (this.authenticationDisabled) {
return;
}

logger.error("Authentication on metrics endpoint is not configured!");
throw new ForbiddenException();
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,23 +9,26 @@

public class MetricsEndpointFactory implements RealmResourceProviderFactory {

private static final String DISABLE_AUTHENTICATION = "disableAuthentication";
private static final String BEARER_ENABLED_CONFIGURATION = "bearerEnabled";
private static final String REALM_CONFIGURATION = "realm";
private static final String DEFAULT_REALM = "master";
private static final String ROLE_CONFIGURATION = "role";
private static final String DEFAULT_ROLE = "prometheus-metrics";

private Boolean authenticationDisabled;
private Boolean bearerEnabled;
private String realm;
private String role;

@Override
public RealmResourceProvider create(KeycloakSession session) {
return new MetricsEndpoint(session, this.bearerEnabled, this.realm, this.role);
return new MetricsEndpoint(session, this.authenticationDisabled, this.bearerEnabled, this.realm, this.role);
}

@Override
public void init(Config.Scope config) {
this.authenticationDisabled = config.getBoolean(DISABLE_AUTHENTICATION, false);
this.bearerEnabled = config.getBoolean(BEARER_ENABLED_CONFIGURATION, false);
this.realm = config.get(REALM_CONFIGURATION, DEFAULT_REALM);
this.role = config.get(ROLE_CONFIGURATION, DEFAULT_ROLE);
Expand Down

0 comments on commit 08898bd

Please sign in to comment.