SSO and Kerberos Setup Guide
Authentication Options Overview
IMTerm supports six authentication methods. Choose one (or combine them) based on your infrastructure:
| Method | When to use |
|---|---|
| Local accounts | Small deployments, no AD, evaluation |
| LDAP / Active Directory | Any organization with a Windows domain |
| OIDC | Okta, Azure AD (Entra ID), Google Workspace, Keycloak |
| SAML | ADFS, PingFederate, older enterprise IdPs |
| Kerberos SPNEGO | Windows domain with zero-login browser SSO |
| mTLS client certificates | High-security, air-gapped, smart-card environments |
Multiple methods can run simultaneously. For example: LDAP for authentication + Kerberos for SSO means users authenticate with AD credentials AND get automatically signed in from domain-joined machines.
Local Accounts
Default method, no external dependencies.
auth:
provider: local
Manage users with:
imterm user add --username admin --role admin
imterm user add --username jsmith --role user
imterm user list
imterm user disable --username jsmith
Passwords are stored as bcrypt hashes. Local accounts are always available as a fallback even when SSO is configured.
LDAP and Active Directory
Active Directory is an LDAP server. IMTerm binds to it using a service account and verifies user passwords via LDAP bind.
config.yaml:
auth:
provider: ldap
ldap:
url: ldap://dc01.corp.com:389
bind_dn: "CN=imterm-svc,OU=Service Accounts,DC=corp,DC=com"
bind_password: "${LDAP_PASSWORD}" # from environment variable
base_dn: "OU=Users,DC=corp,DC=com"
user_filter: "(sAMAccountName=%s)"
group_base_dn: "OU=Groups,DC=corp,DC=com"
group_filter: "(&(objectClass=group)(member=%s))"
tls: false # true for LDAPS (port 636)
start_tls: false # true for STARTTLS on port 389
# Map AD groups to IMTerm roles
role_mapping:
admin: ["CN=IMTerm-Admins,OU=Groups,DC=corp,DC=com"]
user: ["CN=IMTerm-Users,OU=Groups,DC=corp,DC=com", "CN=Domain Users,DC=corp,DC=com"]
Test the connection before restarting IMTerm:
ldapsearch -H ldap://dc01.corp.com -D "CN=imterm-svc,OU=Service Accounts,DC=corp,DC=com" \
-w "$(cat /etc/imterm/ldap-password)" \
-b "OU=Users,DC=corp,DC=com" "(sAMAccountName=jsmith)"
A successful ldapsearch response confirms IMTerm can reach the DC and the bind account works.
For LDAPS (port 636):
ldap:
url: ldaps://dc01.corp.com:636
tls: true
tls_skip_verify: false # never true in production
tls_ca_cert: /etc/imterm/certs/corp-root-ca.pem
Sync groups on login: When a user logs in, IMTerm queries their group membership and updates their role. No scheduled sync needed.
OIDC (Okta, Azure AD, Google Workspace)
Azure AD (Entra ID)
- In the Azure portal, navigate to App registrations > New registration
- Name:
IMTerm, redirect URI:https://imterm.corp.com/auth/callback - Under Certificates & secrets, create a new client secret
- Under API permissions, add
openid,profile,email,User.Read - Copy: Application (client) ID and Directory (tenant) ID
config.yaml:
auth:
provider: oidc
oidc:
issuer_url: "https://login.microsoftonline.com/{tenant-id}/v2.0"
client_id: "{application-client-id}"
client_secret: "${OIDC_CLIENT_SECRET}"
redirect_url: "https://imterm.corp.com/auth/callback"
scopes: ["openid", "profile", "email", "offline_access"]
username_claim: "preferred_username" # or "email"
# Map Azure AD groups to IMTerm roles (requires group_id, not name)
role_mapping:
admin: ["{azure-group-object-id-for-admins}"]
user: ["{azure-group-object-id-for-users}"]
Okta
- In Okta admin, create a new Web Application under Applications
- Grant type: Authorization Code
- Sign-in redirect URI:
https://imterm.corp.com/auth/callback - Copy Client ID and Client secret
auth:
provider: oidc
oidc:
issuer_url: "https://your-org.okta.com"
client_id: "{okta-client-id}"
client_secret: "${OIDC_CLIENT_SECRET}"
redirect_url: "https://imterm.corp.com/auth/callback"
scopes: ["openid", "profile", "email", "groups"]
groups_claim: "groups" # Okta includes groups in the token
role_mapping:
admin: ["imterm-admins"]
user: ["imterm-users", "employees"]
Google Workspace
- In Google Cloud Console, create an OAuth 2.0 Client ID under APIs & Services > Credentials
- Application type: Web application
- Authorized redirect URI:
https://imterm.corp.com/auth/callback
auth:
provider: oidc
oidc:
issuer_url: "https://accounts.google.com"
client_id: "{google-client-id}.apps.googleusercontent.com"
client_secret: "${OIDC_CLIENT_SECRET}"
redirect_url: "https://imterm.corp.com/auth/callback"
scopes: ["openid", "profile", "email"]
username_claim: "email"
# Google does not include groups in OIDC tokens; use hd (hosted domain) claim
hd_restriction: "corp.com" # only allow users from this Google Workspace domain
SAML (ADFS, PingFederate)
ADFS Setup
- In ADFS Management, create a Relying Party Trust
- Import metadata from:
https://imterm.corp.com/auth/saml/metadata - Add claim rules to pass email and group membership
- Note the ADFS federation service name (e.g.,
adfs.corp.com)
config.yaml:
auth:
provider: saml
saml:
entity_id: "https://imterm.corp.com"
metadata_url: "https://adfs.corp.com/FederationMetadata/2007-06/FederationMetadata.xml"
acs_url: "https://imterm.corp.com/auth/saml/callback"
certificate: /etc/imterm/certs/imterm-saml.crt
private_key: /etc/imterm/certs/imterm-saml.key
name_id_format: "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress"
# Attribute name for group membership in SAML assertion
groups_attribute: "http://schemas.microsoft.com/ws/2008/06/identity/claims/groups"
role_mapping:
admin: ["IMTerm-Admins"]
user: ["IMTerm-Users"]
Generate a SAML signing certificate/key pair:
openssl req -x509 -newkey rsa:2048 -keyout imterm-saml.key -out imterm-saml.crt \
-days 3650 -nodes -subj "/CN=imterm.corp.com"
Kerberos SPNEGO (Zero-Login Browser SSO)
Kerberos SPNEGO allows users on domain-joined machines to open IMTerm in their browser without entering a username or password. The browser presents the user's Kerberos ticket automatically.
Prerequisites
- Active Directory domain
- IMTerm server is Linux (domain membership not required)
- Users are on Windows machines joined to the same AD domain
Step 1: Create a Service Account
In Active Directory Users and Computers, create a user account:
- Username: imterm-svc
- Password: set a strong password, mark "Password never expires"
- Uncheck "User must change password at next login"
Step 2: Set the Service Principal Name (SPN)
Run from a Windows machine with AD admin rights:
setspn -S HTTP/imterm.corp.com corp\imterm-svc
setspn -S HTTP/imterm corp\imterm-svc
Verify:
setspn -L corp\imterm-svc
Step 3: Generate the Keytab
ktpass /out imterm.keytab /mapuser corp\imterm-svc@CORP.COM /princ HTTP/imterm.corp.com@CORP.COM /pass "ServiceAccountPassword" /ptype KRB5_NT_PRINCIPAL /crypto AES256-SHA1
Copy imterm.keytab to /etc/imterm/imterm.keytab on the IMTerm server.
Step 4: Configure krb5.conf on Linux
/etc/krb5.conf:
[libdefaults]
default_realm = CORP.COM
dns_lookup_realm = false
dns_lookup_kdc = true
forwardable = true
[realms]
CORP.COM = {
kdc = dc01.corp.com
admin_server = dc01.corp.com
}
[domain_realm]
.corp.com = CORP.COM
corp.com = CORP.COM
Test Kerberos connectivity from the IMTerm server:
kinit -kt /etc/imterm/imterm.keytab HTTP/imterm.corp.com@CORP.COM
klist # should show the TGT
Step 5: Configure IMTerm
auth:
provider: ldap # still use LDAP for authorization/groups
ldap:
url: ldap://dc01.corp.com:389
# ... (as above)
# Kerberos adds SSO on top of LDAP auth
kerberos:
enabled: true
keytab: /etc/imterm/imterm.keytab
principal: "HTTP/imterm.corp.com@CORP.COM"
realm: "CORP.COM"
Step 6: Configure Browsers for SPNEGO
Chrome and Edge: No configuration needed if the IMTerm URL is in the local intranet zone. To explicitly enable:
--auth-server-whitelist="imterm.corp.com"
--auth-negotiate-delegate-whitelist="imterm.corp.com"
Deploy via Group Policy: Computer Configuration > Administrative Templates > Google Chrome > HTTP Authentication > Authentication Server Whitelist
Firefox: Navigate to about:config and set:
- network.negotiate-auth.trusted-uris = https://imterm.corp.com
- network.negotiate-auth.delegation-uris = https://imterm.corp.com
Internet Explorer / Edge (legacy): Add imterm.corp.com to Trusted Sites in Internet Options.
Testing SPNEGO
From a domain-joined Windows machine:
1. Open a command prompt: klist should show cached Kerberos tickets
2. Open Chrome and navigate to https://imterm.corp.com
3. You should be logged in automatically - no login page appears
4. IMTerm logs IMTE1035I: Kerberos authentication success for user@CORP.COM
If you still see the login page, check: - The SPN is registered correctly (step 2) - The browser is configured for SPNEGO (step 6) - IMTerm's hostname matches the SPN exactly
mTLS Client Certificates
Mutual TLS (mTLS) requires users to present a client certificate in their browser or system certificate store. No username/password dialog.
Generate CA and Client Certificates
# Create CA
openssl genrsa -out ca.key 4096
openssl req -new -x509 -days 3650 -key ca.key -out ca.crt -subj "/CN=IMTerm CA"
# Create client certificate for user jsmith
openssl genrsa -out jsmith.key 2048
openssl req -new -key jsmith.key -out jsmith.csr -subj "/CN=jsmith/O=corp"
openssl x509 -req -days 730 -in jsmith.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out jsmith.crt
# Package as PKCS#12 for browser import
openssl pkcs12 -export -in jsmith.crt -inkey jsmith.key -out jsmith.p12 -passout pass:changeme
Configure IMTerm
tls:
cert: /etc/imterm/certs/imterm.crt
key: /etc/imterm/certs/imterm.key
client_ca: /etc/imterm/certs/ca.crt # require client certs
auth:
provider: mtls
mtls:
# Map CN from certificate to IMTerm username
username_field: cn # or email (from SAN)
# Map O from certificate to role
role_mapping:
admin: { organization: "imterm-admins" }
user: { organization: "corp" }
Install Client Certificate in Browser
Chrome/Edge: Import jsmith.p12 in Settings > Privacy & Security > Manage certificates > Import.
Firefox: Settings > Privacy & Security > Certificates > View Certificates > Your Certificates > Import.
When the user navigates to IMTerm, the browser presents the certificate and the user is authenticated automatically.
FIPS 140-2
For government and regulated environments requiring FIPS-compliant cryptography:
# Build with BoringCrypto (FIPS 140-2 validated)
make build-fips
# Produces: bin/imterm-fips
The FIPS binary uses BoringCrypto for all TLS operations. Verify:
bin/imterm-fips --version
# IMTerm v2.0.1 (abc1234) built 2026-06-27 with go1.22.4-fips
FIPS mode enforces: - TLS 1.2+ only (no TLS 1.0 or 1.1) - Approved cipher suites only (AES-GCM, ECDHE) - RSA keys 2048+ bits minimum - SHA-256+ for all certificate hashing
RBAC (Role-Based Access Control)
IMTerm has three roles:
| Role | Permissions |
|---|---|
| admin | All settings, user management, view all sessions, terminate sessions, audit log |
| user | Connect sessions, manage own connection profiles, view own print jobs |
| view-only | Read-only access: view active sessions, cannot connect or change settings |
Assign roles in local accounts or via group mapping in LDAP/OIDC/SAML.
Audit Log Events
Authentication events logged to the audit log (default: /var/log/imterm/audit.jsonl):
| Event ID | Description |
|---|---|
| IMTE1030I | Local auth success |
| IMTE1031W | Local auth failure |
| IMTE1032I | LDAP auth success |
| IMTE1033W | LDAP auth failure |
| IMTE1034I | OIDC auth success |
| IMTE1035I | Kerberos auth success |
| IMTE1036I | SAML auth success |
| IMTE1037I | mTLS auth success |
| IMTE1040W | Authorization failure (wrong role) |
| IMTE1041I | User logout |
| IMTE1050W | Auth provider unreachable |
All events include: timestamp, username, source IP, session ID, and outcome.
Troubleshooting
LDAP: "bind failed" error
Check credentials with ldapsearch first. If the command succeeds but IMTerm fails, verify LDAP_PASSWORD environment variable is set where IMTerm runs.
Kerberos: "KDC_ERR_S_PRINCIPAL_UNKNOWN"
The SPN is not registered. Run setspn -L corp\imterm-svc and verify the SPN matches the hostname in the browser URL exactly.
OIDC: redirect_uri mismatch
The redirect_url in config.yaml must exactly match the redirect URI registered in the IdP. Include the trailing / (or don't) consistently in both places.
SAML: assertion validation failure
Check system clocks. SAML assertions have a strict time window (+/- 5 minutes). If IMTerm's system time differs from the IdP's clock, assertions fail. Use NTP on both systems.
See also: IMTerm Admin Guide section 5 (Security), INTERNAL-LicenseAudit.md