Security Azure

Gravitee Access Management on Ubuntu 24.04 on Azure User Guide

| Product: Gravitee Access Management on Ubuntu 24.04 LTS on Azure

Overview

Gravitee Access Management (AM) is an open source Identity & Access Management server: an OAuth 2.0 authorization server and OpenID Connect provider with single sign-on, multi-factor and passwordless authentication, a web management console and a REST API. You define security domains, register applications (OAuth2/OIDC clients), manage users and identity providers, and issue and introspect access and ID tokens through a dedicated security-token gateway. The cloudimg image runs the official open source Docker images (management API, security-token gateway and management console), pinned to Gravitee AM 4.12.4, on a PostgreSQL backend and fronted by TLS.

This appliance ships the open source edition only - no Enterprise-Edition plugins and no licence key are used or required. It deliberately uses the fully-supported PostgreSQL (JDBC/R2DBC) backend rather than the MongoDB default. Every secret - the admin password, the database password and the token-signing secrets - is generated uniquely on the first boot of each VM, and the stock admin/adminadmin default is never shipped.

What is included:

  • The official Gravitee AM 4.12.4 open source stack under Docker: management-api (console API), gateway (OAuth2/OIDC token endpoints), management-ui (console) and PostgreSQL 16, pinned so it never silently upgrades
  • A PostgreSQL backend (JDBC/R2DBC) - the MongoDB default is not used; no MongoDB, Redis or Elasticsearch is present
  • An nginx TLS terminator: the management console + API on https://<vm>/ (port 443) and the OAuth2/OIDC gateway on https://<vm>:8443/ - port 80 redirects to 443
  • A per-VM admin console account generated on first boot - a unique password recorded in a root-only file - so every VM is secured independently; admin/adminadmin does not work
  • Docker's data-root and the Compose project relocated onto a dedicated 40 GiB Azure data disk at /var/lib/gravitee-am, so the PostgreSQL volume and certificates survive OS changes and can be resized independently
  • The stack managed as one gravitee-am.service systemd unit, plus docker.service, both enabled
  • PostgreSQL bound to the internal Docker network only - just 22/tcp (SSH), 443/tcp (console) and 8443/tcp (gateway) are exposed (80/tcp redirects to 443)
  • 24/7 cloudimg support

Prerequisites

An active Azure subscription, an SSH key pair, and a VNet + subnet in the target region. Standard_B2ms (2 vCPU / 8 GiB RAM) is the recommended starting size - the two JVM services plus PostgreSQL fit comfortably; choose Standard_B4ms for heavier production use. NSG inbound: allow 22/tcp from your management network, and 443/tcp + 8443/tcp from your users. The image serves a self-signed TLS certificate generated per VM; for production, install your own certificate or front the VM with your own domain and certificate.

Step 1 - Deploy from the Azure Marketplace

Sign in to the Azure Portal, choose Create a resource, search the Marketplace for Gravitee Access Management by cloudimg, and select Create. On Basics pick your subscription, resource group, region and size; under Administrator account choose SSH public key and paste your key; under Inbound port rules allow SSH (22), HTTPS (443) and custom 8443. Review the dedicated data disk on the Disks tab, then Review + create then Create.

Step 2 - Deploy from the Azure CLI

az vm create \
  --resource-group <your-rg> \
  --name gravitee-am \
  --image <marketplace-image-urn> \
  --size Standard_B2ms \
  --admin-username azureuser \
  --ssh-key-values ~/.ssh/id_ed25519.pub \
  --vnet-name <your-vnet> --subnet <your-subnet> \
  --public-ip-sku Standard

az vm open-port --resource-group <your-rg> --name gravitee-am --port 443 --priority 1010
az vm open-port --resource-group <your-rg> --name gravitee-am --port 8443 --priority 1020

Step 3 - Connect to your VM

ssh azureuser@<vm-public-ip>

Step 4 - Confirm the stack is running

The Gravitee AM containers run under Docker as a Compose stack managed by a single systemd unit. On first boot the stack rotates every secret, recreates itself on a fresh PostgreSQL database and seeds a per-VM admin console account; the multi-container stack can take a couple of minutes to become fully healthy after the VM is created.

systemctl is-active gravitee-am.service docker.service

Both report active. List the running containers with:

sudo docker compose -f /var/lib/gravitee-am/docker-compose.yml ps

Gravitee AM open source stack running under Docker - management-api, gateway, management-ui, nginx and PostgreSQL

Step 5 - Retrieve your per-VM admin credentials

First boot writes a unique console admin password to a root-only file. Retrieve it:

sudo cat /root/gravitee-am-credentials.txt

Per-VM credentials written by first boot - console URL, gateway URL and the rotated admin password

Step 6 - Confirm the console is reachable over TLS

The management console is served over HTTPS on port 443 (the certificate is self-signed per VM, so -k is used here):

curl -sk -o /dev/null -w 'console: HTTP %{http_code}\n' https://localhost/

It returns HTTP 200.

Step 7 - Confirm the stock default credential is rejected

This image never ships the Gravitee admin/adminadmin default. Prove that only your per-VM password authenticates against the management API - the placeholder below is substituted with the real per-VM password from the credentials file:

echo -n 'per-VM admin password accepted: '
curl -sk -o /dev/null -w 'HTTP %{http_code}\n' -X POST -u 'admin:<GRAVITEE_ADMIN_PASSWORD>' https://localhost/management/auth/token
echo -n 'stock admin/adminadmin default: '
curl -sk -o /dev/null -w 'HTTP %{http_code}\n' -X POST -u 'admin:adminadmin' https://localhost/management/auth/token

The per-VM password returns HTTP 200; admin/adminadmin returns HTTP 401.

The stock admin/adminadmin default is rejected - only the per-VM password authenticates

Step 8 - Issue and validate a real OAuth2 token

This end-to-end example authenticates to the management API, creates a security domain and a client_credentials application, waits for the gateway to publish the domain, then requests and validates a real access token. It is self-contained:

ADMIN_PASS='<GRAVITEE_ADMIN_PASSWORD>'
MGMT=https://localhost/management
GW=https://localhost:8443
TOKEN=$(curl -sk -X POST -u "admin:${ADMIN_PASS}" "$MGMT/auth/token" | jq -r .access_token)
if [ -z "$TOKEN" ] || [ "$TOKEN" = "null" ]; then
  echo "Sign in first with your per-VM admin password (Step 5), then re-run this step."
  exit 0
fi
OE="$MGMT/organizations/DEFAULT/environments/DEFAULT"
DID=$(curl -sk -X POST -H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
      -d '{"name":"quickstart","description":"quickstart demo","dataPlaneId":"default"}' "$OE/domains" | jq -r .id)
curl -sk -X PATCH -H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
      -d '{"enabled":true}' "$OE/domains/$DID" -o /dev/null
DPATH=$(curl -sk -H "Authorization: Bearer $TOKEN" "$OE/domains/$DID" | jq -r .path)
APP=$(curl -sk -X POST -H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
      -d '{"name":"quickstart-service","type":"SERVICE"}' "$OE/domains/$DID/applications")
CID=$(echo "$APP" | jq -r .settings.oauth.clientId)
CSEC=$(echo "$APP" | jq -r .settings.oauth.clientSecret)
for i in $(seq 1 40); do
  [ "$(curl -sk -o /dev/null -w '%{http_code}' "${GW}${DPATH}/oidc/.well-known/openid-configuration")" = "200" ] && break
  sleep 3
done
curl -sk -X POST -u "${CID}:${CSEC}" -d grant_type=client_credentials "${GW}${DPATH}/oauth/token" \
  | jq '{token_type, expires_in, access_token: (.access_token[0:40] + "...")}'

The gateway returns a signed JWT access token with token_type: bearer. The screenshot below shows the same flow returning a token and the introspection endpoint confirming it is active.

Issuing an OAuth2 client_credentials token from the gateway and validating it via introspection

Step 9 - Sign in to the management console

Browse to https://<vm-public-ip>/ (accept the self-signed certificate warning, or install your own certificate). Sign in as admin with the password from Step 5.

The Gravitee Access Management console sign-in page, served over TLS

The console opens on your security domain's dashboard, showing users and registered applications at a glance.

A security domain dashboard in the Gravitee AM console - users and registered applications

Open Applications to see your registered OAuth2/OIDC clients, create new ones, and manage their grant types, scopes, redirect URIs and client credentials.

Registered OAuth2/OIDC applications in a Gravitee AM security domain

Step 10 - Confirm data lives on the dedicated disk

The PostgreSQL database, the Compose project and the per-VM TLS certificate all live on a dedicated 40 GiB Azure data disk mounted at /var/lib/gravitee-am:

df -h /var/lib/gravitee-am

Creating your first application

In the console, create a security domain (Settings then General), then under Applications click Create application and pick the type that matches your client: Web for a server-side app using the authorization-code flow, Single-Page App for a browser app with PKCE, Native for mobile, or Service for machine-to-machine (client_credentials). Configure its redirect URIs, grant types and scopes, then use the OpenID Connect discovery document at https://<vm>:8443/<domain-path>/oidc/.well-known/openid-configuration to wire up your application.

Maintenance

  • Logs: sudo docker compose -f /var/lib/gravitee-am/docker-compose.yml logs -f management-api gateway
  • Restart: sudo systemctl restart gravitee-am.service
  • OS updates: unattended-upgrades is enabled for security patches; reboot to apply kernel updates.
  • Backups: snapshot the /var/lib/gravitee-am data disk, or pg_dump the graviteeam database from the PostgreSQL container.

Support

This image is maintained by cloudimg with 24/7 support. For help, contact cloudimg support via the Azure Marketplace listing.