privacyIDEA
Overview
privacyIDEA is an open-source multi-factor authentication server. It manages second factors for your users, such as TOTP and HOTP one-time password tokens, WebAuthn and FIDO2 security keys, SMS and email challenges, and paper tokens. It answers authentication requests over a documented REST API.
privacyIDEA is a standalone authentication back end rather than an identity provider, so it slots in behind things you already run: RADIUS clients such as VPN concentrators, LDAP proxies, SSH, Keycloak and SAML providers, and web applications you write yourself. Your user accounts stay where they already live, in Active Directory, LDAP or a SQL database, and privacyIDEA adds the second factor on top.
The SecureAnyCloud image installs privacyIDEA 3.13.3 into a dedicated Python virtual environment and backs it with a local MariaDB database. It serves privacyIDEA with gunicorn bound to loopback, fronts it with nginx, then locks the result down for marketplace use.
What you get:
- privacyIDEA 3.13.3 installed in a dedicated Python virtual environment and run by gunicorn as the
privacyideasystemd service - The full privacyIDEA management interface and REST API on
:80, and on:443with a per-VM self-signed certificate - MariaDB 10.11 bound to loopback, holding the token, configuration and audit tables
- A per-VM encryption key protecting token seeds, generated on first boot and never shared between VMs
- A per-VM RSA keypair signing the tamper-evident audit log
- A per-VM Flask session key, password pepper and database password, none of them baked into the image
- An administrator account created on first boot with a unique, randomly generated password
- privacyIDEA's own anonymous
/healthz/readiness endpoint for Azure Load Balancer probes, which reports the encryption key state rather than merely that a socket is open privacyidea.service,nginx.serviceandmariadb.serviceas enabled and active systemd units- 24/7 SecureAnyCloud support
privacyIDEA holds several distinct secrets, and this image generates every one of them uniquely on the first boot of each VM. They are the encryption key that protects token seeds in the database, the RSA keypair that signs the tamper-evident audit log, the Flask session key, the password hashing pepper, the database password and the TLS certificate. None of them is baked into the image.
privacyIDEA ships no default administrator account of its own. The only administrator is the one created on your first boot, with a randomly generated password written to a root-only file.
Prerequisites
You need an active Azure subscription, an SSH key pair, and a VNet with a subnet in the target region. Standard_B2s (2 vCPU / 4 GiB RAM) is a comfortable starting size.
In the network security group, allow inbound 22/tcp from your management network and 443/tcp for the management interface and API. Allow 80/tcp if you also want plain HTTP.
privacyIDEA is an authentication server, so expose as few ports as you can. Restrict access to the networks that need to reach it.
Step 1 - Deploy from the Azure Marketplace
Sign in to the Azure Portal, choose Create a resource, search the Marketplace for privacyIDEA by SecureAnyCloud, and select Create.
On the Basics tab, 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) and HTTPS (443).
Select Review + create, then Create.
Step 2 - Deploy from the Azure CLI
# Accept the Marketplace terms once per subscription (required before the first CLI deploy)
az vm image terms accept --urn sac1647283583153:privacyidea:default:latest
az vm create \
--resource-group <your-rg> \
--name privacyidea \
--image sac1647283583153:privacyidea:default:latest \
--size Standard_B2s \
--admin-username azureuser \
--ssh-key-values ~/.ssh/id_rsa.pub \
--public-ip-sku Standard
az vm open-port --resource-group <your-rg> --name privacyidea --port 443 --priority 1001
az vm open-port --resource-group <your-rg> --name privacyidea --port 80 --priority 1002Step 3 - Confirm the services are running
SSH to the VM as azureuser and confirm that privacyIDEA, nginx and MariaDB are up.
The /healthz/ endpoint is privacyIDEA's own readiness probe. It reports "hsm": "OK" only once the encryption key has been loaded. A 200 response therefore means that the server is ready to issue and validate tokens, not just that a web server is listening.
systemctl is-active privacyidea nginx mariadb curl -s http://127.0.0.1/healthz/The first boot takes a few extra seconds compared with later boots, because that is when the per-VM secrets are generated and the database schema is created. If /healthz/ is not yet answering, wait a moment and try again.
Step 4 - Retrieve the per-VM administrator password
Every VM generates its own administrator password on first boot and writes it to a root-only file. Nothing is shared between deployments, and there is no default password to change.
sudo cat /root/privacyidea-credentials.txtThe file records the URL that privacyIDEA resolved for itself. Azure's instance metadata service returns an empty value for a Standard SKU public IP, so a VM can only discover its own private address.
If you are connecting from outside the VNet, browse to the VM's public IP address or DNS name. You can find it on the VM's Overview blade in the Azure Portal.
Step 5 - Sign in to the management interface
Open https://<your-vm-public-ip>/ in a browser. The image ships a self-signed certificate generated for this VM, so your browser warns you on the first visit until you install a certificate of your own (see Step 9). Sign in with the username and password from Step 4.
On your first sign-in, privacyIDEA shows a short welcome tour. Click through it, or dismiss it, to reach the management interface.
Step 6 - Enroll your first token
Issuing second factors is what privacyIDEA is for, so enroll a token first. Go to Tokens, then Enroll Token. Choose TOTP as the token type and select Enroll Token.
privacyIDEA generates a token seed, stores it encrypted with this VM's own encryption key, and displays a QR code. Scan the QR code with any standard authenticator app to add the token.
The QR code carries the token's secret, so treat it like a password. Enroll where nobody can see the screen, and use Regenerate QR Code if you think it was observed.
Newly enrolled tokens appear under Tokens, then All Tokens, with their serial, type and status.
You can do the same from the command line:
export PRIVACYIDEA_CONFIGFILE=/etc/privacyidea/pi.cfg
sudo -E /opt/privacyidea/venv/bin/pi-tokenjanitor findStep 7 - Authenticate against the REST API
Applications talk to privacyIDEA over its REST API. Authenticating to POST /auth returns a signed JSON Web Token, which you present on subsequent calls. Your RADIUS front end, LDAP proxy or application uses the same flow.
PI_PW='<PRIVACYIDEA_PASSWORD>' curl -s -X POST http://127.0.0.1/auth -d "username=admin" -d "password=${PI_PW}" \
| python3 -c 'import json,sys; v=json.load(sys.stdin)["result"]["value"]; print("role:", v["role"]); print("token issued:", bool(v["token"]))'A wrong password is refused, and the returned token is accepted on protected endpoints:
PI_PW='<PRIVACYIDEA_PASSWORD>' curl -s -X POST http://127.0.0.1/auth -d "username=admin" -d "password=definitely-wrong" \
| python3 -c 'import json,sys; print("wrong password rejected:", json.load(sys.stdin)["result"]["status"] is False)'
TOKEN=$(curl -s -X POST http://127.0.0.1/auth -d "username=admin" -d "password=${PI_PW}" \
| python3 -c 'import json,sys; print(json.load(sys.stdin)["result"]["value"]["token"])')
curl -s -H "Authorization: ${TOKEN}" http://127.0.0.1/token/ \
| python3 -c 'import json,sys; print("tokens visible:", json.load(sys.stdin)["result"]["value"]["count"])'Step 8 - Connect your user source
The image deliberately ships with no user source configured, because privacyIDEA is designed to sit in front of the directory you already run. Until you add one, you can enroll tokens that are not assigned to a user. That is enough to explore the product but not to authenticate anybody.
To connect a directory, sign in to the management interface. Go to Config, then Users, and create a resolver. A resolver is a connection to Active Directory, an LDAP server, a SQL database or a flat file.
Then go to Config, then Realms, and create a realm that contains that resolver. A realm is the namespace your users authenticate against. Once one exists, you can assign tokens to real users and point your RADIUS or application front end at privacyIDEA.
Every administrative action is written to the signed audit log under Audit, which records who did what and when.
Step 9 - Install a production TLS certificate
privacyIDEA carries authentication traffic, so reach it over HTTPS with a certificate your clients trust. The image generates a self-signed certificate for the VM on first boot, so port 443 works immediately. Replace it with a real certificate for production.
Copy your certificate and private key over the generated pair and reload nginx:
sudo install -o root -g privacyidea -m 0644 fullchain.pem /etc/privacyidea/tls/server.crt
sudo install -o root -g privacyidea -m 0640 privkey.pem /etc/privacyidea/tls/server.key
sudo nginx -t && sudo systemctl reload nginxOnce you have a real certificate and a DNS name, set PI_BASE_URL in /etc/privacyidea/pi.cfg to that name. privacyIDEA never derives links from the incoming Host header, so password recovery and notification links use this value.
With TLS and a proper hostname in place, you can also re-enable passkey and WebAuthn sign-in. The image hides the passkey button by default. WebAuthn requires a browser secure context and a configured relying party, and neither exists when the appliance is reached over plain HTTP on an IP address.
Remove the policy to bring the button back, then set a webauthn_relying_party_id policy for your domain:
export PRIVACYIDEA_CONFIGFILE=/etc/privacyidea/pi.cfg
sudo -E /opt/privacyidea/venv/bin/pi-manage config policy delete sac_hide_passkeyMaintenance
Service management. privacyIDEA runs under gunicorn as privacyidea.service, behind nginx.service, with mariadb.service holding the data:
systemctl status privacyidea --no-pager --lines=0Restart with sudo systemctl restart privacyidea, and check sudo journalctl -u privacyidea -n 50 if it does not come back. Application logs are at /var/log/privacyidea/privacyidea.log.
Where things live. The virtual environment is at /opt/privacyidea/venv, the WSGI entry point at /opt/privacyidea/privacyideaapp.py, and all configuration and secret material under /etc/privacyidea:
ls -l /etc/privacyidea/pi.cfg holds the configuration, enckey is the encryption key protecting token seeds, and private.pem / public.pem sign the audit log. Keep them backed up. Without enckey the token seeds in the database cannot be decrypted, and every enrolled token is lost.
Backups. privacyIDEA ships its own backup command, which captures both the database and the configuration:
sudo -E PRIVACYIDEA_CONFIGFILE=/etc/privacyidea/pi.cfg /opt/privacyidea/venv/bin/pi-manage backup create --helpStore backups somewhere separate from the VM, and remember they contain the encryption key.
Operating system updates. The image is patched at build time, and unattended security upgrades stay enabled, so security updates keep being applied automatically. Apply the rest on your own schedule:
sudo apt-get update && sudo apt-get -s upgrade | tail -5Upgrading privacyIDEA. Upgrade inside the virtual environment, then run any schema migrations and restart:
sudo /opt/privacyidea/venv/bin/pip install --upgrade privacyidea
sudo -E PRIVACYIDEA_CONFIGFILE=/etc/privacyidea/pi.cfg /opt/privacyidea/venv/bin/pi-manage db upgrade
sudo systemctl restart privacyideaRead the upstream release notes before a major upgrade, and take a backup first.
Troubleshooting
The web interface does not load. Check that nginx and privacyIDEA are both active, and that your NSG allows inbound 443/tcp (or 80/tcp) from your client address. Run curl -s http://127.0.0.1/healthz/ on the VM itself to tell a network problem from an application problem.
/healthz/ returns 503 with "hsm": "fail". privacyIDEA cannot read its encryption key. Confirm that /etc/privacyidea/enckey exists and is readable by the privacyidea user. The file should be mode 0640 and group-owned by privacyidea.
Sign-in is rejected. Confirm that you are using the password from /root/privacyidea-credentials.txt on this VM, because passwords are not shared between deployments. If you have lost it, set a new one with pi-manage admin change admin --password <new>, with PRIVACYIDEA_CONFIGFILE exported.
The browser warns that the certificate is not trusted. This is expected until you install your own certificate, because the image generates a self-signed one per VM. See Step 9.
The passkey button is missing from the sign-in page. It is hidden by design on the default HTTP deployment, where WebAuthn cannot work. See Step 9 to re-enable it once you have TLS and a domain.
Support
SecureAnyCloud publishes this image and provides 24/7 support. For product documentation, see the privacyIDEA documentation. For issues with the image itself, contact SecureAnyCloud support through the Azure Marketplace listing.
privacyIDEA is licensed under the GNU Affero General Public License v3.0. This is a repackaged open-source software product with additional charges for SecureAnyCloud support services.
privacyIDEA is a trademark of its respective owners. 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.
Deploy on Azure
Launch privacyIDEA on Ubuntu 24.04 LTS on Azure with 24/7 support from SecureAnyCloud.
View this image
Need Help?
Our support team is available 24/7.
sales@secureanycloud.com