FreeIPA CLI on Windows 11

Easy instructions for running the ipa command — and launching it cleanly — from a Windows 11 host. Three realistic paths, with a clear recommendation.

The honest short answer
  • There is no native ipa.exe. ipa-client and the ipa command-line are Linux-only.
  • Recommended path: WSL2 + a tiny ipa.bat launcher. It feels like a real Windows command and does not require giving up WSL features.
  • Fallback path: SSH from Windows into the IPA server and run ipa there.
  • Advanced path: call the FreeIPA JSON-RPC API from native Python on Windows with ipalib. Only worth it for building tooling.
  • All three paths need the prereqs in Windows 11 + FreeIPA (CA trust, DNS, time, Kerberos config) done first.

Why there is no ipa.exe

The ipa command is a Python tool built on ipalib. ipalib itself can technically import on Windows, but it depends on Kerberos libraries and a working enrollment that only ships as part of ipa-client. ipa-client uses SSSD, systemd, and a pile of RPM-delivered policy files that have no Windows equivalent. Red Hat has never shipped a supported Windows binary. So the choice is: use Linux, proxy via SSH, or talk to the API directly.

Path A (recommended): WSL2 + ipa.bat

Install WSL2 with a distro that has freeipa-admintools

Fedora is the easiest because FreeIPA is a Red Hat project; Rocky Linux or AlmaLinux work identically and are stable. In an elevated PowerShell:

wsl --install --no-distribution
wsl --set-default-version 2
wsl --install -d FedoraLinux-42     # or: Rocky Linux, AlmaLinux

If a Fedora/Rocky WSL distro is not available in the Microsoft Store for your build, you can import a rootfs tarball:

wsl --import Fedora C:\wsl\Fedora C:\Downloads\fedora-rootfs.tar.xz --version 2
wsl -d Fedora

Install the IPA admin tools inside WSL

sudo dnf install -y freeipa-admintools krb5-workstation ca-certificates

You do not need to run ipa-client-install in WSL for the CLI to work — freeipa-admintools pulls in ipa alone. Only run ipa-client-install if you specifically want WSL enrolled as an IPA host.

Wire up CA trust and Kerberos inside WSL

# Fedora/Rocky/Alma
sudo cp /mnt/c/certs/ipa-ca.crt /etc/pki/ca-trust/source/anchors/ipa-ca.crt
sudo update-ca-trust

# /etc/krb5.conf — minimal
sudo tee /etc/krb5.conf >/dev/null <<'EOF'
[libdefaults]
    default_realm = EXAMPLE.INTERNAL
    dns_lookup_realm = true
    dns_lookup_kdc = true
    rdns = false
    ticket_lifetime = 24h
    renew_lifetime = 7d
    forwardable = true

[realms]
    EXAMPLE.INTERNAL = {
        kdc = ipa.example.internal
        master_kdc = ipa.example.internal
        admin_server = ipa.example.internal
        default_domain = example.internal
    }

[domain_realm]
    .example.internal = EXAMPLE.INTERNAL
    example.internal  = EXAMPLE.INTERNAL
EOF

If your WSL does not inherit Windows DNS, add the IPA DNS to /etc/resolv.conf (and use /etc/wsl.conf with [network] generateResolvConf=false to stop WSL overwriting it).

First run — get a ticket, list users

kinit admin@EXAMPLE.INTERNAL
klist
ipa user-find
ipa host-show $(hostname -f) || true

If ipa user-find returns rows, WSL-side is ready. Now we make it feel like a native Windows command.

Make ipa a Windows command — ipa.bat

Create C:\Tools\ipa.bat (or anywhere on your PATH):

@echo off
setlocal
rem Drop into WSL, renew a TGT if we still have one, then run `ipa` with all args.
rem If there is no TGT yet, `kinit -R` will fail silently and ipa will prompt.
wsl.exe -d Fedora -- bash -lc "kinit -R 2>/dev/null; ipa %*"
endlocal

Make sure C:\Tools is on PATH (System Properties → Environment Variables → User Path → Edit → New → C:\Tools). Open a new terminal and:

ipa user-find
ipa host-show $(hostname -f)
ipa --version

That is it — ipa is now callable from cmd.exe, PowerShell, Windows Terminal, anything.

A one-command ticket refresh (kinit.bat)

Pair it with C:\Tools\kinit.bat so you do not have to wsl in manually when your ticket expires:

@echo off
setlocal
if "%1"=="" (
  wsl.exe -d Fedora -- bash -lc "kinit"
) else (
  wsl.exe -d Fedora -- bash -lc "kinit %*"
)
wsl.exe -d Fedora -- bash -lc "klist"
endlocal
kinit admin           # prompts for password, stores ticket in the WSL ccache
kinit -r 7d admin     # renewable 7-day ticket

Path B: SSH to the IPA server

No WSL allowed? Jump box style works. Windows 11 ships ssh.exe (OpenSSH). Install the IPA CA (see Windows 11 + FreeIPA), then:

ssh admin@ipa.example.internal
# inside the IPA server:
kinit
ipa user-find

Two quality-of-life improvements:

A Windows Terminal profile named "IPA"

Settings → Profiles → New. Command line:

ssh -t admin@ipa.example.internal "tmux new -A -s ipa || bash -l"

That pins your "IPA shell" to a tab in Windows Terminal — click it and you are in.

Kerberos SSO to the IPA SSH server

If you have a working Windows SSPI Kerberos (see next section), add GSSAPIAuthentication=yes to your SSH command or C:\Users\you\.ssh\config:

Host ipa ipa.example.internal
    HostName ipa.example.internal
    User admin
    GSSAPIAuthentication yes
    GSSAPIDelegateCredentials yes

Then ssh ipa uses your existing ticket — no password.

When to pick this path: Windows hosts are corp-locked down, WSL is blocked by policy, but ssh to internal infra is permitted. It is also the right path for anyone who already lives in an IPA bastion workflow.

Path C: native Python + REST (ipalib/JSON-RPC)

FreeIPA exposes a JSON-RPC API at https://<ipa-server>/ipa/json. With the IPA CA trusted (the Windows step from the foundation page) and Kerberos set up on Windows, you can drive it from native Python.

py -m venv C:\Tools\ipa-py
C:\Tools\ipa-py\Scripts\Activate.ps1
pip install ipalib requests-kerberos
# ipa_show_user.py
import sys
from ipalib import api

api.bootstrap(context='cli', in_server=False, server='ipa.example.internal')
api.finalize()
api.Backend.rpcclient.connect()

result = api.Command.user_show(sys.argv[1] if len(sys.argv) > 1 else 'admin')
print(result['result']['uid'], result['result'].get('mail'))
python .\ipa_show_user.py admin

ipalib delegates auth to the system Kerberos stack via gssapi. If that is not importable on Windows (it frequently is not), fall back to REST:

import json, requests
from requests_kerberos import HTTPKerberosAuth, OPTIONAL

s = requests.Session()
s.verify = r'C:\certs\ipa-ca.crt'
s.headers.update({'referer': 'https://ipa.example.internal/ipa'})
auth = HTTPKerberosAuth(mutual_authentication=OPTIONAL)

# Login once (writes cookie)
s.get('https://ipa.example.internal/ipa/session/login_kerberos', auth=auth)

# Call user_show
body = {'method': 'user_show', 'params': [['admin'], {}], 'id': 0}
r = s.post('https://ipa.example.internal/ipa/session/json', json=body)
print(json.dumps(r.json()['result']['result'], indent=2, default=str))

When to pick this path: building native Windows tooling, packaging into an .exe, or anywhere the lack of WSL and lack of SSH is a hard constraint but Python is fine.

Kerberos on Windows for Paths B and C

Both rely on a working Windows-side Kerberos. You have two choices:

MIT Kerberos for Windows (simplest)

Native Windows SSPI (via ksetup)

Do not mix MIT and Windows SSPI in the same process. Pick one per tool. Browsers and RDP use SSPI; ssh.exe and most Python GSSAPI bindings use SSPI on Windows 11; MIT KfW is the simplest way to get kinit admin to "just work" outside of WSL.

Making it feel like a real command

Start Menu shortcut for Path A

Right-click Desktop → New → Shortcut. Target: C:\Tools\ipa.bat. Pin to Start. Now "ipa" is right next to Edge.

Windows Terminal profile

Add a profile with commandLine = wsl.exe -d Fedora -- bash -lc "kinit -R 2>/dev/null; exec bash -l". The tab opens pre-authenticated (if the ticket is still live) into Fedora. Run ipa there for interactive sessions.

PowerShell functions

Add to your $PROFILE:

function ipa { wsl.exe -d Fedora -- bash -lc "kinit -R 2>/dev/null; ipa $($args -join ' ')" }
function kinit-ipa { wsl.exe -d Fedora -- bash -lc "kinit $($args -join ' '); klist" }

Now tab-complete in PowerShell: ipa user-find, ipa host-show ..., kinit-ipa admin.

Common gotchas

SymptomCauseFix
kinit: Clock skew too greatWindows clock off by >5 min from IPARe-sync with w32tm /resync, point at the IPA NTP (see foundation page)
kinit: Cannot contact any KDC for realmWindows cannot resolve IPA SRV recordsPoint DNS at IPA, or keep explicit kdc = lines in krb5.ini
kinit: KDC reply did not match expectationsRealm name case mismatchRealm is case-sensitive — EXAMPLE.INTERNAL, not example.internal
Server not found in Kerberos databaseMissing reverse DNS for the IPA serverAdd a PTR in IPA DNS, or set rdns = false in krb5.ini
TLS error connecting to ipa.example.internalIPA CA not in whichever trust store the tool usesImport the CA per foundation page; for WSL, update-ca-trust
ipa: command not found in WSLfreeipa-admintools not installedsudo dnf install freeipa-admintools
ipa.bat runs but %* expands weirdlycmd.exe quoting of commas, equals, parensQuote the whole arg: ipa "user-mod name --first=Foo" or use the PowerShell function version above
Ticket dies every 10 hours and is not renewableInitial kinit not renewablekinit -r 7d username
Python ipalib import fails on WindowsMissing python-gssapi / MIT libsFall back to the REST pattern in Path C

When to pick which

ConstraintBest path
No constraints, daily-driver adminPath A (WSL2 + ipa.bat)
WSL blocked by corporate policyPath B (SSH)
SSH to IPA blocked by segmentationPath A (WSL2) talks LDAP/HTTPS, not SSH
Need to package a Windows GUI/CLI toolPath C (Python + REST)
Heavy batch admin / scriptsPath A — fastest, full ipa surface, scripts the same as on the IPA servers
Just one-off "show me this user"Path B — nothing to install
Next. If the goal of getting the ipa CLI running is to set up or troubleshoot Keycloak on Windows + LDAPS, continue there.