Enterprise Deployment Guide for Kleidia Agent (macOS)#
Download#
| Package | Description | Download |
|---|---|---|
| kleidia-agent-<version>.pkg | Signed and notarized macOS installer | GitHub Releases |
Always download installers from the official Kleidia GitHub Releases page. The PKG is signed with an Apple Developer ID and notarized for Gatekeeper compatibility.
Overview#
This guide covers deploying Kleidia Agent across macOS enterprise environments using MDM platforms and central management tools. The agent is distributed as a signed and notarized .pkg package suitable for all macOS deployment scenarios.
Related documentation:
- Installers Overview — Download links and quick installation
- Agent Reference — Configuration options and CLI reference
- Troubleshooting — Common issues and solutions
Package Contents#
After building with build-pkg.sh, you get:
kleidia-agent-<version>.pkg- Signed and notarized macOS installer package
The package includes:
- Kleidia Agent binary (
/usr/local/bin/kleidia-agent) - LaunchDaemon plist (
/Library/LaunchDaemons/com.kleidia.agent.plist) - Configuration directory (
/etc/kleidia/agent/) - Uninstall script (
/usr/local/bin/kleidia-agent-uninstall.sh) - Embedded YubiKey Manager package (optional, downloaded during build)
Deployment Methods#
1. Local Installation (End-Users)#
Prerequisites#
- macOS 10.15 (Catalina) or later
- Administrator privileges
- YubiKey Manager (ykman) installed or will be installed automatically
Step 1: Download and Open Package#
- Download
kleidia-agent-<version>.pkg - Double-click the package file
- macOS may show a security warning (if not notarized)
Step 2: Install Package#
- Click Continue through the installer
- Enter administrator password when prompted
- Installation will:
- Copy agent binary to
/usr/local/bin/ - Install LaunchDaemon for auto-start
- Create configuration directory
- Prompt for backend URL (interactive dialog)
- Copy agent binary to
Step 3: Configure Backend URL#
During installation, a dialog will appear:
Enter your Kleidia server domain (e.g., kleidia.example.com)
Do NOT include https:// — we will add it for you.Enter your backend domain, for example:
kleidia.example.comyubikeys.company.com
The installer will:
- Add
https://automatically - Configure
allowed_originsin/etc/kleidia/agent/agent.toml - Start the agent service
Step 4: Verify Installation#
# Check if service is running
sudo launchctl list | grep com.kleidia.agent
# Check agent status
/usr/local/bin/kleidia-agent --version
# View configuration
cat /etc/kleidia/agent/agent.toml
# Check local listener
curl http://127.0.0.1:56123/healthSilent Installation (Command Line)#
For scripted installations without GUI prompts:
# Set backend URL via environment variable
export BACKEND_URL="kleidia.example.com"
# Install package silently
sudo installer -pkg kleidia-agent-0.4.6.pkg -target /
# Verify
sudo launchctl list | grep com.kleidia.agent2. Microsoft Intune / Endpoint Manager Deployment#
Prerequisites#
- Microsoft Intune subscription with macOS support
- Signed and notarized
.pkgfile - Devices enrolled in Intune
Step 1: Prepare the Package#
Obtain signed .pkg:
- Build locally with signing certificates
- Or download from GitHub release
Create Configuration Profile (optional but recommended):
Create a Custom Settings profile to pre-configure agent.toml:
Profile XML: com.kleidia.agent.mobileconfig
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>PayloadContent</key>
<array>
<dict>
<key>PayloadDescription</key>
<string>Configures Kleidia Agent backend URL</string>
<key>PayloadDisplayName</key>
<string>Kleidia Agent Configuration</string>
<key>PayloadIdentifier</key>
<string>com.kleidia.agent.config</string>
<key>PayloadOrganization</key>
<string>Your Organization</string>
<key>PayloadType</key>
<string>Configuration</string>
<key>PayloadUUID</key>
<string>GENERATE-UUID-HERE</string>
<key>PayloadVersion</key>
<integer>1</integer>
<key>PayloadEnabled</key>
<true/>
<key>PayloadScope</key>
<string>System</string>
<key>TargetDeviceType</key>
<integer>5</integer>
</dict>
</array>
<key>PayloadDescription</key>
<string>Kleidia Agent Settings</string>
<key>PayloadDisplayName</key>
<string>Kleidia Agent</string>
<key>PayloadIdentifier</key>
<string>com.kleidia.agent</string>
<key>PayloadOrganization</key>
<string>Your Organization</string>
<key>PayloadScope</key>
<string>System</string>
<key>PayloadType</key>
<string>Configuration</string>
<key>PayloadUUID</key>
<string>GENERATE-ANOTHER-UUID</string>
<key>PayloadVersion</key>
<integer>1</integer>
</dict>
</plist>Or use a LaunchAgent script to write configuration:
#!/bin/bash
# deploy-config.sh - Deploy via Intune script
BACKEND_URL="https://kleidia.example.com"
CONFIG_FILE="/etc/kleidia/agent/agent.toml"
if [ -f "$CONFIG_FILE" ]; then
# Update existing config
sed -i '' "s|^backend_url.*|backend_url = \"$BACKEND_URL\"|" "$CONFIG_FILE"
# Restart agent
sudo launchctl kickstart -k system/com.kleidia.agent
fiStep 2: Upload to Intune#
Sign in to Microsoft Endpoint Manager admin center:
- Navigate to: https://endpoint.microsoft.com
Create a new macOS app:
- Go to Apps → macOS → Add → macOS app (PKG)
- Click Select app package file
- Upload
kleidia-agent-<version>.pkg
Configure app information:
- Name: Kleidia Agent
- Description: YubiKey management agent for enterprise macOS
- Publisher: Kleidia
- Category: Productivity
- Display as featured app: Optional
- Information URL: Your documentation URL
- Privacy URL: Optional
- Developer: Kleidia
- Owner: IT Department
Configure app settings:
- Minimum operating system: macOS 10.15
- Ignore app version: No (recommended)
Configure deployment settings:
- Install as managed: Yes
- Uninstall on device removal: Optional (choose based on policy)
Configure detection rules (optional):
Use a shell script to detect installation:
#!/bin/bash # Check if agent binary exists and is running if [ -f "/usr/local/bin/kleidia-agent" ]; then if launchctl list | grep -q com.kleidia.agent; then echo "Installed" exit 0 fi fi exit 1Assign to groups:
- Select target device groups
- Choose deployment intent: Required or Available
- Set notifications: As desired
Deploy configuration profile (if created):
- Go to Devices → Configuration profiles → Create profile
- Platform: macOS
- Profile type: Templates → Custom
- Upload your
.mobileconfigfile - Assign to same groups as the app
Monitor deployment:
- Go to Apps → Kleidia Agent → Device install status
- Check for installation success/failures
Step 3: Pre-Configuration via Intune Script#
Alternatively, deploy configuration via Intune Shell Script:
- Create shell script (
configure-kleidia.sh):
#!/bin/bash
# Intune post-install configuration script for Kleidia Agent
BACKEND_URL="https://kleidia.example.com"
CONFIG_DIR="/etc/kleidia/agent"
CONFIG_FILE="${CONFIG_DIR}/agent.toml"
# Wait for installation to complete
sleep 5
if [ ! -f "$CONFIG_FILE" ]; then
echo "Config file not found, creating..."
mkdir -p "$CONFIG_DIR"
cat > "$CONFIG_FILE" <<EOF
port = 56123
name = "Kleidia Agent"
backend_url = "$BACKEND_URL"
allowed_origins = [
"$BACKEND_URL"
]
[logging]
level = "info"
EOF
chmod 0644 "$CONFIG_FILE"
chown root:wheel "$CONFIG_FILE"
else
# Update existing config
sed -i '' "s|^backend_url.*|backend_url = \"$BACKEND_URL\"|" "$CONFIG_FILE"
fi
# Restart agent if running
if launchctl list | grep -q com.kleidia.agent; then
launchctl kickstart -k system/com.kleidia.agent
fi
exit 0- Upload to Intune:
- Go to Devices → macOS → Shell scripts → Add
- Name: Configure Kleidia Agent
- Upload script file
- Run script as signed-in user: No
- Hide script notifications: Yes
- Script frequency: Once
- Max number of retries: 3
- Assign to device groups
Intune Deployment Notes#
- Installation time: Typically 10-15 minutes after check-in
- Detection: Service must be running for success
- Updates: Upload new version and assign with supersedence
- Reporting: Monitor via Intune device install status
- Troubleshooting: Check
/var/log/install.logon devices
3. Jamf Pro Deployment#
Prerequisites#
- Jamf Pro server
- Signed and notarized
.pkgfile - macOS devices enrolled in Jamf Pro
- Jamf Admin or direct package upload access
Step 1: Upload Package to Jamf Pro#
Option A: Via Jamf Admin Application#
- Open Jamf Admin
- Connect to your Jamf Pro server
- Drag and drop
kleidia-agent-<version>.pkginto the Packages list - Configure package settings:
- Display Name: Kleidia Agent
- Category: Productivity or Security
- Priority: 10 (default)
- Install if reported available: Optional
- Fill user template: No
- Fill existing users: No
- Reboot required: No
- Save package to distribution point
Option B: Via Jamf Pro Web Interface#
- Sign in to Jamf Pro
- Navigate to: Settings → Computer Management → Packages
- Click New
- Upload package:
- Click Choose and select
kleidia-agent-<version>.pkg - Display Name: Kleidia Agent
- Category: Productivity
- Priority: 10
- Fill user template: Unchecked
- Fill existing users: Unchecked
- Install if reported available: Optional
- Click Choose and select
- Save
Step 2: Create Configuration Profile (Recommended)#
Create a Configuration Profile to pre-configure the backend URL:
Navigate to: Computers → Configuration Profiles → New
General:
- Display Name: Kleidia Agent Configuration
- Description: Configures backend URL for Kleidia Agent
- Category: Security
- Level: Computer Level
- Distribution Method: Install Automatically
Add Custom Settings Payload:
- Click Configure next to Custom Settings
- Preference Domain:
com.kleidia.agent - Click Upload PLIST file or Configure manually
Custom Settings PLIST:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>backend_url</key>
<string>https://kleidia.example.com</string>
<key>backend_host</key>
<string>kleidia.example.com</string>
</dict>
</plist>Scope:
- Targets: Select Smart Group or Static Group
- Exclusions: None (unless needed)
Save
Step 3: Create Policy for Installation#
Navigate to: Computers → Policies → New
General:
- Display Name: Install Kleidia Agent
- Enabled: Checked
- Category: Productivity
- Trigger:
- ☑ Recurring Check-in
- ☑ Enrollment Complete (for new devices)
- ☐ Login (optional)
- ☐ Check-in (optional)
- Execution Frequency: Once per computer
Packages:
- Click Configure
- Click Add next to Packages
- Select Kleidia Agent
- Action: Install
- Click Save
Files and Processes (for configuration):
- Click Configure
- Execute Command: Add this script:
#!/bin/bash
BACKEND_URL="https://kleidia.example.com"
CONFIG_FILE="/etc/kleidia/agent/agent.toml"
# Wait for package installation
sleep 10
if [ -f "$CONFIG_FILE" ]; then
# Update backend URL
/usr/bin/sed -i '' "s|^backend_url.*|backend_url = \"$BACKEND_URL\"|" "$CONFIG_FILE"
# Update allowed_origins
ORIGIN=$(echo "$BACKEND_URL" | /usr/bin/awk -F/ '{print $1"//"$3}')
/usr/bin/awk -v origin="$ORIGIN" '
/^allowed_origins/ {
print "allowed_origins = [";
print " \"" origin "\"";
print "]";
in_array=1;
next;
}
in_array==1 && /^\]/ { in_array=0; next; }
in_array==0 { print; }
' "$CONFIG_FILE" > "$CONFIG_FILE.tmp" && mv "$CONFIG_FILE.tmp" "$CONFIG_FILE"
# Restart agent
/bin/launchctl kickstart -k system/com.kleidia.agent
fiScope:
- Targets: Select Smart Group or Static Group
- Example Smart Group criteria:
- Operating System Version greater than or equal to 10.15
- AND Application Title does not have Kleidia Agent
Self Service (optional):
- Enable for Self Service
- Display Name: Install Kleidia Agent
- Description: Installs YubiKey management agent
- Icon: Upload icon (optional)
Save
Step 4: Create Extension Attribute for Monitoring#
Monitor agent installation status:
Navigate to: Settings → Computer Management → Extension Attributes → New
General:
- Display Name: Kleidia Agent Status
- Description: Reports Kleidia Agent installation and running status
- Data Type: String
- Inventory Display: General
Input Type: Script
Script:
#!/bin/bash
AGENT_BIN="/usr/local/bin/kleidia-agent"
RESULT="Not Installed"
if [ -f "$AGENT_BIN" ]; then
VERSION=$("$AGENT_BIN" --version 2>/dev/null | grep -o 'v[0-9]\+\.[0-9]\+\.[0-9]\+' || echo "unknown")
if /bin/launchctl list | grep -q com.kleidia.agent; then
RESULT="Installed and Running ($VERSION)"
else
RESULT="Installed but Not Running ($VERSION)"
fi
fi
echo "<result>$RESULT</result>"- Save
Step 5: Create Smart Group for Monitoring#
Navigate to: Computers → Smart Computer Groups → New
General:
- Display Name: Kleidia Agent - Installed
- Criteria:
- Kleidia Agent Status contains Installed
Save
Create additional Smart Groups:
- Kleidia Agent - Not Running: Status contains “Not Running”
- Kleidia Agent - Not Installed: Status is “Not Installed”
Step 6: Advanced Configuration with Scripts#
For more complex deployments, use a Jamf Policy with a full configuration script:
#!/bin/bash
# Jamf Pro deployment script for Kleidia Agent
# Parameters (configured in Jamf):
# $4 = Backend URL (e.g., https://kleidia.example.com)
# $5 = Log level (optional, default: info)
BACKEND_URL="${4:-https://kleidia.example.com}"
LOG_LEVEL="${5:-info}"
CONFIG_DIR="/etc/kleidia/agent"
CONFIG_FILE="${CONFIG_DIR}/agent.toml"
LOG_FILE="/var/log/kleidia-agent/jamf-deployment.log"
# Logging function
log_message() {
echo "$(date '+%Y-%m-%d %H:%M:%S') - $1" | tee -a "$LOG_FILE"
}
log_message "Starting Kleidia Agent configuration"
log_message "Backend URL: $BACKEND_URL"
# Wait for package installation
COUNTER=0
while [ ! -f "$CONFIG_FILE" ] && [ $COUNTER -lt 30 ]; do
sleep 2
((COUNTER++))
done
if [ ! -f "$CONFIG_FILE" ]; then
log_message "ERROR: Config file not found after waiting"
exit 1
fi
# Extract origin from backend URL
ORIGIN=$(echo "$BACKEND_URL" | awk -F/ '{print $1"//"$3}')
# Create optimized configuration
cat > "$CONFIG_FILE" <<EOF
port = 56123
name = "Kleidia Agent"
backend_url = "$BACKEND_URL"
allowed_origins = [
"$ORIGIN"
]
[logging]
level = "$LOG_LEVEL"
EOF
# Set permissions
chmod 0644 "$CONFIG_FILE"
chown root:wheel "$CONFIG_FILE"
log_message "Configuration written successfully"
# Verify agent binary
if [ ! -f "/usr/local/bin/kleidia-agent" ]; then
log_message "ERROR: Agent binary not found"
exit 1
fi
# Check if LaunchDaemon is loaded
if /bin/launchctl list | grep -q com.kleidia.agent; then
log_message "Agent is running, restarting..."
/bin/launchctl kickstart -k system/com.kleidia.agent
else
log_message "Agent not loaded, bootstrapping..."
/bin/launchctl bootstrap system /Library/LaunchDaemons/com.kleidia.agent.plist
/bin/launchctl enable system/com.kleidia.agent
/bin/launchctl kickstart system/com.kleidia.agent
fi
# Verify agent is running
sleep 3
if /bin/launchctl list | grep -q com.kleidia.agent; then
log_message "Agent deployed successfully"
exit 0
else
log_message "ERROR: Agent failed to start"
exit 1
fiTo use this script in Jamf:
- Navigate to: Settings → Computer Management → Scripts → New
- Upload script or paste content
- Configure Parameter Labels:
- Parameter 4 Label: Backend URL
- Parameter 5 Label: Log Level
- Save
- Add script to Policy (Files and Processes → Scripts)
- Set parameters when adding to policy
Jamf Pro Deployment Notes#
- Execution: Policies run at check-in (typically every 15 minutes)
- Enrollment: New devices get agent automatically if enrollment trigger enabled
- Self Service: Users can install on-demand if enabled
- Updates: Create new policy with new package version
- Monitoring: Use Extension Attributes and Smart Groups
- Logging: Check
/var/log/install.logand/var/log/kleidia-agent/
4. Munki Deployment#
Prerequisites#
- Munki repository configured
munkiimportcommand-line tool- Signed
.pkgfile
Step 1: Import Package to Munki#
# Import package
munkiimport kleidia-agent-0.4.6.pkg
# During import, configure:
# - Name: KleidiaAgent
# - Display name: Kleidia Agent
# - Description: YubiKey management agent
# - Category: Productivity
# - Developer: Kleidia
# - Requires: (optional) YubiKeyManagerStep 2: Create pkginfo with Scripts#
Edit the pkginfo file to add post-install configuration:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>autoremove</key>
<false/>
<key>catalogs</key>
<array>
<string>production</string>
</array>
<key>category</key>
<string>Productivity</string>
<key>description</key>
<string>YubiKey management agent for enterprise environments</string>
<key>display_name</key>
<string>Kleidia Agent</string>
<key>installcheck_script</key>
<string>#!/bin/bash
if [ -f "/usr/local/bin/kleidia-agent" ]; then
if /bin/launchctl list | grep -q com.kleidia.agent; then
exit 1
fi
fi
exit 0
</string>
<key>postinstall_script</key>
<string>#!/bin/bash
BACKEND_URL="https://kleidia.example.com"
CONFIG_FILE="/etc/kleidia/agent/agent.toml"
if [ -f "$CONFIG_FILE" ]; then
sed -i '' "s|^backend_url.*|backend_url = \"$BACKEND_URL\"|" "$CONFIG_FILE"
/bin/launchctl kickstart -k system/com.kleidia.agent
fi
exit 0
</string>
<key>minimum_os_version</key>
<string>10.15.0</string>
<key>name</key>
<string>KleidiaAgent</string>
<key>unattended_install</key>
<true/>
<key>version</key>
<string>0.4.6</string>
</dict>
</plist>Step 3: Add to Manifests#
# Add to production catalog
manifestutil add-pkg KleidiaAgent --manifest production
# Or add to specific client manifests
manifestutil add-pkg KleidiaAgent --manifest site_defaultMunki Deployment Notes#
- Installation: Automatic on next Munki run
- Updates: Import new version with higher version number
- Removal: Set
autoremovetotruein pkginfo - Reporting: Use MunkiReport or Munki Admin
Configuration Management#
agent.toml Structure#
# Local listener port
port = 56123
# Agent name
name = "Kleidia Agent"
# Backend server URL (required)
backend_url = "https://kleidia.example.com"
# Allowed CORS origins (typically same as backend)
allowed_origins = [
"https://kleidia.example.com"
]
# Logging configuration
[logging]
level = "info" # debug, info, warn, error
# TLS settings (optional, for client certificates)
[tls]
# client_cert = "/etc/kleidia/agent/client.crt"
# client_key = "/etc/kleidia/agent/client.key"
# ca_cert = "/etc/kleidia/agent/ca.crt"Centralized Configuration Methods#
Option 1: Pre-Deploy via Package#
Build package with custom agent.toml.example:
# Modify example before building
cd go-agent-http/packaging/macos/payload/etc/kleidia/agent
vi agent.toml.example
# Set your backend_url
# Build package
cd ../../../../../
./build-pkg.shOption 2: MDM Configuration Profile#
Deploy via Intune or Jamf Configuration Profile (see MDM sections above).
Option 3: Post-Install Script#
Deploy configuration via MDM script after installation (see MDM sections above).
Option 4: Configuration Management Tools#
Ansible:
- name: Deploy Kleidia Agent configuration
template:
src: agent.toml.j2
dest: /etc/kleidia/agent/agent.toml
owner: root
group: wheel
mode: '0644'
- name: Restart Kleidia Agent
command: launchctl kickstart -k system/com.kleidia.agentPuppet:
file { '/etc/kleidia/agent/agent.toml':
ensure => file,
owner => 'root',
group => 'wheel',
mode => '0644',
content => template('kleidia/agent.toml.erb'),
notify => Exec['restart-kleidia-agent'],
}
exec { 'restart-kleidia-agent':
command => '/bin/launchctl kickstart -k system/com.kleidia.agent',
refreshonly => true,
}Chef:
template '/etc/kleidia/agent/agent.toml' do
source 'agent.toml.erb'
owner 'root'
group 'wheel'
mode '0644'
notifies :run, 'execute[restart-kleidia-agent]'
end
execute 'restart-kleidia-agent' do
command '/bin/launchctl kickstart -k system/com.kleidia.agent'
action :nothing
endVerification and Monitoring#
Verify Installation#
# Check if agent binary exists
ls -l /usr/local/bin/kleidia-agent
# Check agent version
/usr/local/bin/kleidia-agent --version
# Check if LaunchDaemon is loaded
sudo launchctl list | grep com.kleidia.agent
# Check LaunchDaemon status
sudo launchctl print system/com.kleidia.agent
# Check configuration
cat /etc/kleidia/agent/agent.toml
# Test local listener
curl http://127.0.0.1:56123/health
# Check process
ps aux | grep kleidia-agentView Logs#
# Installation logs
cat /var/log/kleidia-agent/postinstall.log
# System install log
grep kleidia /var/log/install.log
# Agent logs (if configured)
tail -f /var/log/kleidia-agent/agent.log
# LaunchDaemon stdout/stderr
tail -f /var/log/kleidia-agent/stdout.log
tail -f /var/log/kleidia-agent/stderr.log
# System logs
log show --predicate 'process == "kleidia-agent"' --last 1hHealth Check Script#
#!/bin/bash
# health-check.sh - Verify Kleidia Agent health
AGENT_BIN="/usr/local/bin/kleidia-agent"
CONFIG_FILE="/etc/kleidia/agent/agent.toml"
RESULTS=()
# Check binary exists
if [ -f "$AGENT_BIN" ]; then
VERSION=$("$AGENT_BIN" --version 2>/dev/null | grep -o 'v[0-9.]\+' || echo "unknown")
RESULTS+=("✅ Binary installed: $VERSION")
else
RESULTS+=("❌ Binary not found")
echo "${RESULTS[@]}" && exit 1
fi
# Check configuration exists
if [ -f "$CONFIG_FILE" ]; then
BACKEND_URL=$(grep "^backend_url" "$CONFIG_FILE" | cut -d '"' -f 2)
RESULTS+=("✅ Config exists: $BACKEND_URL")
else
RESULTS+=("❌ Config not found")
fi
# Check LaunchDaemon loaded
if launchctl list | grep -q com.kleidia.agent; then
RESULTS+=("✅ LaunchDaemon loaded")
else
RESULTS+=("❌ LaunchDaemon not loaded")
echo "${RESULTS[@]}" && exit 1
fi
# Check process running
if pgrep -x kleidia-agent > /dev/null; then
PID=$(pgrep -x kleidia-agent)
RESULTS+=("✅ Process running (PID: $PID)")
else
RESULTS+=("❌ Process not running")
echo "${RESULTS[@]}" && exit 1
fi
# Check local listener
if curl -s -f http://127.0.0.1:56123/health > /dev/null; then
RESULTS+=("✅ Local listener responding")
else
RESULTS+=("⚠️ Local listener not responding")
fi
# Print results
printf '%s\n' "${RESULTS[@]}"
# Exit code
[[ "${RESULTS[@]}" =~ "❌" ]] && exit 1 || exit 0Troubleshooting#
Common Issues#
Service won’t start#
# Check LaunchDaemon status
sudo launchctl print system/com.kleidia.agent
# Check for errors
tail -50 /var/log/kleidia-agent/stderr.log
# Try manual start
sudo launchctl kickstart system/com.kleidia.agent
# Check permissions
ls -l /usr/local/bin/kleidia-agent
ls -l /Library/LaunchDaemons/com.kleidia.agent.plistConfiguration not applied#
# Verify file exists
cat /etc/kleidia/agent/agent.toml
# Check permissions
ls -l /etc/kleidia/agent/agent.toml
# Validate TOML syntax
# (No built-in validator, but agent will log errors on start)
# Restart service
sudo launchctl kickstart -k system/com.kleidia.agentCannot connect to backend#
# Test connectivity
nc -zv kleidia.example.com 443
# Check DNS resolution
nslookup kleidia.example.com
# Test HTTPS
curl -v https://kleidia.example.com
# Check backend URL in config
grep backend_url /etc/kleidia/agent/agent.toml
# Review agent logs for connection errors
tail -100 /var/log/kleidia-agent/stderr.log | grep -i connectionYubiKey not detected#
# Check if ykman is installed
which ykman
ykman --version
# Test YubiKey detection
ykman list
# Check system report
system_profiler SPUSBDataType | grep -A 10 YubicoUninstall and Reinstall#
# Stop and unload service
sudo launchctl bootout system/com.kleidia.agent
# Run uninstall script
sudo /usr/local/bin/kleidia-agent-uninstall.sh
# Or manual removal
sudo rm -f /usr/local/bin/kleidia-agent
sudo rm -f /Library/LaunchDaemons/com.kleidia.agent.plist
sudo rm -rf /etc/kleidia/agent
sudo rm -rf /var/log/kleidia-agent
# Reinstall
sudo installer -pkg kleidia-agent-0.4.6.pkg -target /Security Considerations#
File Permissions#
The package installer sets secure permissions:
/usr/local/bin/kleidia-agent:root:wheel,0755/etc/kleidia/agent/:root:wheel,0755/etc/kleidia/agent/agent.toml:root:wheel,0644/Library/LaunchDaemons/com.kleidia.agent.plist:root:wheel,0644
Service Account#
The LaunchDaemon runs as root (required for YubiKey access via USB).
Network Security#
- Agent communicates with backend over HTTPS (TLS 1.2+)
- Local listener (127.0.0.1:56123) bound to localhost only
- No inbound connections required
Code Signing and Notarization#
For enterprise deployment:
- Sign the agent binary with Developer ID Application certificate
- Sign the installer package with Developer ID Installer certificate
- Notarize the package with Apple notary service
- Staple the notarization ticket to the package
See: SIGNING_GUIDE.md and NOTARIZATION_GUIDE.md
Deployment Checklist#
Pre-Deployment#
- Build or obtain signed
.pkgpackage - Verify code signing and notarization
- Prepare
agent.tomlwith backend URL - Test installation on a single Mac
- Verify service starts and connects
- Document configuration settings
Deployment#
- Choose deployment method (Intune/Jamf/Munki/Manual)
- Prepare MDM policies/profiles or scripts
- Deploy to pilot group (5-10 devices)
- Monitor installation success rate
- Verify agent connectivity to backend
- Check for issues in logs
Post-Deployment#
- Monitor device check-ins in backend
- Set up alerts for failed installations
- Document any issues and resolutions
- Deploy to production groups
- Train support team on troubleshooting
- Schedule periodic health checks
Updates and Maintenance#
Updating the Agent#
Via Intune#
- Upload new package version to Intune
- Configure as superseding update
- Deploy to device groups
- Monitor rollout
Via Jamf Pro#
- Upload new package to Jamf Pro
- Update policy with new package
- Force policy execution or wait for check-in
- Monitor via Extension Attribute
Via Munki#
- Import new package:
munkiimport kleidia-agent-0.4.7.pkg - Package automatically supersedes old version
- Munki handles upgrade on next run
Configuration Updates#
To update configuration without reinstalling:
# Update backend URL
sudo sed -i '' 's|backend_url = ".*"|backend_url = "https://new-server.example.com"|' /etc/kleidia/agent/agent.toml
# Restart agent
sudo launchctl kickstart -k system/com.kleidia.agentOr deploy via MDM script/profile.
Best Practices#
- Test First: Always test on pilot group before mass deployment
- Use MDM: Leverage Intune or Jamf for centralized management
- Pre-Configure: Deploy configuration via MDM profiles or scripts
- Monitor Health: Use Extension Attributes (Jamf) or compliance policies (Intune)
- Keep Updated: Subscribe to Kleidia releases for security updates
- Document Process: Maintain deployment runbooks for your organization
- Train Support: Ensure help desk can troubleshoot common issues
- Backup Config: Store configuration templates in version control
- Review Logs: Regularly check deployment and agent logs
- Plan Rollback: Have procedure to revert to previous version if needed
Support and Resources#
Documentation#
- SIGNING_GUIDE.md - Code signing instructions
- NOTARIZATION_GUIDE.md - Apple notarization process
- agent.toml.example - Configuration file example
- GitHub Issues: https://github.com/kleidia/kleidia-docs/issues
Logs and Diagnostics#
- Installation:
/var/log/kleidia-agent/postinstall.log - System install:
/var/log/install.log - Agent logs:
/var/log/kleidia-agent/ - LaunchDaemon:
launchctl print system/com.kleidia.agent
Common Commands#
# Status
sudo launchctl list | grep kleidia
# Start
sudo launchctl kickstart system/com.kleidia.agent
# Stop
sudo launchctl kill SIGTERM system/com.kleidia.agent
# Restart
sudo launchctl kickstart -k system/com.kleidia.agent
# Unload
sudo launchctl bootout system/com.kleidia.agent
# Load
sudo launchctl bootstrap system /Library/LaunchDaemons/com.kleidia.agent.plist
# Logs
tail -f /var/log/kleidia-agent/stderr.log
# Version
/usr/local/bin/kleidia-agent --versionDocument Version: 1.0
Last Updated: 2025-11-10
Agent Version: 0.4.6+
Platforms: macOS 10.15 (Catalina) and later