authz-keycloak
#
Descriptionauthz-keycloak
is an authorization plugin to be used with the Keycloak Identity Server. Keycloak is an OAuth/OIDC and
UMA compliant Identity Server. Although, it's developed working in conjunction with Keycloak it should work with any
OAuth/OIDC and UMA compliant identity providers as well.
For more information on Keycloak, refer to Keycloak Authorization Docs for more information.
#
AttributesName | Type | Requirement | Default | Valid | Description |
---|---|---|---|---|---|
discovery | string | optional | https://host.domain/auth/realms/foo/.well-known/uma2-configuration | URL to discovery document for Keycloak Authorization Services. | |
token_endpoint | string | optional | https://host.domain/auth/realms/foo/protocol/openid-connect/token | A OAuth2-compliant Token Endpoint that supports the urn:ietf:params:oauth:grant-type:uma-ticket grant type. Overrides value from discovery, if given. | |
resource_registration_endpoint | string | optional | https://host.domain/auth/realms/foo/authz/protection/resource_set | A Keycloak Protection API-compliant resource registration endpoint. Overrides value from discovery, if given. | |
client_id | string | optional | The client identifier of the resource server to which the client is seeking access. One of client_id or audience is required. | ||
audience | string | optional | Legacy parameter now replaced by client_id . Kept for backwards compatibility. One of client_id or audience is required. | ||
client_secret | string | optional | The client secret, if required. | ||
grant_type | string | optional | "urn:ietf:params:oauth:grant-type:uma-ticket" | ["urn:ietf:params:oauth:grant-type:uma-ticket"] | |
policy_enforcement_mode | string | optional | "ENFORCING" | ["ENFORCING", "PERMISSIVE"] | |
permissions | array[string] | optional | Static permission to request, an array of strings each representing a resources and optionally one or more scopes the client is seeking access. | ||
lazy_load_paths | boolean | optional | false | Dynamically resolve the request URI to resource(s) using the resource registration endpoint instead of using the static permission. | |
http_method_as_scope | boolean | optional | false | Map HTTP request type to scope of same name and add to all permissions requested. | |
timeout | integer | optional | 3000 | [1000, ...] | Timeout(ms) for the http connection with the Identity Server. |
access_token_expires_in | integer | optional | 300 | [1, ...] | The expiration time(s) of the access token. |
access_token_expires_leeway | integer | optional | 0 | [0, ...] | Expiration leeway(s) for access_token renewal. If this is set, renewal will happen access_token_expires_leeway seconds before the token expiration. This avoids errors in case the access_token just expires when arriving to the OAuth Resource Server. |
refresh_token_expires_in | integer | optional | 3600 | [1, ...] | The expiration time(s) of the refresh token. |
refresh_token_expires_leeway | integer | optional | 0 | [0, ...] | Expiration leeway(s) for refresh_token renewal. If this is set, renewal will happen refresh_token_expires_leeway seconds before the token expiration. This avoids errors in case the refresh_token just expires when arriving to the OAuth Resource Server. |
ssl_verify | boolean | optional | true | Verify if TLS certificate matches hostname. | |
cache_ttl_seconds | integer | optional | 86400 (equivalent to 24h) | positive integer >= 1 | The maximum period in seconds up to which the plugin caches discovery documents and tokens, used by the plugin to authenticate to Keycloak. |
keepalive | boolean | optional | true | Enable HTTP keep-alive to keep connections open after use. Set to true if you expect a lot of requests to Keycloak. | |
keepalive_timeout | integer | optional | 60000 | positive integer >= 1000 | Idle timeout after which established HTTP connections will be closed. |
keepalive_pool | integer | optional | 5 | positive integer >= 1 | Maximum number of connections in the connection pool. |
access_denied_redirect_uri | string | optional | [1, 2048] | Redirect unauthorized user with the given uri like "http://127.0.0.1/test", instead of returning "error_description":"not_authorized" . |
#
Discovery and EndpointsThe plugin can discover Keycloak API endpoints from a URL in the discovery
attribute that points to
Keycloak's discovery document for Authorization Services for the respective realm. This is the recommended
option and typically most convenient.
If the discovery document is available, the plugin determines the token endpoint URL from it. If present, the
token_endpoint
attribute overrides the URL.
Analogously, the plugin determines the registration endpoint from the discovery document. The
resource_registration_endpoint
overrides, if present.
#
Client ID and SecretThe plugin needs the client_id
attribute to identify itself when interacting with Keycloak.
For backwards compatibility, you can still use the audience
attribute as well instead. The plugin
prefers client_id
over audience
if both are configured.
The plugin always needs the client_id
or audience
to specify the context in which Keycloak
should evaluate permissions.
If lazy_load_paths
is true
then the plugin additionally needs to obtain an access token for
itself from Keycloak. In this case, if the client access to Keycloak is confidential, the plugin
needs the client_secret
attribute as well.
#
Policy Enforcement ModeSpecifies how policies are enforced when processing authorization requests sent to the server.
Enforcing
- (default mode) Requests are denied by default even when there is no policy associated with a given resource.
Permissive
- Requests are allowed even when there is no policy associated with a given resource.
#
PermissionsWhen handling an incoming request, the plugin can determine the permissions to check with Keycloak either statically, or dynamically from properties of the request.
If lazy_load_paths
is false
, the plugin takes the permissions from the permissions
attribute. Each entry
needs to be formatted as expected by the token endpoint's permission
parameter;
see https://www.keycloak.org/docs/latest/authorization_services/index.html#_service_obtaining_permissions.
Note that a valid permission can be a single resource, or a resource paired with one or more scopes.
if lazy_load_paths
is true
, the plugin resolves the request URI to one or more resources, as configured
in Keycloak. It uses the resource registration endpoint to do so. The plugin uses the resolved resources
as the permissions to check.
Note that this requires that the plugin can obtain a separate access token for itself from the token endpoint.
Therefore, in the respective client settings in Keycloak, make sure to set the Service Accounts Enabled
option. Also make sure that the issued access token contains the resource_access
claim with the
uma_protection
role. Otherwise, plugin may be unable to query resources through the Protection API.
#
Automatic Mapping of HTTP Method to ScopeThis option is often used together with lazy_load_paths
, but can also be used with a static permission list.
If the http_method_as_scope
attribute is set to true
, the plugin maps the request's HTTP method to a scope
of the same name. The scope is then added to every permission to check.
If lazy_load_paths
is false
, the plugin adds the mapped scope to any of the static permissions configured
in the permissions
attribute, even if they contain one or more scopes already.
#
How To EnableCreate a route
and enable the authz-keycloak
plugin on the route:
curl http://127.0.0.1:9080/apisix/admin/routes/5 -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d '
{
"uri": "/get",
"plugins": {
"authz-keycloak": {
"token_endpoint": "http://127.0.0.1:8090/auth/realms/{client_id}/protocol/openid-connect/token",
"permissions": ["resource name#scope name"],
"audience": "Client ID"
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"127.0.0.1:8080": 1
}
}
}'
#
Test Plugincurl http://127.0.0.1:9080/get -H 'Authorization: Bearer {JWT Token}'
#
Disable PluginRemove the corresponding json configuration in the plugin configuration to disable the authz-keycloak
.
APISIX plugins are hot-reloaded, therefore no need to restart APISIX.
curl http://127.0.0.1:9080/apisix/admin/routes/5 -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d '
{
"uri": "/get",
"plugins": {
},
"upstream": {
"type": "roundrobin",
"nodes": {
"127.0.0.1:8080": 1
}
}
}'
#
ExamplesCheckout the unit test for of the authz-keycloak.t to understand how the authorization policies can be integrated into your
API workflows. Run the following docker image and visit http://localhost:8090
to view the associated policies for the unit tests.
docker run -e KEYCLOAK_USER=admin -e KEYCLOAK_PASSWORD=123456 -p 8090:8080 sshniro/keycloak-apisix
The following image shows how the policies are configures in the Keycloak server.
#
Future DevelopmentCurrently the
authz-plugin
requires to define the resource name and required scopes in order to enforce policies for the routes. However, Keycloak's official adapters (Java, JS) also provides path matching by querying Keycloak paths dynamically, and lazy loading the paths to identity resources. Future version on authz-plugin will support this functionality.Support to read scope and configurations from the Keycloak JSON File