Adminutils on Sunbird
Introduction
Adminutils service is used to issues two types of tokens -
Kong consumer tokens
Keycloak access token
The source code of adminutils repo is located here - https://github.com/Sunbird-Lern/sunbird-apimanager-util
For more information about the service, reach out to the Sunbird-Lern community forum.
Kong consumer tokens
These tokens are issued in the mobile device register, desktop device register, portal anonymous and logged in user workflows. For an understanding on how this works, refer to this design doc -
Keycloak access token
These tokens are issued when a user logs in on the mobile or portal. Desktop app login does not follow this workflow as of now and is yet to be implemented. For more details on how this works, refer to this design doc
Deployment Files / Process
The deployment helm chart is present here - https://github.com/project-sunbird/sunbird-devops/tree/master/kubernetes/helm_charts/core/adminutils
The related jenkins jobs are
Build/Core/Adminutils
ArtifcatUpload/Core/Adminutils
Deploy/Kubernetes/Adminutils
Deploy/Kubernetes/KongJWTAdminUtil
Token issue and signing process
The service is injected with private keys. The key generation script can be found here - https://github.com/project-sunbird/sunbird-devops/blob/release-5.1.0/private_repo/ansible/inventory/dev/key-generate.sh
During deployment these keys are injected into the pod as volume mounts. Refer to these ansible roles to understand how its being done -
When an API request arrives, the adminutils services creates the token and issues to the users. Refer to the adminutils source code and the key generation process
In case of kong consumer api, a HS256 kong token is issued which gets created using the respective private keys -
For mobile - a random key is picked with the name mobile_device
For desktop - a random key is picked with the name desktop_device
For portal anonymous sessions - a random key is picked with the name portal_anonymous
For portal logged in sessions - a random key is picked with the name portal_loggedin
In case of Keycloak token, a RS256 token is issues which gets created using the respective private keys -
For keycloak token - a random key is picked with the name access_v1
The private file names, number of keys, portal session variables etc are all controlled using these variables - https://github.com/project-sunbird/sunbird-devops/blob/release-5.1.0/private_repo/ansible/inventory/dev/Core/common.yml#L446-L477
The consumers are controlled using these variables - https://github.com/project-sunbird/sunbird-devops/blob/release-5.1.0/private_repo/ansible/inventory/dev/Core/common.yml#L366-L403
The mobile and portal invoke the refresh token api immediately after a user logs in and get a token issued by the adminutils service
This token would have a kid of the form access_v1_key*
The mobile, desktop and portal invoke the register api when the app is installed and opened for the first time or a browser session is opened. This token will have appropriate kid based on the type of device
portal_anonymous_key* for portal anonymous sessions
portal_loggedin_key* for portal loggedin sessions
desktop_devicev2_key* for desktop register
mobile_devicev2_key* for mobile device register
All the services that require keycloak token verification are injected with the public keys. The public keys correspond to the private keys which have the file names of the form access_v1*
The services will check the kid field in the token and use the appropriate public key file to validate the token.
The public keys are created on the fly using the private key and are injected using this anisble role - https://github.com/project-sunbird/sunbird-devops/tree/master/kubernetes/ansible/roles/mount-keys
Similarly the the kong consumer keys issued by the adminutils (desktop, mobile, portal anonymous and loggedin) are validated on the kong api gateway. The public key for these are created on the fly and onboarded to the kong as consumers.
You can refer to the KongJWTAdminUtil job to understand how the public keys are created and onboarded. The ansible role that does this is located here - https://github.com/project-sunbird/sunbird-devops/tree/master/kubernetes/ansible/roles/kong-jwt-create-adminutil
Adminutils connections
Mobile / Desktop → Nginx → Kong → Adminutils - For the mobile / desktop register API kong consumer token and refresh token API (Desktop doesn’t yet invoke the refresh token endpoint)
Portal → Kong → Adminutils - For portal anonymous and loggedin kong consumer token and refresh token API
Adminutils → Kong → Learner Service - For fetching user roles
Rotating the keys
In order to rotate the keys, you can just run the key generate script to create a new set of keys and then commit to github and inject them to the pod.
The key generate script is located here - https://github.com/project-sunbird/sunbird-devops/blob/release-5.1.0/private_repo/ansible/inventory/dev/key-generate.sh
If old keys are replaced, all the user sessions will be invalidated and users will be logged out
Another way is to generate new set of keys by incrementing the key number. We can still retain the old keys for only verification purpose. We should configure adminutils to issue tokens using only the new set of keys. Eventually, all the tokens will be signed only using the new keys. After this point, the old keys can be removed even from verification flows. But this would be a manual activity and has not been tested. It can be automated if required.