When using Kubernetes Admission Controllers ValidatingWebhookConfiguration, I'd like to skip the interception of internal requests such as Kubernetes Controllers.
More specifically, the only requests that I want the validation webhook to match are users' requests via the Kubctl/API, etc.
Is it possible?
According to Webhook request and response your webhook will receive an AdmissionRequest object which contains UserInfo field. In it, there are fields like Username, Groups and others that might be useful for solving your problem.
...
"userInfo": {
# Username of the authenticated user making the request to the API server
"username": "admin",
# UID of the authenticated user making the request to the API server
"uid": "014fbff9a07c",
# Group memberships of the authenticated user making the request to the API server
"groups": ["system:authenticated","my-admin-group"],
# Arbitrary extra info associated with the user making the request to the API server.
# This is populated by the API server authentication layer and should be included
# if any SubjectAccessReview checks are performed by the webhook.
"extra": {
"some-key":["some-value1", "some-value2"]
}
},
...
Related
I have a KC instance where I have some clients with the Authorization option enabled. All works well, but, acting as a client, I need this specific information: Given a certain resource with specific scopes I want the list of users who have accesse to this resource.
I've explored the available APIs multiple times without success. Is there a way to obtain this information or do I necessary need to extends KC capabilities with a dedicated SPI ?
It is possible by Admin rest-API for finding a specific resource's all of user.
This steps
I am using Keycloak v18.0.2 (if use v19/v20, just remove auth in API endpoint)
#1 Get specific client uuid
GET {keycloak_url}/auth/admin/realms/{realm}/clients/{client-uuid}
#2 Get specific resource uuid
GET {keycloak_url}/auth/admin/realms/{realm}/clients/{client-uuid}/authz/resource-server/resource/{resource-uuid}
#3 Get specific permission of #2
GET {keycloak_url}/auth/admin/realms/{realm}/clients/{client-uuid}/authz/resource-server/resource/{resource-uuid}/permissions
#4 Get policy of #3
Get policy and permission list
GET {keycloak_url}/auth/admin/realms/{realm}/clients/{client-uuid}/authz/resource-server/policy
Get policy of specific permission
GET {keycloak_url}/auth/admin/realms/{realm}/clients/{client-uuid}/authz/resource-server/policy/{permission-uuid}/associatedPolicies
#5 Get user list of #4
GET {keycloak_url}/auth/admin/realms/{realm}/clients/{client-uuid}/authz/resource-server/policy/{policy-uuid}
The user list will return in body of response
{
"id": {policy-uuid},
"name": {policy-name},
"config": {
"users": "[array of {user-uuid}]"
}
}
Demo by UI
I will find all of user in resource1 of my-test client.
It assosicated permission1
permissions1 apply policy1
policy's user two users
Demo by API
Same step by APIs
Find client uuid
Find a specific resource uuid
Get specific resource
Get permission and policy list
Get associated policy for permission
Get user list for policy
That user uuid matched user list
So you can find resource1's user are user1 and user3
Unfortunately, you cannot. Keycloak authorization mechanism examines only when it has input. Here your input is User.
To do that, you have to ask for all users. This is not practical bcz there might be thousand of users.
Resource servers (applications or services serving protected resources) usually rely on some kind of information to decide if access should be granted to a protected resource. For RESTful-based resource servers, that information is usually obtained from a security token, usually sent as a bearer token on every request to the server. For web applications that rely on a session to authenticate users, that information is usually stored in a user’s session and retrieved from there for each request
I have Frontend application (spa) and this is calling rest api server.
As I need Authorization enabled, I have to create two client in Keycloak i.e. frontend(public) and backend(confidential).
I am passing an Access token fetched by frontend from Keycloak in Authorization header. Do REST api server need to call Keycloak every time to fetch Authorization info from provided access token. If yes, then it will increase the latency and what should be right approach then?
o REST api server need to call keycloak everytime to fetch
Authorization info from provided access token. If yes, then it will
increase the latency and what should be right approach then?
Yes, whenever one sends the access token to the Keycloak (KC) Server, one "pays" the corresponding performance penalty. That is a common problem when centralizing the authorization in a server. Fortunately, that problem can be solved in KC by configuring it to issue tokens with the user permissions already on it. Thus, the backend can locally inspect those tokens for the user permissions without having to perform additional calls to the KC server. You can read more about it in this link to the KC Authorization Server documentation. An example of such an token taken from that link:
{
"authorization": {
"permissions": [
{
"resource_set_id": "d2fe9843-6462-4bfc-baba-b5787bb6e0e7",
"resource_set_name": "Hello World Resource"
}
]
},
"jti": "d6109a09-78fd-4998-bf89-95730dfd0892-1464906679405",
"exp": 1464906971,
"nbf": 0,
"iat": 1464906671,
"sub": "f1888f4d-5172-4359-be0c-af338505d86c",
"typ": "kc_ett",
"azp": "hello-world-authz-service"
}
Do I need to invoke the server every time I want to introspect an RPT?
No. Just like a regular access token issued by a Keycloak server, RPTs
also use the JSON web token (JWT) specification as the default format.
If you want to validate these tokens without a call to the remote
introspection endpoint, you can decode the RPT and query for its
validity locally. Once you decode the token, you can also use the
permissions within the token to enforce authorization decisions.
Depending on your requirements, you can also try to reduce the number of calls to the KC server by caching the pair <user>/<resource to be accessed> along with the response if the user has or does not have permission to access it. In this manner, you do not need to constantly query the KC server on whether the user is allowed to access a given resource. The downside is that if the user access rights to that resource get updated (e.g., gains or loses a new role) the cache will contain outdated values. Therefore, you should invalidate your cache once in a while. This approach can potentially reduce the number of requests to the server but introduces more complexity on the client side and is more error-prone.
Another approach is for the KC client used for the frontend application to omit a token with all the information needed to allow your backend to determine whether the user has permission to access the resource. Hence, moving the Authorization responsibility from the KC server to your backend. IMO this one is the simplest and more performant solution. One of the downsides is that it tightly couples the authorization-related concerns with the domain concerns of the application. Consequently, changes to the authorization logic might result in changes to the code application.
Does keycloak provide a way to distinguish between logins by the same user on different devices (a user can be logged in on mobile device/s and also on desktop browser/s).
Does keycloak provide a way to identify when a user entered their credentials (whether through keycloak login or using an identity provider flow)?
Our use case is:
a user can request to reset their pin (from our app).
the user is logged out (a /logout using the 'keycloak-connect'
middleware).
following logout, the user is redirected to login and enters
credentials (keycloak or identity provider).
on login, the user is presented with the 'enter a new pin' page (our app).
To achieve this we want to be able to determine server side when to send the 'enter a new pin' page.
Our situation is that we don't easily know (for various reasons, including active keycloak session or other token expire/active states) when an actual 'credentials entered' login occurs.
Could the session_state from the keycloak access token be used to identify which keycloak session a client request corresponds to?
Could something like the following work:
the server receives the keycloak access token (containing the
session_state) from the keycloak login,
the server passes the session_state to the client (browser/mobile
app),
the client passes this session_state back to the server along with
the user requesting the action,
the server requests the session information from keycloak (something along the lines of making the following request to the admin REST API localhost:8080/auth/admin/realms/demo/users/{{user_id}}/sessions - then checking against session_state somehow?)
if the 'start' value of the session returned by the REST API is
recent, then maybe we have 'actual' login information?
We're still using Keycloak 6.0.1
Any help is greatly appreciated.
I wanted to update with how I'm proceeding, which I believe gives me all I want in terms of solving/answering my original question.
The keycloak access token includes: "sub", "auth_time" and "session_state".
{
"sub": "ae384e77-7588-444b-9c4f-3dc920750e1f",
"auth_time": 1590555910,
"session_state": "2d735372-1a5a-43de-8a6c-1a45deebf20b",
}
I can use the sub to query the Keycloak Admin REST API with https://my-domain.com/auth/admin/realms/demo/users/{{sub}}/sessions which gives a list like:
[
{
"id": "2d735372-1a5a-43de-8a6c-1a45deebf20b",
"username": "20000",
"userId": "ae384e77-7588-444b-9c4f-3dc920750e1f",
"ipAddress": "52.62.57.52",
"start": 1590555910000,
"lastAccess": 1590555910000,
"clients": {
"4eb676c2-94c3-4bac-a423-94a7bf57ece0": "demo"
}
}
]
I can then choose from the returned sessions list matching the id to the session_state from the access token (n.b., that start from the sessions list matches auth_time from the access token.
This gives me what I need. I can pass the original session_state to the client and request from keycloak matching that session_state :)
I'll update if I encounter issues.
So I build a RESTful API. It has an /account/{id} endpoint to return user data. The API is secured via an identity server that issues the requester a JSON Web token (JWT) with access to the /account/{id} endpoint. The user sends a request with username and password and receives a JWT in return on successful authentication. Now the user sends a request for their account information to /account/{id}. The request is sent with a token in the header and returns a 200 response with the user data in the payload.
How would one go about authorizing the {id} in the endpoint? In other words, an authenticated user could just add any {id} in the endpoint and potentially receive another user's data. How is this prevented using the JWT?
You can store data in a web token. If you store the ID of the user, then you can identify them for each request they make. This is safe, because the contents of the token are signed with the private key of the server. Therefore their contents cannot be changed.
After that you can either limit the API so that each user can only query their own record, or you can also implement a complex role system, where each user has a set of roles (e.g. read-only, guest, maintainer, admin, client, etc.) that define which endpoints and how they can use.
I am implementing REST API using the following technologies/approaches:
JSONAPI
JWT token
I want to implement authentication endpoint, it should receive username and password in POST request in JSONAPI format and return JWT token in JSONAPI format.
But I see there are some contradictions that does not allow me to be 100% RESTful:
Let's name endpoint /tokens, because it actually creates tokens. Response would be also resource of type tokens, e.g:
{
"data": {
"type": "tokens",
"attributes": {
"value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjEifQ.ivJ5P23wqVo3w31flg3aOu7er--Ijght_RrBf_MuqsU",
}
}
}
But how about request? username and password are properties of user, but they should be sent to /tokens endpoint. If I send users resource to /tokens endpoint it does not make much sense.
Is there a way around for this, to follow JSONAPI and keep API meaningful?
If I send users resource to /tokens endpoint it does not make much sense.
Why not? REST does not impose that you only send users to a user resource. Sure, when you CRUD operations on a user resource you'll do this via the user resource endpoint.
But to generate a token, it's totally reasonable to send a user resource to the token endpoint.
You could also supply the user credentials via an HTTP Authorization header, or as part of the toplevel meta property of the JSON payload.