Security Azure

FreeIPA Identity Management on AlmaLinux 9 on Azure User Guide

| Product: FreeIPA Identity Management on AlmaLinux 9 on Azure

Overview

FreeIPA is an open source identity management suite for Linux environments. It combines four things that are usually run separately into one managed domain: an LDAP directory (389 Directory Server) holding users, groups, hosts and services; a Kerberos KDC (MIT Kerberos) issuing tickets for single sign-on; a certificate authority (Dogtag) that issues and renews certificates for every host and service in the domain; and a web interface and CLI for administering all of it, with host-based access control, sudo rules and two-factor authentication.

The cloudimg image delivers FreeIPA 4.13.1 on AlmaLinux 9, with your entire identity domain built on the first boot of your own VM. Backed by 24/7 cloudimg support.

Nothing is baked into this image, and that is the point. ipa-server-install writes the realm, the server hostname and a freshly generated certificate authority into installed state. If any of that shipped inside a shared marketplace image, every buyer would receive the same CA signing key — enough to mint certificates that every other customer's domain would trust — along with the same Kerberos master key and the same realm. So the image contains staged packages only: no directory instance, no CA, no Kerberos principals and no realm. All of it is created on your VM, once, at first boot.

What is included:

  • FreeIPA 4.13.1 (ipa-server) from the AlmaLinux 9 AppStream repository, with 389 Directory Server 2.8.0, MIT Kerberos 1.21.1 and Dogtag PKI 11.7.1
  • A complete IdM domain provisioned at first boot: LDAP directory, Kerberos KDC, a certificate authority generated for your VM alone, and the FreeIPA web interface on port 443
  • No default login: the IdM admin password and the Directory Manager password are generated on your VM at first boot and written to a root-only file. They exist nowhere else, and they are never passed on a command line or written to the system journal
  • A certificate authority whose private key is unique to your VM
  • firewalld configured to the exact port set this appliance needs, with Dogtag's internal ports and the Kerberos administration port closed
  • SELinux enforcing, with no permissive mode and no custom policy module
  • Unattended security updates via dnf-automatic, proven at build time to actually install a pending update

FreeIPA is a trademark of its respective owner. All product and company names are trademarks or registered trademarks of their respective holders. Use of them does not imply any affiliation with or endorsement by them. This image packages the unmodified open source software, which is distributed under the GNU General Public License v3.0 or later.

The FreeIPA web interface sign-in screen

Prerequisites

  • An Azure subscription
  • A VM size with at least 8 GiB of RAM. FreeIPA runs a directory server, a Kerberos KDC and a Java certificate authority together; Standard_B2ms is the recommended minimum and is what this image is tested on
  • An SSH key pair for the azureuser account

Step 1: Deploy from the Azure Marketplace

Find FreeIPA Identity Management on AlmaLinux 9 in the Azure Marketplace, select Get It Now, and create a VM of size Standard_B2ms or larger. Allow inbound 22 for administration, plus 80, 443, 389, 636, 88 and 464 for the identity services described in Step 6.

Step 2: Deploy from the Azure CLI

az group create --name freeipa-rg --location eastus

az vm create \
  --resource-group freeipa-rg \
  --name my-idm \
  --image cloudimg:freeipa-almalinux-9:default:latest \
  --size Standard_B2ms \
  --admin-username azureuser \
  --generate-ssh-keys \
  --public-ip-sku Standard

The VM name matters: by default your realm is derived from it. A VM named my-idm produces the domain my-idm.internal and the realm MY-IDM.INTERNAL. Step 5 explains how to use your own domain instead.

Step 3: Connect to your VM

ssh azureuser@<vm-ip>

Step 4: Wait for first boot to finish

First boot takes about ten minutes, and that is expected. Provisioning an IdM domain means generating a certificate authority from scratch, building a directory instance and creating every Kerberos principal. On a Standard_B2ms this measured 573 seconds end to end, 558 of which were ipa-server-install itself. Nothing times out; the work simply takes that long.

Watch it complete:

sudo systemctl is-active freeipa-firstboot.service

While it is still working this reports activating. When it is finished it reports active, and the record of what was built is written to a sentinel file:

sudo cat /var/lib/cloudimg/freeipa-firstboot.done
provisionedAt=2026-09-20T08:02:38Z
realm=ALMA9-FREEIPA-SMK2-09200650-F7A1C3.INTERNAL
serverFqdn=ipa.alma9-freeipa-smk2-09200650-f7a1c3.internal
ipaServerInstallSeconds=558
firstbootTotalSeconds=573

First boot builds the whole domain on your own VM

Confirm every component of the domain is running:

sudo ipactl status
Directory Service: RUNNING
krb5kdc Service: RUNNING
kadmin Service: RUNNING
httpd Service: RUNNING
ipa-custodia Service: RUNNING
pki-tomcatd Service: RUNNING
ipa-otpd Service: RUNNING

After a reboot the stack takes roughly 90 seconds to come back up fully.

Step 5: Understand your realm, and use your own domain

FreeIPA is unusually sensitive to host naming: the realm and the server's fully qualified name are written into the CA certificate and into every Kerberos principal, and they cannot be changed afterwards without rebuilding the domain.

By default, this image derives a private domain from the name you gave the VM:

VM name Domain Realm Server FQDN
my-idm my-idm.internal MY-IDM.INTERNAL ipa.my-idm.internal

.internal is reserved by ICANN for private use, so this can never collide with a registered name, and deriving it from your VM name keeps your realm distinct. The Azure-supplied <vm>.<id>.bx.internal.cloudapp.net name is deliberately not used as a realm: it lives in Microsoft's namespace and changes shape between virtual networks.

Check what your VM chose:

sudo ipa env realm domain server
  domain: alma9-freeipa-smk2-09200650-f7a1c3.internal
  realm: ALMA9-FREEIPA-SMK2-09200650-F7A1C3.INTERNAL
  server: ipa.alma9-freeipa-smk2-09200650-f7a1c3.internal

To use your own domain, supply it before the VM's first boot by writing /etc/cloudimg/freeipa.conf with cloud-init custom-data at create time:

#cloud-config
write_files:
  - path: /etc/cloudimg/freeipa.conf
    permissions: '0644'
    content: |
      IPA_DOMAIN=idm.example.com
      IPA_HOSTNAME=ipa.idm.example.com
      IPA_REALM=IDM.EXAMPLE.COM
      IPA_NETBIOS=EXAMPLE

Pass it with --custom-data cloud-init.yaml on az vm create. The first-boot script reads these values instead of deriving its own, sets the hostname to IPA_HOSTNAME, and builds the domain there. IPA_HOSTNAME must sit inside IPA_DOMAIN or provisioning stops with a clear error rather than half-building a domain.

If you only realise afterwards, the domain has to be rebuilt: sudo ipa-server-install --uninstall -U, then remove /var/lib/cloudimg/freeipa-firstboot.done and /var/lib/cloudimg/freeipa-domain.env, write the file above, and reboot. Deploying a fresh VM is usually quicker.

Step 6: Check what is listening

ss -lntu | awk 'NR==1 || $5 !~ /127\.0\.0\.1|\[::1\]/' | head -14
sudo firewall-cmd --zone=public --list-ports
22/tcp 80/tcp 88/tcp 389/tcp 443/tcp 464/tcp 636/tcp 88/udp 464/udp

Each open port earns its place:

Port Why it is open
22/tcp SSH administration
80/tcp CA certificate and CRL distribution. ipa-client-install fetches the CA certificate over plain HTTP before it has anything to trust, and issued certificates carry an HTTP CRL distribution point. Browsers are redirected to HTTPS
443/tcp The web interface and the IdM API that the ipa command and every enrolled client use
389/tcp LDAP with STARTTLS, for enrolled clients and LDAP-aware applications
636/tcp LDAPS, for clients that require implicit TLS
88/tcp, 88/udp The Kerberos KDC. UDP is the default transport; TCP is the fallback for large tickets
464/tcp, 464/udp Kerberos password changes (kpasswd) by enrolled users

Three ports are listening on the VM but deliberately closed by the firewall, and should never be opened in your network security group:

  • 8080 and 8443 belong to Dogtag, the certificate authority. The web server reaches Dogtag over a loopback-only AJP connection on 127.0.0.1:8009, so these are purely internal
  • 749 is the Kerberos administration port. FreeIPA administers principals through its own API on 443, and Red Hat's documented FreeIPA port list does not include it

The integrated DNS role is not enabled in this image. FreeIPA can run its own BIND server, but on a VM with a public address that means an internet-reachable recursive resolver, which is a denial-of-service amplification vector and not a safe default. Azure already provides DNS in every virtual network, and Azure Private DNS Zones are the natural place for the _kerberos._tcp and _ldap._tcp service records that clients use for automatic discovery. If you do want the integrated DNS role, add it with sudo ipa-dns-install and restrict recursion to your own network before opening port 53.

The security posture of the running appliance

Step 7: Retrieve your credentials

Both passwords were generated on your VM at first boot and written to a root-only file:

sudo stat -c '%n %a %U:%G' /root/freeipa-credentials.txt
/root/freeipa-credentials.txt 600 root:root
sudo cat /root/freeipa-credentials.txt
# cloudimg FreeIPA on AlmaLinux 9 — per-VM credentials
# Generated on this VM at first boot. These values exist nowhere else.
IPA_REALM=ALMA9-FREEIPA-SMK2-09200650-F7A1C3.INTERNAL
IPA_DOMAIN=alma9-freeipa-smk2-09200650-f7a1c3.internal
IPA_SERVER_FQDN=ipa.alma9-freeipa-smk2-09200650-f7a1c3.internal
IPA_WEB_UI=https://ipa.alma9-freeipa-smk2-09200650-f7a1c3.internal/ipa/ui/
IPA_ADMIN_USER=admin
IPA_ADMIN_PASSWORD=<generated on your VM>
DIRECTORY_MANAGER_DN=cn=Directory Manager
DIRECTORY_MANAGER_PASSWORD=<generated on your VM>

admin is the IdM administrator, used for day-to-day identity management. Directory Manager is the LDAP superuser, used only for low-level directory operations and replica creation — you will rarely need it.

Step 8: Get a Kerberos ticket

Interactively, run sudo kinit admin and type the IPA_ADMIN_PASSWORD value at the prompt. To do it in one step, read the password straight out of the credentials file:

sudo bash -c 'grep ^IPA_ADMIN_PASSWORD= /root/freeipa-credentials.txt | cut -d= -f2- | kinit admin' && echo "ticket granted"

Then confirm you hold a ticket in your own realm:

sudo klist
sudo ipa ping

Kerberos issuing tickets in your own realm

Step 9: Add a user

sudo ipa user-add awilson --first=Amara --last=Wilson --email=awilson@example.com || sudo ipa user-show awilson

Read it back:

sudo ipa user-find

Give the new account a password, which the user must change at their first login:

sudo ipa passwd awilson

Adding and listing users

Step 10: Sign in to the web interface

The web interface is served under the server's own fully qualified name, and FreeIPA redirects any other address there. This is normal for an identity server — the name is what the Kerberos service principal and the TLS certificate are issued for — so point your browser at the name rather than the IP.

The straightforward option is an entry in your workstation's hosts file, mapping your VM's public address to the FQDN from Step 7:

<vm-public-ip>  ipa.my-idm.internal

For a shared deployment, create the equivalent record in an Azure Private DNS Zone linked to your virtual network, or in your own DNS.

Then browse to https://ipa.my-idm.internal/ipa/ui/ and sign in as admin. Your browser will warn that the certificate is not trusted, because it was issued by your VM's own certificate authority; install /etc/ipa/ca.crt as a trusted root to remove the warning.

Signed in, with the user added in Step 9 visible

A user's full identity record

Step 11: Enrol a client machine

On another AlmaLinux, Rocky, RHEL or Fedora machine that can resolve your server's name:

sudo dnf -y install ipa-client
sudo ipa-client-install \
  --server=ipa.my-idm.internal \
  --domain=my-idm.internal \
  --realm=MY-IDM.INTERNAL \
  --principal=admin \
  --mkhomedir

Because the integrated DNS role is not enabled, pass --server, --domain and --realm explicitly rather than relying on SRV-record discovery. Once enrolled, users in your domain can log in to that machine and sudo rules and host-based access control apply.

Step 12: Inspect your certificate authority

Your VM generated its own CA at first boot. Its private key exists only on this VM:

sudo openssl x509 -in /etc/ipa/ca.crt -noout -subject -issuer -dates
subject=O=ALMA9-FREEIPA-SMK2-09200650-F7A1C3.INTERNAL, CN=Certificate Authority
issuer=O=ALMA9-FREEIPA-SMK2-09200650-F7A1C3.INTERNAL, CN=Certificate Authority
notBefore=Sep 20 07:56:46 2026 GMT
notAfter=Sep 20 07:56:46 2046 GMT

Every certificate the domain has issued is listed in the web interface under Authentication → Certificates, and sudo ipa cert-find shows the same from the CLI.

Certificates issued by your VM's own certificate authority

/root/cacert.p12 holds a backup of the CA signing key, encrypted with the Directory Manager password, and is readable only by root. Copy it somewhere safe: without it you cannot rebuild a replica of this CA.

Step 13: Back up the domain

FreeIPA ships its own backup tool, which captures the directory data, the CA and all configuration:

sudo ipa-backup
sudo ls -1 /var/lib/ipa/backup/

Restore with sudo ipa-restore <backup-directory>. Take a backup before any upgrade, and keep /root/cacert.p12 and /root/freeipa-credentials.txt with it.

Step 14: Keep the VM patched

Unattended security updates are enabled:

systemctl is-enabled dnf-automatic.timer
grep -E '^(upgrade_type|apply_updates)' /etc/dnf/automatic.conf
upgrade_type = default
apply_updates = yes

upgrade_type is deliberately default rather than security: security-only mode depends on repository metadata that not every EL-family repository publishes, and getting that judgement wrong produces an image whose automatic updates silently never update anything.

Apply updates by hand at any time:

sudo dnf -y upgrade --refresh

Reboot after a kernel update. The domain survives reboots: the hostname is pinned so that Kerberos principals stay valid.

Security notes

  • No credential is shared between VMs. The IdM admin password, the Directory Manager password, the CA private key and certificate, the Kerberos master key, the LDAP TLS material, the SSH host keys and the machine ID are all generated on your VM at first boot. Two VMs deployed from this image were compared field by field and had nothing in common
  • No credential is baked into the image. The captured image contains no directory instance, no CA and no realm at all, so there is nothing to leak
  • Passwords never reach the process table or the journal. ipa-server-install accepts passwords only on the command line or at an interactive prompt; the command line is visible to every local user through ps and is echoed into the journal, so the first-boot script drives the installer through a pseudo-terminal and supplies both passwords on standard input instead
  • The build account is removed before the image is captured, root is locked, and SSH accepts keys only — PermitRootLogin no and PasswordAuthentication no
  • SELinux is enforcing, with no custom policy module and no permissive domains
  • The Dogtag administration ports (8080, 8443) and the Kerberos administration port (749) are closed by the host firewall
  • Rotate the IdM admin password with sudo ipa passwd admin once you have signed in

Support

cloudimg provides 24/7 support for this image. Contact support@cloudimg.co.uk.