Admin CLI (ahdapactl)
ahdapactl is the command-line administration tool for ahdapa. It stores
named session credentials in ~/.config/ahdapactl/sessions.toml (mode 0600)
and sends authenticated requests to the admin API on one or more nodes.
Installation
From the RPM package
When ahdapa is installed from the RPM, ahdapactl is included automatically:
- Binary:
/usr/bin/ahdapactl - Man page:
/usr/share/man/man1/ahdapactl.1.gz
No additional steps are needed.
From source
ahdapactl is built as part of the ahdapa workspace:
cargo build --release -p ahdapactl
# Binary: target/release/ahdapactl
Copy it to a directory in your $PATH (e.g. /usr/local/bin/ahdapactl).
Authentication
ahdapactl supports two authentication methods:
- Kerberos SPNEGO — uses the ambient Kerberos ticket cache (
kinitmust have been run beforehand). Selected automatically when a valid TGT is present; forced with--kerberos. - Password — prompts for a password and calls
POST /api/auth/login. Selected automatically when Kerberos is unavailable; forced with--password.
When neither flag is given, ahdapactl login tries Kerberos first and falls
back to password if it fails.
Global flags
| Flag | Description |
|---|---|
--node <ALIAS> | Use the session stored under this alias instead of the default. |
--url <URL> | Override the node URL for this one invocation (does not save). |
--insecure | Accept any TLS certificate (development only). |
--ca-cert <PATH> | Path to a CA certificate PEM file for TLS verification. |
--kerberos | Force Kerberos SPNEGO authentication for this invocation. When combined with --url, performs a transient Kerberos login without storing a session. |
Note:
--passwordis not a global flag. It is available only on theloginandcluster bootstrapsubcommands (see below).
Transient Kerberos mode (FreeIPA integration)
When --url and --kerberos are given together without a prior login, ahdapactl
performs a single authenticated request using the ambient Kerberos ticket cache and
exits without writing or reading any session file. This is the intended invocation
pattern when FreeIPA calls ahdapactl on behalf of an administrator:
ahdapactl --url https://idp.ipa.example.com/idp --ca-cert /etc/ipa/ca.crt \
--kerberos hbac list
Note: Connecting to a FreeIPA server whose TLS certificate is signed with ML-DSA-65 or ML-DSA-87 requires OpenSSL 3.3 or later on the client host.
ahdapactlusesOsslServerCertVerifier, which advertises ML-DSA-44/65/87 in its TLS signature-scheme list and verifies ML-DSACertificateVerifymessages via OpenSSL. On older OpenSSL versions the TLS handshake will fail if the server presents an ML-DSA certificate.
Session management
ahdapactl login <url>
Authenticate to the node at <url> and store the session.
ahdapactl login https://idp.example.com
ahdapactl login https://node1.example.com --name node1
ahdapactl login https://node2.example.com --name node2 --kerberos
ahdapactl login https://node3.example.com --name node3 --password --user admin
| Flag | Description |
|---|---|
--name <ALIAS> | Alias for this session (default: short hostname label). |
-u, --user <USER> | Username for password auth (default: $USER). |
--kerberos | Force Kerberos SPNEGO authentication. Conflicts with --password. |
--password | Force password authentication. Conflicts with --kerberos. |
--kerberos is also available as a global flag (see Global flags) and may be
placed before or after the login subcommand.
The first session saved becomes the default.
ahdapactl logout [alias]
Remove a stored session. Defaults to the current default session.
ahdapactl use <alias>
Set the default session alias.
ahdapactl status
List all stored sessions with their URL, auth method, and expiry time. The
active default is marked with *.
Cluster management
ahdapactl cluster bootstrap <url>...
Bootstrap a new cluster by automating the 5-step key-alignment procedure:
- Log in to every listed node.
- Generate a random 32-byte cluster wrapping key (or use
--keyto supply one). - Push the key to every node via
PUT /api/admin/keys/cluster. - Re-authenticate to every node (sessions are now sealed under the shared key).
- Save all new sessions.
ahdapactl cluster bootstrap \
https://node1.example.com:8080 \
https://node2.example.com:8080 \
https://node3.example.com:8080
The generated wrapping key is printed to stdout. Store it securely — it cannot be recovered from the server.
| Flag | Description |
|---|---|
-u, --user <USER> | Username for password auth. |
--name <PREFIX> | Alias prefix for generated session names (e.g. --name prod → prod-node1). |
--key <BASE64URL> | Existing base64url-encoded 32-byte key to use instead of generating one. |
--kerberos | Force Kerberos SPNEGO authentication. Conflicts with --password. |
--password | Force password authentication. Conflicts with --kerberos. |
--kerberos is also available as a global flag (see Global flags) and may be
placed before or after the cluster bootstrap subcommand.
After bootstrap, verify gossip convergence with ahdapactl cluster status and
the curl check from Provisioning a fresh cluster.
ahdapactl cluster status
Show the current cluster wrapping key UUID and the list of registered nodes with their KEM, signing-key, and wrapping-key recipient status.
ahdapactl cluster key show
Print the cluster wrapping key metadata (UUID and rotation timestamp).
ahdapactl cluster key rotate [BASE64URL]
Rotate the cluster wrapping key. Generates a new random key if no argument is given. Prints the new key to stdout — store it securely.
ahdapactl cluster nodes list
List all registered cluster nodes and their gossip key enrollment status.
ahdapactl cluster nodes seed
Manually seed a node’s ML-KEM-768 public key (and optionally gossip signing key) via the admin API. Used in static-peer deployments when automatic Kerberos-based self-registration is not available.
ahdapactl cluster nodes seed \
--node-id node2.example.com \
--kem-key <BASE64URL-DER> \
[--signing-key <BASE64URL-DER>]
The key values can be obtained from GET /api/gossip/kem-info on the target
node.
JWT signing key management
ahdapactl keys list
List all JWT signing keys registered on the node.
ahdapactl keys rotate
Rotate the JWT signing key. The new key is generated server-side using the
algorithm configured by [server] jwt_signing_algorithm. The old public key
remains in the CRDT so that tokens minted before the rotation are still
verifiable until they expire.
ahdapactl keys delete <kid>
Delete a JWT signing key by its key ID. Only inactive keys (not the currently active signing key) can be deleted.
OAuth2 client management
ahdapactl clients list
List all registered OAuth2 clients.
ahdapactl clients show <id>
Print full JSON for a single client.
ahdapactl clients create
Register a new OAuth2 client.
ahdapactl clients create \
--name "My Application" \
--redirect-uris https://app.example.com/callback \
--scopes openid,profile,email \
[--auth-method private_key_jwt] \
[--jwks-uri https://app.example.com/.well-known/jwks.json]
Alternatively, read all client fields from a TOML file:
ahdapactl clients create --file /path/to/client.toml
The TOML file uses the same [[client]] field names as the static clients
file (see Configuration Reference – [[client]]).
When --file is used, --name, --redirect-uris, and --scopes flags are
not required (their values come from the file).
| Flag | Description |
|---|---|
--file <PATH> | Read client definition from a TOML file (conflicts with --name, --redirect-uris, --scopes). |
--name <NAME> | Human-readable client name (required unless --file). |
--redirect-uris <URL,...> | Comma-separated allowed redirect URIs. |
--scopes <SCOPE,...> | Comma-separated allowed scopes. |
--auth-method <METHOD> | Token endpoint auth method (default: client_secret_basic). |
--secret <SECRET> | Pre-shared secret for client_secret_* methods. |
--grant-types <TYPE,...> | Comma-separated allowed grant types. |
--jwks-uri <URL> | JWKS endpoint for private_key_jwt. |
--id-token-alg <ALG> | JWS algorithm for ID tokens issued to this client. |
ahdapactl clients delete <id>
Delete a client by its client_id. Static clients (seeded from the
[clients] file) are rejected with 403 Forbidden.
ahdapactl clients credentials generate <CLIENT_ID>
Generate OIDC client credentials for SSSD consumption. Generates key material, optionally builds a self-signed certificate, packages into PKCS#12, and registers the credentials with the ahdapa server.
Three authentication methods are supported, matching SSSD’s oidc_child --client-auth-method options:
--auth-method | Server registration | Output |
|---|---|---|
client_secret | client_secret_basic + generated secret | Secret printed to stdout |
mtls (self-signed) | self_signed_tls_client_auth + certificate | PKCS#12 file + password |
mtls (external cert) | tls_client_auth + subject DN | Confirmation only |
private_key_jwt | private_key_jwt + jwks_uri | PKCS#12 file + JWKS file + password |
| Flag | Description |
|---|---|
--auth-method <METHOD> | Required. One of: client_secret, mtls, private_key_jwt. |
--key-type <TYPE> | Key algorithm (default: ec-p256). Options: ec-p256, ec-p384, ec-p521, rsa-2048, rsa-4096, ed25519, ed448, ml-dsa-44, ml-dsa-65, ml-dsa-87. |
--output <PATH> | PKCS#12 output path (required for mtls/private_key_jwt). |
--certificate <PATH> | External PEM certificate (mtls only, skips key generation). |
--subject-dn <DN> | Certificate subject DN (default: CN=<client_id>). |
--validity-days <N> | Certificate validity (default: 365). |
--jwks-uri <URL> | Where the JWKS is hosted (required for private_key_jwt). |
--force | Overwrite existing output files. |
--dry-run | Preview changes without modifying server or writing files. |
User and group inspection
These commands are read-only. User management is performed in FreeIPA.
ahdapactl users list
List all users visible to the identity API.
ahdapactl users show <username>
Print the full profile for one user.
ahdapactl users groups
List all groups.
ahdapactl users group <name>
Print members of a group.
Scope management
ahdapactl scopes list
List all defined OAuth2 scopes and their claimed mappings.
ahdapactl scopes update <name>
Update a scope’s description and claim list.
ahdapactl scopes update profile \
--description "Basic profile claims" \
--claims name,given_name,family_name,email
ahdapactl scopes delete <name>
Delete a scope definition.
HBAC rule management
ahdapactl hbac list
List all HBAC rules. Prints a summary table with columns: ID, name, enabled, user count, client count, scope count.
ahdapactl hbac list
ahdapactl hbac show <id>
Print the full rule detail as pretty-printed JSON.
ahdapactl hbac show 01234567-89ab-cdef-0123-456789abcdef
ahdapactl hbac create
Create a new HBAC rule and print the generated ID. All member arguments are
optional: when none are provided the rule is created empty and disabled;
members can be added later with hbac update. When initial-member flags are
provided the rule is created with those members set via a follow-up PUT
(create then configure in one command).
ahdapactl hbac create --name "HR portal access"
ahdapactl hbac create --name "Finance MFA" --description "Require MFA for finance tools"
# Create with initial members — equivalent to create + update in one step
ahdapactl hbac create --name "HR portal access" \
--users alice,bob \
--user-groups hr-staff \
--clients hr-portal \
--scopes openid,email,profile \
--enabled true
Required:
| Flag | Description |
|---|---|
--name <NAME> | Rule name. |
Optional general flags:
| Flag | Description |
|---|---|
--description <DESC> | Human-readable description. |
--enabled <BOOL> | Enable the rule immediately (true / false; default: false). |
--mfa-bypass <BOOL> | Set MFA bypass (true = skip MFA check; required for M2M flows). |
--required-acr <VALUE> | Set required ACR value. |
Optional user axis flags:
| Flag | Description |
|---|---|
--users <USER,...> | Initial users (comma-separated). |
--user-groups <GRP,...> | Initial user groups. |
--user-category <BOOL> | Set user category to all (true) or specific (false). |
Optional host/service axis flags (PAM/SSH compatibility):
| Flag | Description |
|---|---|
--hosts <HOST,...> | Initial hosts. |
--host-groups <GRP,...> | Initial host groups. |
--host-category <BOOL> | Set host category to all. |
--services <SVC,...> | Initial services. |
--service-groups <GRP,...> | Initial service groups. |
--service-category <BOOL> | Set service category to all. |
Optional client/scope axis flags:
| Flag | Description |
|---|---|
--clients <ID,...> | Initial OAuth2 client IDs. |
--client-groups <GRP,...> | Initial client groups. |
--client-category <BOOL> | Set client category to all. |
--scopes <SCOPE,...> | Initial allowed scopes. |
--scope-category <BOOL> | Set scope category to all. |
Optional network axis flags:
| Flag | Description |
|---|---|
--networks <CIDR,...> | Initial source network CIDRs. |
--network-category <BOOL> | Set network category to all. |
Optional device axis flags:
| Flag | Description |
|---|---|
--device-groups <GRP,...> | Initial device groups. |
--device-category <BOOL> | Set device category to all. |
Optional delegation flags:
| Flag | Description |
|---|---|
--delegation-targets <SPN,...> | Initial Kerberos SPNs as delegation targets. |
--delegation-target-category <BOOL> | Set delegation target category to all (wildcard). |
ahdapactl hbac delete <id>
Delete an HBAC rule by its ID.
ahdapactl hbac delete 01234567-89ab-cdef-0123-456789abcdef
ahdapactl hbac enable <id>
Enable an HBAC rule.
ahdapactl hbac enable 01234567-89ab-cdef-0123-456789abcdef
ahdapactl hbac disable <id>
Disable an HBAC rule (no access is granted by a disabled rule).
ahdapactl hbac disable 01234567-89ab-cdef-0123-456789abcdef
ahdapactl hbac update <id>
Patch an existing HBAC rule using add/remove semantics for all HBAC axes. Only the flags you provide are applied; omitted axes are unchanged.
# Add users and a client to the rule
ahdapactl hbac update <id> \
--add-users alice,bob \
--add-clients hr-portal \
--add-scopes openid,email,profile
# Remove a user and enable MFA bypass for M2M flows
ahdapactl hbac update <id> \
--remove-users charlie \
--mfa-bypass true
# Set user category to "all" (any user matches)
ahdapactl hbac update <id> --user-category true
# Add delegation targets for OBO token exchange
ahdapactl hbac update <id> \
--add-delegation-targets host/backend.example.com
# Restrict by source network
ahdapactl hbac update <id> \
--add-networks 10.0.0.0/8,172.16.0.0/12
# Set required ACR (use empty string to clear)
ahdapactl hbac update <id> --required-acr urn:example:mfa
ahdapactl hbac update <id> --required-acr ""
# Rename and add a description
ahdapactl hbac update <id> \
--name "Updated rule name" \
--description "New description"
User axis flags:
| Flag | Description |
|---|---|
--add-users <USER,...> | Add users (comma-separated). |
--remove-users <USER,...> | Remove users. |
--user-category <BOOL> | Set user category to all (true) or specific (false). |
--add-user-groups <GRP,...> | Add user groups. |
--remove-user-groups <GRP,...> | Remove user groups. |
Client axis flags:
| Flag | Description |
|---|---|
--add-clients <ID,...> | Add OAuth2 client IDs. |
--remove-clients <ID,...> | Remove OAuth2 client IDs. |
--client-category <BOOL> | Set client category to all (true) or specific (false). |
--add-client-groups <GRP,...> | Add client groups. |
--remove-client-groups <GRP,...> | Remove client groups. |
Scope axis flags:
| Flag | Description |
|---|---|
--add-scopes <SCOPE,...> | Add allowed scopes. |
--remove-scopes <SCOPE,...> | Remove allowed scopes. |
--scope-category <BOOL> | Set scope category to all (true) or specific (false). |
Network axis flags:
| Flag | Description |
|---|---|
--add-networks <CIDR,...> | Add source network CIDRs. |
--remove-networks <CIDR,...> | Remove source network CIDRs. |
--network-category <BOOL> | Set network category to all (true) or specific (false). |
Host/service axis flags (PAM/SSH compatibility):
| Flag | Description |
|---|---|
--add-hosts <HOST,...> | Add hosts. |
--remove-hosts <HOST,...> | Remove hosts. |
--host-category <BOOL> | Set host category to all. |
--add-host-groups <GRP,...> | Add host groups. |
--remove-host-groups <GRP,...> | Remove host groups. |
--add-services <SVC,...> | Add services. |
--remove-services <SVC,...> | Remove services. |
--service-category <BOOL> | Set service category to all. |
--add-service-groups <GRP,...> | Add service groups. |
--remove-service-groups <GRP,...> | Remove service groups. |
Device axis flags:
| Flag | Description |
|---|---|
--add-device-groups <GRP,...> | Add device groups. |
--remove-device-groups <GRP,...> | Remove device groups. |
--device-category <BOOL> | Set device category to all. |
Security and delegation flags:
| Flag | Description |
|---|---|
--mfa-bypass <BOOL> | Set MFA bypass (true = skip MFA check; required for M2M flows). |
--required-acr <VALUE> | Set required ACR value (empty string to clear). |
--add-delegation-targets <SPN,...> | Add Kerberos SPNs as delegation targets. |
--remove-delegation-targets <SPN,...> | Remove delegation targets. |
--delegation-target-category <BOOL> | Set delegation target category to all (wildcard). |
General flags:
| Flag | Description |
|---|---|
--name <NAME> | Rename the rule. |
--description <DESC> | Update the description. |
--enabled <BOOL> | Enable or disable the rule. |
Audit log
ahdapactl audit list
Query audit events from the systemd journal (or JSONL fallback). Supports filtering by event type, subject, outcome, and time range.
ahdapactl audit list
ahdapactl audit list --type login.failed --limit 20
ahdapactl audit list --subject alice@EXAMPLE.COM --from 2026-06-01T00:00:00Z
ahdapactl audit list --outcome failure --offset 50
| Flag | Description |
|---|---|
--type <TYPE> | Filter by event type (e.g. login.success, token.issued). |
--subject <SUB> | Filter by subject (user or machine principal). |
--outcome <OUTCOME> | Filter by outcome (success or failure). |
--from <RFC3339> | Start time (e.g. 2026-06-01T00:00:00Z). |
--until <RFC3339> | End time. |
--limit <N> | Maximum events to return (default: 100). |
--offset <N> | Skip N events for pagination (default: 0). |
Examples
Bootstrap a three-node cluster with Kerberos:
ahdapactl cluster bootstrap --kerberos \
https://ipa1.example.com/idp \
https://ipa2.example.com/idp \
https://ipa3.example.com/idp
Register a confidential client:
ahdapactl login https://idp.example.com
ahdapactl clients create \
--name "Internal API" \
--scopes openid,profile \
--auth-method client_secret_basic \
--secret "$(openssl rand -base64 32)"
Rotate the JWT signing key on all nodes (multi-node cluster):
for alias in node1 node2 node3; do
ahdapactl --node "$alias" keys rotate
done
Create an HBAC rule restricting an app to a specific group:
ahdapactl login https://idp.example.com
# Option A: create with all members in one step
ahdapactl hbac create --name "HR portal — hr-staff only" \
--user-groups hr-staff \
--clients hr-portal \
--scopes openid,email,profile \
--enabled true
# Option B: create empty, then configure separately
ahdapactl hbac create --name "HR portal — hr-staff only"
ahdapactl hbac update <id> \
--add-user-groups hr-staff \
--add-clients hr-portal \
--add-scopes openid,email,profile
ahdapactl hbac enable <id>
# Verify
ahdapactl hbac list
ahdapactl hbac show <id>
Set up a two-rule pattern for OBO deployments:
# Rule 1: CC base — covers all clients for client_credentials (one step)
ahdapactl hbac create --name "M2M base — client credentials" \
--client-category true \
--user-category true \
--scope-category true \
--mfa-bypass true \
--delegation-targets _cc_only \
--enabled true
# Rule 2: OBO rule — explicit delegation to the backend (one step)
ahdapactl hbac create --name "Agent OBO to backend" \
--clients pipeline-agent-id \
--user-category true \
--scope-category true \
--mfa-bypass true \
--delegation-targets host/backend.example.com \
--enabled true
Generate mTLS credentials for an SSSD client:
ahdapactl clients create \
--name "SSSD mTLS client" \
--redirect-uris "urn:ietf:wg:oauth:2.0:oob" \
--scopes openid \
--generate-credentials mtls \
--key-type ec-p256 \
--output /etc/sssd/client.p12
Or for an existing client:
ahdapactl clients credentials generate <client-id> \
--auth-method mtls \
--key-type ec-p256 \
--output /etc/sssd/client.p12
Generate client_secret credentials for SSSD:
ahdapactl clients credentials generate <client-id> \
--auth-method client_secret
Generate private_key_jwt credentials with JWKS:
ahdapactl clients credentials generate <client-id> \
--auth-method private_key_jwt \
--key-type ec-p256 \
--output /etc/sssd/client.p12 \
--jwks-uri https://sssd-host.example.com/.well-known/jwks.json
# Copy /etc/sssd/client-jwks.json to the JWKS URI location
Generate post-quantum mTLS credentials (ML-DSA-65):
ahdapactl clients credentials generate <client-id> \
--auth-method mtls \
--key-type ml-dsa-65 \
--output /etc/sssd/client.p12
Preview what would be configured (dry-run):
ahdapactl clients credentials generate <client-id> \
--auth-method mtls \
--key-type ec-p256 \
--output /etc/sssd/client.p12 \
--dry-run