The User info fetcher allows for additional information to be obtained from the configured backend (for example, Keycloak). You can then write Rego rules for OpenPolicyAgent which make an HTTP request to the User info fetcher and make use of the additional information returned for the username or user id.
You can enable the User info fetcher sidecar as follows:
apiVersion: opa.stackable.tech/v1alpha1
kind: OpaCluster
metadata:
name: opa
spec:
image:
productVersion: 0.61.0
clusterConfig:
userInfo: # (1)
backend:
keycloak:
hostname: keycloak.my-namespace.svc.cluster.local
port: 8443
tls:
verification:
server:
caCert:
secretClass: tls # (2)
clientCredentialsSecret: user-info-fetcher-client-credentials # (3)
adminRealm: master # (4)
userRealm: master # (4)
cache: # optional, enabled by default
entryTimeToLive: 60s # optional, defaults to 60s
servers:
roleGroups:
default: {}
---
apiVersion: v1
kind: Secret
metadata:
name: user-info-fetcher-client-credentials
stringData:
clientId: user-info-fetcher # (3)
clientSecret: user-info-fetcher-client-secret # (3)
-
Enable the
user-info-fetcher
sidecar -
Enable TLS verification using the CA from the
tls
secretClass. -
Obtain Keycloak API credentials from the specified secret. The Secret must have
clientId
andclientSecret
entries. -
Refer to the applicable realm in your Keycloak server.
Currently the following backends are supported:
Fetch groups and extra credentials, but not roles.
Note
|
The OAuth2 Client in Keycloak must be given the view-users Service Account Role for the realm that the users are in.
|
Note
|
About unencrypted HTTP
The User info fetcher serves endpoints over clear-text HTTP. It is intended to only be accessed from the OPA Server via localhost and to not be exposed outside of the Pod. |
package test # (1)
# Define a function to lookup by username
userInfoByUsername(username) := http.send({
"method": "POST",
"url": "http://127.0.0.1:9476/user",
"body": {"username": username}, (2)
"headers": {"Content-Type": "application/json"},
"raise_error": true
}).body
# Define a function to lookup by a stable identifier
userInfoById(id) := http.send({
"method": "POST",
"url": "http://127.0.0.1:9476/user",
"body": {"id": id}, (3)
"headers": {"Content-Type": "application/json"},
"raise_error": true
}).body
currentUserInfoByUsername := userInfoByUsername(input.username)
currentUserInfoById := userInfoById(input.id)
-
The package name is important in the OPA URL used by the product.
-
Lookup by username
-
Lookup by id
For more information on the request and response payloads, see [_user_info_fetcher_api]
HTTP Post Requests must be sent to the /user
endpoint with the following header set: Content-Type: application/json
.
You can either lookup the user info by stable identifier:
{
"id": "af07f12c-a2db-40a7-93e0-874537bdf3f5",
}
or by the username:
{
"username": "alice",
}
If the user is found, the following response structure will be returned:
{
"id": "af07f12c-a2db-40a7-93e0-874537bdf3f5",
"username": "alice",
"groups": [
"/superset-admin"
],
"customAttributes": {}
}