How Can We Secure a Microservice?
In a traditional web application, a server side web tier is used to authenticate the user. An HTTP session is then created containing the authentication and user details. The security context is propagated between the tiers within the application server so there’s no need to re-authenticate the user. With microservices, the server side web tier is replaced by html and javascript on the client side. Since it’s stateless, there is no HTTP session and no single layer to deal with authentication. This is where Keycloak comes to the rescue.
What is Keycloak?
Keycloak is an SSO solution for web apps, mobile and RESTful web services. It is an authentication server where users can centrally login, logout, register, and manage their user accounts. The Keycloak admin UI can manage roles and role mappings for any application secured by Keycloak. The Keycloak Server can also be used to perform social logins via the user’s favorite social media site i.e. Google, Facebook, Twitter etc.
Using the Keycloak adapter, an unauthenticated user is redirected to the login screen on the Keycloak server. The user then supplies credentials for authentications to the Keycloak server. Since the authentication is done by the Keycloak server and not your application, it’s easy to add support for multi-factor authentication or social logins without having to change anything in your application.
Once the user is authenticated, Keycloak returns a token to the application. The token contains details about the user as well as permissions the user has. A token is basically just a signed JSON document and can be verified by the called services or by invoking the Keycloak server.
Installing the Servers
Follow the steps from the post Using Vagrant and Ansible To Build A Keycloak/Wildfly Development Server to setup both Keycloak and Wildfly servers.
What is Ansible doing?
After downloading and installing wildfly , keycloak-wildfly-adapter-distis then downloaded and unzipped adding additional keycloak modules needed to communicate with the authentication server.
At that point a command line script is executed adding the keycloak subsystem to the Wildfly standalone.xml configuration file
1234567891011121314 embed-serverif (outcome != success) of /extension=org.keycloak.keycloak-adapter-subsystem:read-resource/extension=org.keycloak.keycloak-adapter-subsystem:add()end-ifif (outcome != success) of /subsystem=keycloak:read-resource/subsystem=keycloak:addend-ifif (outcome != success) of /subsystem=security/security-domain=keycloak:read-resource/subsystem=security/security-domain=keycloak/:add()/subsystem=security/security-domain=keycloak/authentication=classic:add(login-modules=[{"code"=>"org.keycloak.adapters.jboss.KeycloakLoginModule","flag"=>"required"}])end-ifstop-embedded-server
Checking out the Serenity REST Services
The services being deployed consist of:
- Services
- JaxRsActivator – This is used to bootstrap the application. It uses the
@ApplicationPath
annotation to set the application context path - CargoServices – Service endpoint that allows us to find, update and add cargo
- JobServices – Service endpoint that finds existing jobs
- LocationServices – Service endpoint that finds existing accessible locations
- JaxRsActivator – This is used to bootstrap the application. It uses the
- EJB
- CargoAccess – Stateless session bean used to demonstrate programmatic authentication and authorization
Securing the Services
The services can be secured by updating the web.xml as follows:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" version="3.0"> <module-name>serenity</module-name> <security-constraint> <web-resource-collection> <url-pattern>/*</url-pattern> </web-resource-collection> <auth-constraint> <role-name>captain</role-name> <role-name>crew</role-name> <role-name>passengers</role-name> </auth-constraint> </security-constraint> <login-config> <auth-method>KEYCLOAK</auth-method> <realm-name>serenity</realm-name> </login-config> <security-role> <role-name>captain</role-name> </security-role> <security-role> <role-name>crew</role-name> </security-role> <security-role> <role-name>passengers</role-name> </security-role> </web-app> |
The CargoAccess stateless session bean demonstrates how to programmatically use the keycloak system.
- The Jboss specific @SecurityDomain annotation is used to set Keycloak as the security domain
- The @PermitAll and @RolesAllowed annotations are used to supply access to the operations
Configure the keycloak.json adapter config file. This file specifies the configuration used to communicate with the Keycloak server. Our sample looks like:
1 2 3 4 5 6 7 8 9 |
{ "realm": "serenity", "realm-public-key": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB", "bearer-only": true, "auth-server-url": "https://172.16.0.100/auth", "ssl-required": "none", "resource": "serenity-service", "enable-cors" : true } |
- realm : The Keycloak realm representing the serenity application and users
- resource : Name of the application client to connect to when attempting authentication
- bearer-only : Tells the adapter to only accept bearer tokens through the Authorization header
Further documentation can found at Keycloak adapter config
Building The Services
The following should have already been done:
1 2 |
$ git clone git@github.com:SUMGlobal/keycloak_demo.git $ cd keycloak_demo |
Gradle is used to create the deployment artifact
1 2 3 |
$ cd serenity $ gradle clean build $ cp build/libs/serenity.war ../vm-keycloak/shared |
This will build the war file and copy it out to the vm’s shared directory. Then:
1 2 3 4 5 |
$ cd ../vm-keycloak $ vagrant ssh $ sudo -u wildfly cp /shared/serenity.war /opt/jboss/wildfly/standalone/deployments/ $ sudo service keycloak restart $ sudo service wildfly restart |
That’s it. The services are now deployed at:
In the next post, we will review the cortex Angularjs application where we use the deployed services.
Social Media