When configuring OpenSSH via ssh-host-config
on Cygwin/Windows, two service accounts are created due to security requirements:
1. cyg_server - Privileged account for SSH daemon operation
2. sshd - Non-privileged account for privilege separation
Modern OpenSSH (since v3.3) implements privilege separation as security best practice. The workflow:
- The main SSH daemon (running as
cyg_server
) binds to port 22 - After authentication, spawns unprivileged processes as
sshd
- Critical operations stay privileged while user sessions run restricted
Key configuration elements in /etc/sshd_config
:
# Privilege separation configuration
UsePrivilegeSeparation yes
ChrootDirectory /var/empty
PidFile /var/run/sshd.pid
The automatic password generation follows Windows security policies:
# To check password settings for sshd account:
wmic useraccount where name='sshd' get PasswordExpires
net user sshd | find "Password expires"
# To modify expiration (admin required):
net accounts /MAXPWAGE:unlimited
wmic useraccount where name='sshd' set PasswordExpires=FALSE
For production systems, consider these adjustments:
# Recommended post-install steps:
1. Set strong passwords for both accounts
2. Disable interactive logins:
net user cyg_server /active:no
net user sshd /active:no
3. Verify service account permissions:
icacls C:\cygwin64\var\empty /grant sshd:(RX)
icacls C:\cygwin64\home /grant cyg_server:(RX)
When encountering permission problems:
# Debug steps:
cygrunsrv -V -S sshd
/usr/sbin/sshd -d -p 2222
cat /var/log/sshd.log
# Critical permission checks:
ls -l /var/empty
getfacl ~/.ssh/authorized_keys
Remember that both accounts are system-level entities - never use them for regular login sessions. The separation exists specifically to contain potential security breaches.
When running ssh-host-config
on Windows 8.1 with Cygwin, the script creates two distinct accounts:
1. cyg_server - Privileged account for service control
2. sshd - Non-privileged account for privilege separation
The architecture follows OpenSSH's security model:
# From /usr/share/doc/openssh/README.privsep
Privilege separation:
- Parent process (root privileges)
- Child process (sshd user privileges)
- Network communication channels between them
The accounts have different Windows configurations:
# Check account status via WMIC
wmic useraccount where "Name='cyg_server' or Name='sshd'" get Name,Disabled,PasswordExpires
# Output typically shows:
Name Disabled PasswordExpires
cyg_server FALSE FALSE
sshd TRUE TRUE
The automatic password handling can be problematic:
# To modify password expiration for sshd account:
net user sshd /passwordchg:no /expires:never
# Or via PowerShell:
Set-LocalUser -Name sshd -PasswordNeverExpires $true
For simplified administration, you can:
# 1. Remove default accounts
net user cyg_server /delete
net user sshd /delete
# 2. Create custom account
$password = ConvertTo-SecureString "YourPassword" -AsPlainText -Force
New-LocalUser -Name "cygwin_sshd" -Password $password -PasswordNeverExpires -AccountNeverExpires
# 3. Modify sshd_config
sed -i 's/^PrivilegeSeparation.*/PrivilegeSeparation no/' /etc/sshd_config
After account changes, update the service:
# Stop and reconfigure the service
cygrunsrv --stop sshd
cygrunsrv --edit sshd --user cygwin_sshd --passwd "YourPassword"
# Verify service account
sc qc sshd | find "SERVICE_START_NAME"
When modifying the default setup:
- Ensure proper file permissions in /var/empty
- Maintain strict control over authorized_keys files
- Regularly audit service account privileges
# Example permission check
find /home -name authorized_keys -exec ls -la {} \;