Deployment guide

walt.id Identity

Overview

walt.id Identity is an open-source platform for decentralized identity and verifiable credentials. It gives you the building blocks to issue, hold and verify W3C Verifiable Credentials using open standards, including OpenID for Verifiable Credential Issuance (OID4VCI), OpenID for Verifiable Presentations (OID4VP) and Decentralized Identifiers (DIDs).

This SecureAnyCloud image runs walt.id Identity 0.22.0 on Ubuntu 24.04 LTS. It ships the three core backend services of the stack. Each runs as its pinned upstream container (by immutable digest) under a systemd service that starts it on boot and restarts it on failure.

What you get:

  • The Issuer API on port 7002, which issues Verifiable Credentials to wallets over OID4VCI
  • The Verifier API on port 7003, which requests and verifies Verifiable Presentations over OID4VP and runs configurable credential and presentation policies
  • The Wallet API on port 7001, a server-side holder wallet that can receive, store and present credentials, backed by a local SQLite database
  • walt.id Identity 0.22.0 from the official waltid/issuer-api, waltid/verifier-api and waltid/wallet-api images, pinned by digest and run by systemd
  • The Issuer API and Verifier API served on :7002 and :7003
  • The Wallet API on :7001, bound to loopback so the credential store is not exposed to the internet by default
  • A per-VM wallet administrator account and per-VM wallet signing keys, generated on first boot and recorded in a root-only file
  • A built-in end-to-end self-test that issues, holds and verifies a real credential
  • docker.service, waltid-issuer.service, waltid-verifier.service and waltid-wallet.service as systemd units, enabled and active
  • No administrator baked into the image, and 24/7 SecureAnyCloud support

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 sensible starting size. Choose a larger size for heavier use.

In the network security group (NSG), allow inbound 22/tcp from your management network, and 7002/tcp and 7003/tcp for the Issuer and Verifier APIs. The Wallet API on 7001 is bound to loopback and is not exposed.

The services speak plain HTTP. For production, front them with your own domain and TLS, and set the service base URLs accordingly (see the final step).

Step 1 - Deploy from the Azure Marketplace

Sign in to the Azure Portal, choose Create a resource, search the Marketplace for walt.id Identity 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), 7002 and 7003.

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:waltid-identity-ubuntu-24-04:default:latest
az vm create \
  --resource-group <your-rg> \
  --name waltid-identity \
  --image sac1647283583153:waltid-identity-ubuntu-24-04:default:latest \
  --size Standard_B2s \
  --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 waltid-identity --port 7002 --priority 1010
az vm open-port --resource-group <your-rg> --name waltid-identity --port 7003 --priority 1020

Step 3 - Connect to your VM

ssh azureuser@<vm-public-ip>

Step 4 - Confirm the services are running

The stack runs as four systemd services: docker, waltid-issuer, waltid-verifier and waltid-wallet. Confirm that they are active. Also confirm that the Issuer and Verifier listen on their public ports while the Wallet stays on loopback:

systemctl is-active docker waltid-issuer waltid-verifier waltid-wallet
sudo ss -tlnp | grep -E ':7001|:7002|:7003' | awk '{print $4}' | sort -u

Expected output:

active active active active 127.0.0.1:7001 *:7002 *:7003

Step 5 - Retrieve your per-VM wallet credentials

The image ships with no administrator. On the first boot of every VM, waltid-firstboot.service generates a unique wallet administrator account and unique wallet signing keys, and records them in a root-only file. Confirm that first boot completed, then read the file:

systemctl is-active waltid-firstboot.service
sudo stat -c '%n mode=%a owner=%U:%G' /root/waltid-credentials.txt
sudo cat /root/waltid-credentials.txt

The file contains WALLET_ADMIN_EMAIL, WALLET_ADMIN_PASSWORD, and the Issuer, Verifier and Wallet API URLs. Keep the password safe, because it is unique to this VM.

Step 6 - Run the built-in end-to-end self-test

The image includes a self-test that exercises the whole platform. It issues a Verifiable Credential from the Issuer API and has the Wallet API claim it. It then asks the Verifier API for a presentation, has the Wallet present the credential, and confirms that the Verifier reports the presentation as valid. Run it:

sudo /usr/local/sbin/waltid-selftest.sh

The expected final line is:

SELFTEST_OK issue->hold->verify verified=true

Step 7 - Issue a Verifiable Credential with the Issuer API

The Issuer API issues credentials over OID4VCI. This example creates a fresh issuer key and DID with the onboarding endpoint, then issues an OpenBadge credential. The response is an openid-credential-offer URL that a wallet can claim:

ISSUER=http://127.0.0.1:7002
ONB=$(curl -s -X POST "$ISSUER/onboard/issuer" -H 'Content-Type: application/json' \
  -d '{"key":{"backend":"jwk","keyType":"secp256r1"},"did":{"method":"jwk"}}')
IKEY=$(echo "$ONB" | jq -c '.issuerKey');
IDID=$(echo "$ONB" | jq -r '.issuerDid')
curl -s -X POST "$ISSUER/openid4vc/jwt/issue" -H 'Content-Type: application/json' \
  -d "$(jq -n --argjson ik "$IKEY" --arg did "$IDID" '{ issuerKey:$ik, issuerDid:$did, credentialConfigurationId:"OpenBadgeCredential_jwt_vc_json", credentialData:{"@context":["https://www.w3.org/2018/credentials/v1"],type:["VerifiableCredential","OpenBadgeCredential"],name:"Example badge",credentialSubject:{type:["AchievementSubject"]}}, mapping:{id:"<uuid>",issuer:{id:"<issuerDid>"},credentialSubject:{id:"<subjectDid>"},issuanceDate:"<timestamp>",expirationDate:"<timestamp-in:365d>"}, authenticationMethod:"PRE_AUTHORIZED"}')"; echo

Expected output, an offer URL that a wallet can claim:

openid-credential-offer://?credential_offer_uri=http%3A%2F%2F<vm-ip>%3A7002%2Fdraft13%2FcredentialOffer%3Fid%3D...

Step 8 - Verify a presentation with the Verifier API

The Verifier API creates a presentation request over OID4VP and runs policies against the presentation. Create a request for an OpenBadge credential:

VERIFIER=http://127.0.0.1:7003 curl -s -X POST "$VERIFIER/openid4vc/verify" -H 'Content-Type: application/json' -H 'responseMode: direct_post' \
  -d '{"request_credentials":[{"format":"jwt_vc_json","type":"OpenBadgeCredential"}]}'; echo

The response is an openid4vp://authorize URL that a wallet resolves and answers. The verification result for the session is available at GET /openid4vc/session/<state>. The self-test in Step 6 runs this whole exchange automatically.

Step 9 - Use the Wallet API

The Wallet API is a server-side holder wallet. It is bound to loopback, so the credential store is not exposed. Reach it on the VM, or from your workstation over an SSH tunnel:

ssh -L 7001:127.0.0.1:7001 azureuser@<vm-public-ip>
# then open http://127.0.0.1:7001/swagger and log in with the
# WALLET_ADMIN_EMAIL / WALLET_ADMIN_PASSWORD from Step 5

Step 10 - Production hardening

The Issuer and Verifier serve plain HTTP and embed their own base URL into credential offers and presentation requests, so relying wallets must be able to reach that address. For production:

  • Put the Issuer and Verifier behind your own reverse proxy with TLS and a real domain name.
  • Set the base URLs to your public HTTPS host. Edit baseUrl in /etc/waltid/issuer/config/issuer-service.conf and /etc/waltid/verifier/config/verifier-service.conf, then run sudo systemctl restart waltid-issuer waltid-verifier.
  • Restrict the NSG so that only the hosts that need the Issuer and Verifier can reach 7002 and 7003.
  • Keep the Wallet API on loopback, or expose it only through an authenticated gateway.

The base image is fully patched at build time and has unattended security upgrades enabled, so the OS keeps receiving security updates. For help, contact 24/7 SecureAnyCloud support.

Deploy on Azure

Launch walt.id Identity 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

Deploy on Azure