Every new application starts with an idea. Whether creating a new site, the next big social media platform or just trying to make a process workflow easier, the idea is the driving force where teams want to spend most of their time perfecting the user experience. However, once a project moves out of the proof of concept phase, there is a lot of development that needs to be done which only indirectly helps make an idea a reality. There is a laundry list of needs a web application has that are important for getting an application to production. This list could include user management, HTTPS, deployment strategy and project organization. A development team can spend a lot of time working on these features, which takes away time that could be spent working on the core application functionality. Teams at UDig have been looking for ways to minimize this initial project infrastructure workload. Utilizing some awesome microservices we have managed to create a tech stack that allows developers to spend less time configuring and more time developing.
The base of this stack utilizes Docker to containerize the application. Creating images for different parts of the application allows the infrastructure to be standardized making it easier to manage. The “it runs fine on my machine” risks are minimized when moving from development to production environments. When each part of the application runs in its own container, different parts of the application will not have compatibility issues as they would running on the same machine. Developers can start to think of the different parts of the application as their own units with their own concerns. When architecture becomes pluggable, developers can handoff work to trusted third party dependencies.
Most web applications manage users. A development team could fill multiple sprints with all the work needed to create a custom solution building out this feature. There are roles, admin views, authentication schemes, UI screens and more. It is important to have confidence in a sensitive feature like user security. RedHat’s Keycloak Identity Management System offloads this work and provides an advanced user management system out of the box. This system supports all major authentication schemes like SSO, Social Logins, 2 Factor and OAuth 2.0. For single system setups, Keycloak provides different settings for regulating user fields such as enforcing user password requirements. Part of what makes Keycloak so functional out of the box is most of the user UI screens are provided such as the login, user details and admin views. The development team can customize these screens and rebrand them so they match the look and feel of the rest of the application. On the client side, Keycloak provides libraries for different frameworks like React to perform the authorization flow. You can configure the endpoints and then allow the client to complete the work.
When it comes to assigning roles to users, there are a few ways to create and assign them to users. A role is a defined permission. Roles can be a composite of other defined roles. These can be assigned directly to users. Additionally, there is a concept of groups. A group is a bucket of users with assigned roles. A “Student” group would have different roles then a “Teacher” group. Groups can also be organized hieratically, so that groups inherit roles from its parent group.
While Keycloak runs independently from the application, it provides a Rest API to allow the application to look up and update users. There is also a need to keep track of the configuration of the whole system. It is possible to export the complete configuration so it can be tracked in version control and reconstituted. In Docker, you can use the script below to extract the roles, users and auth config into a json file:
docker exec -it irc-api_keycloak_1 opt/jboss/keycloak/bin/standalone.sh \ -Djboss.socket.binding.port-offset=100 \ -Dkeycloak.migration.action=export \ -Dkeycloak.migration.provider=singleFile \ -Dkeycloak.migration.realmName=<name-of-realm-here> \ -Dkeycloak.migration.usersExportStrategy=REALM_FILE \ -Dkeycloak.migration.file=/tmp/lms-export/KeycloakConfig.json
This is great for keeping the application consistent on developers’ computers. This JSON file can be imported by the Keycloak container on startup. The production config (without user secrets) can be version controlled to prevent any catastrophic issues, and in the development environment, configurations with test users can be used for testing.
With user security taken care of, there is still concern for the website’s security. What parts of the application are public facing, and how is communication secured? Traefik is an edge router that handles these problems with minimal configuration. With Traefik there are settings for the application like entry points and HTTPS, but once that is complete, it will inspect the project’s infrastructure and map out the rest of the configuration for you. While UDig has used this with Docker, Traefik has support for many providers such as Kubernetes, Redis and Marathon. For Docker, labels are added to a container, which are discovered by Traefik which handles the rest.
labels: - "traefik.http.routers.api.rule=Host(`api.localhost`)" - "traefik.http.routers.api.entrypoints=web"
Traefik config can specify middleware, load balancers, and rules for more fine-tuned traffic scenarios. A common need for a web application is certificates for HTTPS traffic. Traefik provides settings to use certificates a team already has assigned. If the team does not already have certificates, Traefik can use an ACME provider like Let’s Encrypt to generate certificates automatically. A bonus of this approach is Traefik will automatically renew the certificates before they expire so there is less risk of them lapsing.
Developers should be confident in their application infrastructure. It is important to have a solid base so the team can focus on business goals. The approach highlighted here lets a team use tried–and–true techniques for successful application development which saves valuable time. While we have had good results with this approach, utilizing containers also allows an application to be flexible and swap out services if needs change in the future. Development can utilize existing software to solve common application problems and focus on what matters for a project’s success.