Skip to content

dpavle/keycloak-openresty-demo

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

36 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Keycloak + OpenResty Demo

keycloak-openresty

Provision infrastructure and deploy application Destroy provisioned infrastructure

This project demonstrates automated provisioning and deployment of a secure web application stack on Azure, featuring Keycloak for authentication and OpenResty (Nginx) as a reverse proxy / web-server. Infrastructure is managed with OpenTofu (Terraform-compatible), configuration is handled by Ansible, and containers are orchestrated via Podman. The example app is a static website built with Hugo.

Infrastructure is automatically provisioned and configured on push via GitHub Actions workflow(s). A manually triggered infrastructure teardown (destroy) workflow is also defined.

Built and tested on Azure Cloud, Ubuntu Server 24.04 image.

Tools used:

  • OpenTofu

    I'm experimenting with OpenTofu as there seems to be a community shift towards it at the moment, although the HCL here would probably also work just fine on Terraform.

  • Ansible

  • Podman

    First time using Podman, I chose it because I liked it's rootless/daemonless capabilities and standardized approach (meaning possibly easier migration to other container orchestrators in the future, e.g k8s). It also integrates well with Ansible.

  • Hugo

    Generating a decent looking site and simulating a bit more complex app build process. I just thought it would be more interesting than echo "<a>Hello World!</a>" > index.html.

  • Keycloak

  • OpenResty

    Based on Nginx, which I have the most experience with. It's Lua-based extension system provides support for the OAuth authorization required by the project. Nginx/OpenResty can sometimes have issues in containerized environments (internal DNS resolution, load balancing between X instances), but for the purposes of this project it's absolutely fine.

OpenTofu/Terraform

Derived from # Quickstart: Use Terraform to create a Linux VM , extended with:

  • ansible provider for generating inventory from state
  • remote state storage on an Azure storage account/container
  • dns zone and A record(s) for the provisioned host on Azure DNS

Ansible

Ansible configuration is split into two playbooks

  • for Keycloak (keycloak.yml) - Sets up Keycloak, its Postgres database, reverse proxy configuration and new realm initialization (with client and user).
  • and App (app.yml) - Builds Hugo-based static site (locally on the Ansible runner), synchronizes the result 'artifact' to the host and configures it's OpenResty web server for access (with Keycloak authentication).

with a main.yml tying them both together, along with some prep pre_steps. A separate task list is defined for OpenResty configuration, called from both keycloak.yml and app.yml allowing each one of them to define their own proxy configuration.

main.yml pre_steps setup the necessary iptables routes to route traffic from port 80/443 to their respective container-exposed counterparts. This is necessary because podman rootless can't bind to privileged ports.

Inventory used is generated by Terraform's ansible provider. The cloud.terraform collection inventory plugin reads host data from Terraform state and generates a workable inventory.

www.redhat.com/en/blog/providing-terraform-with-that-ansible-magic

Web-server/Proxy

  • A server block is defined for app.avalonpark.store where the app is served from. Access is restricted behind Keycloak authorization using the resty.openidc module.
  • Keycloak is reverse proxied behind Nginx/OpenResty at keycloak.avalonpark.store for easy single point SSL termination.

The server names (app/keycloak.avalonpark.store) are configurable. They are passed through from the DNS A records provisioned in dns.tf.

SSL certificates are provided by Let's Encrypt, using the lua-resty-auto-ssl module for auto provisioning and renewal.

Issues encountered:

https://stackoverflow.com/questions/48507224/cant-access-keycloak-rest-api-methods-404
https://stackoverflow.com/questions/70577004/keycloak-could-not-find-resource-for-full-path - see top answer

GitHub Actions

Two GH Actions workflows are defined:

  1. deploy.yml - runs the provisioning steps with OpenTofu and configuration/deployment with Ansible (in two separate, dependent jobs)
  2. teardown.yml - runs tofu destroy which destroys all the provisioned infrastructure.

Secrets/variables for Azure authentication (for provisioning and state storage) are provided via GitHub Actions variables, passed down to OpenTofu as environment variables.

Possible Improvements / TODOs

  1. There's no DNS setup here, instead it's "faked" through /etc/hosts. In a real production setup there should be an actual DNS A record set-up to the host, ideally dynamically provisioned together with the rest of the infrastructure (e.g on Azure's DNS service)

  2. Enable SSL. No SSL certificates are deployed here, in part because of 1. OpenResty has been configured with this in mind though, acting both as a reverse proxy for Keycloak and serving the app, as such it's able to do SSL termination for both. Both existing certificates and Let's Encrypt can be used.

  3. Secret handling. For Keycloak secrets (client secret, admin password, user password), temporary values are used. In prod it would be preferable to store the real values in an encrypted vault (Ansible Vault, Azure KeyVault) and decrypt them at playbook runtime.

  4. Consider using a more container-friendly reverse proxy like Traefik instead.

  5. Investigate why containers are sometimes "randomly" left in a stopped state on subsequent updates/redeployments. Consider running containers differently.

Links

Podman:

https://blog.jdboyd.net/2024/05/exposing-privileged-ports-with-podman/
https://www.geeksforgeeks.org/devops/set-up-a-postgresql-database-with-podman/

OpenResty/Keycloak:

https://kevalnagda.github.io/configure-nginx-and-keycloak-to-enable-sso-for-proxied-applications
https://www.keycloak.org/server/containers
https://medium.com/@cabreltchoffo12/secure-keycloak-in-5-minutes-with-nginx-lets-encrypt-e81a9ac15807
https://www.keycloak.org/server/reverseproxy
https://www.lshnk.me/2025/07/10/keycloak-and-reverse-proxy-a-guide-to-production-setup/

Hugo:

https://www.nodinrogers.com/post/2021-12-05-hugo-in-docker/

About

This project demonstrates automated provisioning and deployment of a secure web application stack on Azure, featuring Keycloak for authentication and OpenResty (Nginx) as a reverse proxy / web-server.

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors