Why OpenSSH in Cygwin Creates cyg_server and sshd Accounts: Privilege Separation Explained


2 views

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:

  1. The main SSH daemon (running as cyg_server) binds to port 22
  2. After authentication, spawns unprivileged processes as sshd
  3. 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 {} \;