System Accounts
Service authentication for applications without Kerberos support using dedicated system accounts
Overview
System accounts, introduced in FreeIPA 4.13.0, provide a secure way for applications and services to authenticate to FreeIPA when Kerberos authentication is not available. These specialized LDAP objects enable non-human service authentication while maintaining FreeIPA’s security model and access control framework.
Unlike traditional user accounts, system accounts are designed exclusively for programmatic access and don’t represent actual users or require POSIX attributes.
Why System Accounts?
Legacy Application Support
Many enterprise applications lack native Kerberos support but need to interact with FreeIPA’s LDAP directory. System accounts provide these applications with authentication credentials without creating full user accounts.
Common scenarios include:
- Database management tools querying LDAP for user information
- Legacy authentication systems performing password validation
- Monitoring tools collecting identity data
- Third-party integrations requiring directory access
External Password Management
Organizations using external password management systems (like enterprise password vaults or synchronization tools) need controlled access to modify user passwords without triggering FreeIPA’s password policy reset mechanisms.
System accounts with privileged password change capabilities solve this by:
- Allowing password updates without forcing user password changes at next login
- Maintaining audit trails of password modifications
- Enabling integration with external credential management systems
- Supporting password synchronization across multiple platforms
Key Differences from Regular Users
System accounts are fundamentally different from standard user accounts:
| Feature | System Account | Regular User |
|---|---|---|
| Purpose | Service authentication | Human authentication |
| Object Classes | account, simpleSecurityObject | inetOrgPerson, posixAccount |
| Authentication | LDAP bind with password | Kerberos + optional password |
| POSIX Attributes | None (no UID/GID) | Required for Unix access |
| Login Capability | Cannot login to systems | Can login to enrolled hosts |
| Identification | LDAP DN only | Username, UID, email, etc. |
Authentication Mechanism
System accounts authenticate using LDAP simple bind:
DN: uid=my-app,cn=sysaccounts,cn=etc,dc=example,dc=com
Password: stored in userPassword attribute
Applications perform LDAP bind operations:
import ldap
# Initialize connection
conn = ldap.initialize('ldaps://ipa.example.com')
# Bind as system account
conn.simple_bind_s(
'uid=my-app,cn=sysaccounts,cn=etc,dc=example,dc=com',
'system-account-password'
)
# Perform LDAP operations
result = conn.search_s(
'cn=users,cn=accounts,dc=example,dc=com',
ldap.SCOPE_SUBTREE,
'(objectClass=person)'
)
Privileged System Accounts
System accounts can be designated as “privileged” to enable password management capabilities:
Standard System Account
- Read-only access to directory information
- Cannot modify user passwords
- Limited to search and bind operations
Privileged System Account
- Can modify user passwords
- Password changes don’t trigger “change on next login”
- Ideal for password synchronization systems
- Requires explicit permission grants
Management Commands
Creating System Accounts
# Create basic system account
ipa sysaccount-add app-reader \
--desc="Application for reading user data"
# Create privileged system account with random password
ipa sysaccount-add password-sync \
--desc="Password synchronization service" \
--privileged=true \
--random
# Create with specific password
ipa sysaccount-add monitoring \
--desc="Monitoring system" \
--password
The --random flag generates a secure random password, which is displayed once during creation.
Managing System Accounts
# List all system accounts
ipa sysaccount-find
# Show account details
ipa sysaccount-show app-reader
# Modify account description
ipa sysaccount-mod app-reader \
--desc="Updated description"
# Change password
ipa sysaccount-mod app-reader --password
# Disable account (prevent LDAP bind)
ipa sysaccount-disable app-reader
# Re-enable account
ipa sysaccount-enable app-reader
# Delete account
ipa sysaccount-del app-reader
Managing Privileged Status
# Grant privileged password change capability
ipa sysaccount-policy password-sync \
--privileged=true
# Revoke privileged status
ipa sysaccount-policy password-sync \
--privileged=false
# View privileged accounts
ipa sysaccount-find --privileged=true
Role-Based Access Control
System accounts integrate with FreeIPA’s RBAC system through roles and privileges:
Basic Workflow
# 1. Create custom privilege
ipa privilege-add 'App User Read Privilege' \
--desc="Read user information"
# 2. Add permissions to privilege
ipa privilege-add-permission 'App User Read Privilege' \
--permissions='System: Read Users'
# 3. Create role
ipa role-add 'Application Reader Role' \
--desc="Role for read-only applications"
# 4. Add privilege to role
ipa role-add-privilege 'Application Reader Role' \
--privileges='App User Read Privilege'
# 5. Assign system account to role
ipa role-add-member 'Application Reader Role' \
--sysaccounts=app-reader
Password Management Privileges
For privileged password changes:
# Create password management privilege
ipa privilege-add 'Password Sync Privilege' \
--desc="Change user passwords without reset"
# Add password change permission
ipa privilege-add-permission 'Password Sync Privilege' \
--permissions='System: Change User password'
# Create role
ipa role-add 'Password Sync Role'
# Add privilege to role
ipa role-add-privilege 'Password Sync Role' \
--privileges='Password Sync Privilege'
# Assign privileged system account to role
ipa role-add-member 'Password Sync Role' \
--sysaccounts=password-sync
Use Cases
Password Synchronization
Synchronize passwords between FreeIPA and external systems:
#!/usr/bin/env python3
import ldap
import ldap.modlist as modlist
# System account credentials
SYSACCOUNT_DN = 'uid=password-sync,cn=sysaccounts,cn=etc,dc=example,dc=com'
SYSACCOUNT_PW = 'secure-password'
def sync_password(username, new_password):
"""Update user password without forcing reset"""
# Connect and bind
conn = ldap.initialize('ldaps://ipa.example.com')
conn.simple_bind_s(SYSACCOUNT_DN, SYSACCOUNT_PW)
# Find user DN
user_dn = f'uid={username},cn=users,cn=accounts,dc=example,dc=com'
# Modify password
mod_attrs = [(ldap.MOD_REPLACE, 'userPassword', new_password.encode())]
conn.modify_s(user_dn, mod_attrs)
print(f"Password updated for {username}")
conn.unbind()
# Sync password from external system
sync_password('jsmith', 'NewSecurePassword123!')
Legacy Application Integration
Authenticate legacy applications to LDAP:
# Create system account for legacy app
ipa sysaccount-add legacy-app \
--desc="Legacy HR application" \
--random
# Grant read-only access to user data
ipa role-add 'Legacy App Reader'
ipa role-add-privilege 'Legacy App Reader' \
--privileges='User Administrators'
ipa role-add-member 'Legacy App Reader' \
--sysaccounts=legacy-app
Application configuration:
# legacy-app.conf
ldap_uri = ldaps://ipa.example.com
ldap_bind_dn = uid=legacy-app,cn=sysaccounts,cn=etc,dc=example,dc=com
ldap_bind_password = [password from ipa sysaccount-add]
ldap_search_base = cn=users,cn=accounts,dc=example,dc=com
Monitoring and Automation
Create read-only access for monitoring systems:
# Create monitoring account
ipa sysaccount-add nagios \
--desc="Nagios monitoring system" \
--random
# Grant search permissions only
ipa role-add 'Monitoring Role'
ipa privilege-add 'Monitoring Privilege'
ipa privilege-add-permission 'Monitoring Privilege' \
--permissions='System: Read Users' \
--permissions='System: Read Groups' \
--permissions='System: Read Hosts'
ipa role-add-privilege 'Monitoring Role' \
--privileges='Monitoring Privilege'
ipa role-add-member 'Monitoring Role' \
--sysaccounts=nagios
Monitoring script:
#!/bin/bash
# Check FreeIPA user count
SYSACCOUNT_DN="uid=nagios,cn=sysaccounts,cn=etc,dc=example,dc=com"
SYSACCOUNT_PW="monitoring-password"
USER_COUNT=$(ldapsearch -x -H ldaps://ipa.example.com \
-D "$SYSACCOUNT_DN" \
-w "$SYSACCOUNT_PW" \
-b "cn=users,cn=accounts,dc=example,dc=com" \
"(objectClass=person)" dn | grep -c "^dn:")
echo "Total users: $USER_COUNT"
if [ $USER_COUNT -lt 1 ]; then
echo "CRITICAL: No users found"
exit 2
fi
DevOps Automation
Automate user provisioning with system accounts:
#!/usr/bin/env python3
"""
Automated user onboarding script using system account
"""
import ldap
import ldap.modlist as modlist
import json
SYSACCOUNT_DN = 'uid=provisioning,cn=sysaccounts,cn=etc,dc=example,dc=com'
SYSACCOUNT_PW = 'automation-password'
def create_user_ldap(user_data):
"""Create user via LDAP using system account"""
conn = ldap.initialize('ldaps://ipa.example.com')
conn.simple_bind_s(SYSACCOUNT_DN, SYSACCOUNT_PW)
dn = f"uid={user_data['username']},cn=users,cn=accounts,dc=example,dc=com"
attrs = {
'objectClass': [b'inetOrgPerson', b'person'],
'cn': [user_data['fullname'].encode()],
'sn': [user_data['lastname'].encode()],
'givenName': [user_data['firstname'].encode()],
'mail': [user_data['email'].encode()],
'uid': [user_data['username'].encode()],
}
ldif = modlist.addModlist(attrs)
conn.add_s(dn, ldif)
print(f"Created user: {user_data['username']}")
conn.unbind()
# Read from onboarding system
with open('new_users.json') as f:
users = json.load(f)
for user in users:
create_user_ldap(user)
Multi-Server Considerations
Important: The privileged system accounts configuration is not replicated across FreeIPA servers. Each server maintains its own list of privileged accounts.
Managing Across Replicas
Update privileged status on all servers:
# List all IPA servers
ipa server-find --pkey-only
# Update on specific server
ipa sysaccount-policy password-sync \
--privileged=true \
--force-server=ipa01.example.com
ipa sysaccount-policy password-sync \
--privileged=true \
--force-server=ipa02.example.com
ipa sysaccount-policy password-sync \
--privileged=true \
--force-server=ipa03.example.com
Automation script:
#!/bin/bash
# Synchronize system account policy across all servers
ACCOUNT="password-sync"
# Get all servers
SERVERS=$(ipa server-find --pkey-only | grep "Server name:" | awk '{print $3}')
for server in $SERVERS; do
echo "Updating policy on $server..."
ipa sysaccount-policy "$ACCOUNT" \
--privileged=true \
--force-server="$server"
done
echo "Policy synchronized across all servers"
Security Best Practices
1. Use Strong Passwords
Generate secure random passwords:
# Always use --random for production
ipa sysaccount-add production-app --random
# Store password securely (don't save in shell history)
ipa sysaccount-add app-name --password
# Enter password interactively
2. Principle of Least Privilege
Grant minimum necessary permissions:
# Bad: Assigning admin privileges
ipa role-add-member 'Security Architect' --sysaccounts=app
# Good: Create specific role with limited permissions
ipa privilege-add 'App Specific Privilege'
ipa privilege-add-permission 'App Specific Privilege' \
--permissions='System: Read Users'
ipa role-add 'App Specific Role'
ipa role-add-privilege 'App Specific Role' \
--privileges='App Specific Privilege'
ipa role-add-member 'App Specific Role' --sysaccounts=app
3. Regular Audits
Monitor system account usage:
# List all system accounts
ipa sysaccount-find --all
# Find privileged accounts
ipa sysaccount-find --privileged=true
# Review roles and privileges
ipa role-show 'App Role' --all
4. Disable Unused Accounts
Don’t delete immediately; disable first:
# Disable instead of delete
ipa sysaccount-disable old-app
# Monitor for issues, then delete
ipa sysaccount-del old-app
5. Secure Credential Storage
Store passwords securely in applications:
# Use environment variables (not hardcoded)
export LDAP_BIND_PASSWORD="$(cat /secure/path/password)"
# Or use secret management systems
# - HashiCorp Vault
# - Kubernetes Secrets
# - AWS Secrets Manager
6. Monitor Authentication
Track system account binds:
# Enable LDAP access logging
ldapmodify -x -D "cn=Directory Manager" -W << EOF
dn: cn=config
changetype: modify
replace: nsslapd-accesslog-level
nsslapd-accesslog-level: 256
EOF
# Monitor access logs
tail -f /var/log/dirsrv/slapd-*/access | grep "cn=sysaccounts"
Troubleshooting
Cannot Bind as System Account
# Verify account exists
ipa sysaccount-show my-app
# Check if disabled
ipa sysaccount-show my-app | grep "Account disabled"
# Enable if needed
ipa sysaccount-enable my-app
# Test bind
ldapwhoami -x -H ldaps://ipa.example.com \
-D "uid=my-app,cn=sysaccounts,cn=etc,dc=example,dc=com" \
-W
Password Change Not Working
# Verify account is privileged
ipa sysaccount-find --privileged=true | grep my-app
# Check privileged status on current server
ipa sysaccount-policy my-app
# Verify permissions
ipa role-show 'My App Role' --all
# Ensure 'System: Change User password' permission granted
Permission Denied
# Check role membership
ipa role-show 'App Role' --all
# Verify privilege includes needed permissions
ipa privilege-show 'App Privilege' --all
# Test with IPA CLI using system account (if possible)
kinit admin
ipa user-show testuser
Administrative Permissions
Default FreeIPA roles with system account management:
- Security Architect: Full system account administration
- Add/modify/remove system accounts
- Configure privileged status
- Manage system account roles
Custom delegation:
# Create help desk role for basic management
ipa privilege-add 'System Account Help Desk'
ipa privilege-add-permission 'System Account Help Desk' \
--permissions='System: Add System Accounts' \
--permissions='System: Modify System Accounts' \
--permissions='System: Remove System Accounts'
ipa role-add 'System Account Operators'
ipa role-add-privilege 'System Account Operators' \
--privileges='System Account Help Desk'
ipa role-add-member 'System Account Operators' \
--users=helpdesk_staff
Migration from Service Accounts
If migrating from generic service accounts to system accounts:
# 1. Create system account
ipa sysaccount-add new-system-app \
--desc="Migrated from service user" \
--random
# 2. Grant equivalent permissions via roles
ipa role-add-member 'Appropriate Role' \
--sysaccounts=new-system-app
# 3. Update application configuration
# Change DN from:
# uid=serviceuser,cn=users,cn=accounts,dc=example,dc=com
# To:
# uid=new-system-app,cn=sysaccounts,cn=etc,dc=example,dc=com
# 4. Test thoroughly in non-production
# 5. Disable old service user
ipa user-disable serviceuser
# 6. Monitor and delete after confirmation
ipa user-del serviceuser --preserve
Limitations
No Kerberos Support
System accounts cannot obtain Kerberos tickets:
# This will fail
kinit uid=my-app,cn=sysaccounts,cn=etc,dc=example,dc=com
# System accounts use LDAP bind only
No POSIX Attributes
Cannot be used for system login:
# System account has no UID/GID
ipa sysaccount-show my-app
# No uidNumber or gidNumber
# Cannot SSH or login to systems
ssh my-app@server.example.com # Will fail
Per-Server Configuration
Privileged status requires manual synchronization:
- Not automatically replicated
- Must update each server individually
- Use
--force-serveror SSH to each replica - Consider automation scripts for consistency
Getting Started
Quick start for creating your first system account:
# 1. Create system account
ipa sysaccount-add my-first-app \
--desc="My first application" \
--random
# Save the displayed password securely!
# 2. Create role and privilege
ipa privilege-add 'App Read Privilege'
ipa privilege-add-permission 'App Read Privilege' \
--permissions='System: Read Users'
ipa role-add 'App Reader Role'
ipa role-add-privilege 'App Reader Role' \
--privileges='App Read Privilege'
# 3. Assign system account to role
ipa role-add-member 'App Reader Role' \
--sysaccounts=my-first-app
# 4. Test LDAP bind
ldapwhoami -x -H ldaps://ipa.example.com \
-D "uid=my-first-app,cn=sysaccounts,cn=etc,dc=example,dc=com" \
-W
# 5. Test search
ldapsearch -x -H ldaps://ipa.example.com \
-D "uid=my-first-app,cn=sysaccounts,cn=etc,dc=example,dc=com" \
-W \
-b "cn=users,cn=accounts,dc=example,dc=com" \
"(uid=admin)"
Conclusion
System accounts provide a secure, purpose-built solution for application authentication in FreeIPA environments. By separating service authentication from user accounts and integrating with FreeIPA’s RBAC system, they enable secure application integration while maintaining security and auditability.
Key benefits:
- Purpose-built for application authentication
- No POSIX overhead for non-login services
- Granular permission control via RBAC
- Privileged password management capabilities
- Clear separation from user accounts
- Full audit trail of operations
Start using system accounts today to improve security and simplify application integration with your FreeIPA infrastructure!