Files
Invoke-OpenSSHConfiguration/README.md
T
GraceSolutions e566ab15f1 Automatic service management and Windows Firewall rules
- Service auto-start and start now happen automatically (no switches)
- Windows Firewall rules created automatically per profile (Domain, Private, Public)
- Dynamic profile enumeration using [Microsoft.PowerShell.Cmdletization.GeneratedTypes.NetSecurity.Profile]
- Added -SSHPort parameter for custom port (default: 22)
- Idempotent firewall rule creation with update support
- Removed -EnableService and -StartService switches (now automatic)
2026-05-01 15:21:54 -04:00

277 lines
11 KiB
Markdown

# Invoke-OpenSSHConfiguration
A PowerShell toolkit for automated installation and configuration of OpenSSH on Windows systems. Provides idempotent configuration of SSH server settings, public key authentication, certificate-based authentication using Windows certificate stores, and key pair generation.
## Features
- **Automated Installation**: Downloads and installs the latest Win32-OpenSSH MSI from GitHub, with dynamic OS architecture detection
- **Public Key Authentication**: Idempotently manages `administrators_authorized_keys` with deduplication
- **Certificate Authentication**: Exports Windows Root and Intermediate CA certificates to PEM format for OpenSSH trust
- **Key Pair Generation**: Creates SSH host keys with configurable algorithm and key size
- **Configuration Management**: Idempotently modifies `sshd_config` with proper encoding (ASCII, no BOM)
- **Elevation Handling**: Automatically re-launches with elevated privileges when required
## Requirements
- Windows 10/11 or Windows Server 2016+
- PowerShell 5.1 or later
- Administrator privileges
- Internet connectivity (for initial OpenSSH download)
## Installation
Clone the repository and run the script directly:
```powershell
git clone https://github.com/yourusername/Invoke-OpenSSHConfiguration.git
cd Invoke-OpenSSHConfiguration
.\Invoke-OpenSSHConfiguration.ps1 -Mode Server
```
## Parameters
| Parameter | Type | Description |
|-----------|------|-------------|
| `-Mode` | String | Installation mode: `Client` or `Server` |
| `-PublicKeyList` | String[] | Array of public keys to add to `administrators_authorized_keys` |
| `-GenerateKeyPair` | Switch | Generate SSH host key pair |
| `-KeyType` | String | Key algorithm: `rsa`, `ecdsa`, `ed25519` (default: `ed25519`) |
| `-KeyBits` | Int | Key size: 256, 384, 521 (ECDSA) or 2048, 3072, 4096 (RSA) |
| `-EnablePubkeyAuthentication` | Switch | Enable `PubkeyAuthentication yes` in sshd_config |
| `-DisablePasswordAuthentication` | Switch | Disable password authentication (`PasswordAuthentication no`) |
| `-EnableCertificateAuthentication` | Switch | Configure `TrustedUserCAKeys` for certificate auth |
| `-TrustWindowsCertificateAuthorities` | Switch | Export Windows CA certificates to PEM bundle |
| `-CAInclusionExpression` | String | Regex to filter CAs by Subject or Thumbprint (include matches) |
| `-CAExclusionExpression` | String | Regex to filter CAs by Subject or Thumbprint (exclude matches) |
| `-SFTPSubsystemPath` | String | Custom SFTP server path (default: `sftp-server.exe`, configured automatically) |
| `-SSHPort` | Int | SSH port number (default: `22`, used for firewall rules) |
| `-LogDirectory` | DirectoryInfo | Custom log directory path |
| `-ContinueOnError` | Switch | Continue execution on non-fatal errors |
## Usage Examples
### Basic Server Installation
```powershell
.\Invoke-OpenSSHConfiguration.ps1 -Mode Server
```
### Server with Public Key Authentication
```powershell
$PublicKeys = @(
'ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIExample1... user1@host',
'ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIExample2... user2@host'
)
.\Invoke-OpenSSHConfiguration.ps1 -Mode Server `
-PublicKeyList $PublicKeys `
-EnablePubkeyAuthentication
```
### Server with Certificate Authentication (Windows CA Trust)
```powershell
.\Invoke-OpenSSHConfiguration.ps1 -Mode Server `
-TrustWindowsCertificateAuthorities `
-EnableCertificateAuthentication `
-EnablePubkeyAuthentication
```
This exports all unexpired Root and Intermediate CA certificates from the Windows certificate store to `C:\ProgramData\ssh\OpenSSH-TrustedCertificateAuthorities-LocalMachine.pem` and configures sshd to trust them.
### Generate Host Keys
```powershell
# Generate Ed25519 key (recommended)
.\Invoke-OpenSSHConfiguration.ps1 -Mode Server -GenerateKeyPair
# Generate RSA 4096-bit key
.\Invoke-OpenSSHConfiguration.ps1 -Mode Server -GenerateKeyPair -KeyType rsa -KeyBits 4096
# Generate ECDSA 384-bit key
.\Invoke-OpenSSHConfiguration.ps1 -Mode Server -GenerateKeyPair -KeyType ecdsa -KeyBits 384
```
### Full Server Configuration
```powershell
.\Invoke-OpenSSHConfiguration.ps1 -Mode Server `
-PublicKeyList @('ssh-ed25519 AAAAC3NzaC1lZDI1NTE5... admin@corp') `
-GenerateKeyPair `
-KeyType ed25519 `
-TrustWindowsCertificateAuthorities `
-EnableCertificateAuthentication `
-EnablePubkeyAuthentication `
-DisablePasswordAuthentication `
-LogDirectory 'C:\Logs\OpenSSH'
```
### Hardened Server (Keys Only, No Passwords)
```powershell
.\Invoke-OpenSSHConfiguration.ps1 -Mode Server `
-EnablePubkeyAuthentication `
-DisablePasswordAuthentication
```
### Selective CA Trust (Regex Filtering)
```powershell
# Only trust CAs with "Corp" or "Enterprise" in the subject
.\Invoke-OpenSSHConfiguration.ps1 -Mode Server `
-TrustWindowsCertificateAuthorities `
-CAInclusionExpression '(Corp|Enterprise)' `
-EnableCertificateAuthentication
# Trust all CAs except Microsoft root CAs
.\Invoke-OpenSSHConfiguration.ps1 -Mode Server `
-TrustWindowsCertificateAuthorities `
-CAExclusionExpression 'Microsoft' `
-EnableCertificateAuthentication
# Trust specific CA by thumbprint pattern
.\Invoke-OpenSSHConfiguration.ps1 -Mode Server `
-TrustWindowsCertificateAuthorities `
-CAInclusionExpression '^A1B2C3' `
-EnableCertificateAuthentication
```
### Custom SFTP Server Path
SFTP subsystem is configured automatically. To use a custom path:
```powershell
.\Invoke-OpenSSHConfiguration.ps1 -Mode Server `
-SFTPSubsystemPath 'C:\Program Files\OpenSSH\sftp-server.exe'
```
## File Locations
| File | Path | Description |
|------|------|-------------|
| sshd_config | `C:\ProgramData\ssh\sshd_config` | SSH server configuration |
| sshd_config.backup.* | `C:\ProgramData\ssh\sshd_config.backup.*` | Timestamped config backups |
| administrators_authorized_keys | `C:\ProgramData\ssh\administrators_authorized_keys` | Authorized keys for admin users |
| CA Bundle | `C:\ProgramData\ssh\OpenSSH-TrustedCertificateAuthorities-LocalMachine.pem` | Trusted CA certificates |
| Generated Keys | `C:\ProgramData\ssh\keys\` | Generated host key pairs |
| Logs | `%WINDIR%\Temp\Invoke-OpenSSHConfiguration\Logs\` | Script execution logs |
## Certificate Authentication
The script bridges Windows certificate trust to OpenSSH by exporting CA certificates:
1. Reads unexpired CA certificates from `Cert:\LocalMachine\Root` and `Cert:\LocalMachine\CA`
2. Applies optional inclusion/exclusion regex filters on Subject and Thumbprint
3. Filters for certificates with Basic Constraints CA flag
4. Exports to PEM format bundle
5. Configures `TrustedUserCAKeys` in sshd_config
**Important**: OpenSSH does NOT accept expired certificates. When CA certificates are renewed, re-run the script with `-TrustWindowsCertificateAuthorities` to update the PEM bundle.
### Periodic CA Refresh
For automated CA refresh, create a scheduled task:
```powershell
$Action = New-ScheduledTaskAction -Execute 'powershell.exe' -Argument '-ExecutionPolicy Bypass -File "C:\Scripts\Invoke-OpenSSHConfiguration.ps1" -TrustWindowsCertificateAuthorities'
$Trigger = New-ScheduledTaskTrigger -Daily -At '3:00AM'
$Principal = New-ScheduledTaskPrincipal -UserId 'SYSTEM' -LogonType ServiceAccount -RunLevel Highest
Register-ScheduledTask -TaskName 'OpenSSH-CA-Refresh' -Action $Action -Trigger $Trigger -Principal $Principal
```
## Toolkit Functions
The toolkit includes reusable functions in `Toolkit\Functions\`:
| Function | Description |
|----------|-------------|
| `ConvertFrom-CertificateToPEM` | Converts X.509 certificates to PEM format |
| `Get-GitRepositoryRelease` | Downloads releases from GitHub repositories |
| `Get-CurrentUser` | Retrieves current user session information |
| `Start-ProcessWithOutput` | Executes processes with output capture and logging |
| `Get-InstalledSoftware` | Queries installed software from registry |
| `Get-MSIPropertyList` | Reads MSI file properties |
## Known Limitations
### Current Gaps (Not Yet Implemented)
**Server Configuration**
- User/group restrictions (AllowUsers, AllowGroups)
- SSH banner/MOTD configuration
- ListenAddress binding to specific interfaces
**Security**
- No automatic ACL/permission setting on generated keys
**Management**
- No uninstall/rollback capability
- No certificate expiry warnings
### Features Implemented
- ✅ Password authentication control (`-DisablePasswordAuthentication`)
- ✅ Service auto-start and start (automatic, no switches needed)
- ✅ Windows Firewall rules (automatic per-profile: Domain, Private, Public)
- ✅ Port configuration (`-SSHPort`, default 22)
- ✅ Config backup before modification (automatic timestamped backups)
- ✅ Config validation (`sshd -t`) before restart with automatic rollback
- ✅ CA selection via regex (`-CAInclusionExpression`, `-CAExclusionExpression`)
- ✅ SFTP subsystem (configured automatically, custom path via `-SFTPSubsystemPath`)
## Troubleshooting
### Script Re-launches in New Window
The script automatically elevates to administrator. This is expected behavior.
### Public Keys Not Working
1. Verify the key format is correct (starts with `ssh-rsa`, `ssh-ed25519`, etc.)
2. Check `C:\ProgramData\ssh\administrators_authorized_keys` file permissions
3. Ensure `PubkeyAuthentication yes` is in sshd_config
### Certificate Authentication Not Working
1. Verify CA certificates are not expired
2. Check the PEM bundle exists at `C:\ProgramData\ssh\OpenSSH-TrustedCertificateAuthorities-LocalMachine.pem`
3. Verify `TrustedUserCAKeys` path in sshd_config
4. Run `sshd -t` to validate configuration
### Service Won't Start
1. Check Windows Event Viewer for sshd errors
2. Validate config: `& 'C:\Program Files\OpenSSH\sshd.exe' -t`
3. Ensure no port conflicts on TCP 22
## Project Structure
```
Invoke-OpenSSHConfiguration/
├── Invoke-OpenSSHConfiguration.ps1 # Main script
├── README.md # This file
├── Content/ # Additional content files
├── Toolkit/
│ ├── Toolkit.ps1 # Core toolkit initialization
│ ├── Functions/ # Reusable PowerShell functions
│ │ ├── ConvertFrom-CertificateToPEM.ps1
│ │ ├── Get-GitRepositoryRelease.ps1
│ │ ├── Get-CurrentUser.ps1
│ │ └── ...
│ ├── Modules/ # PowerShell modules
│ └── Tools/ # External tools
└── .augment/
└── rules/ # Coding standards
```
## Contributing
1. Follow the coding standards in `.augment/rules/PowershellScripts.md`
2. Use the established patterns (OrderedDictionary, Switch statements, etc.)
3. Test changes with `-Verbose` flag
4. Update documentation for new parameters
## License
[Add your license here]
## Acknowledgments
- [Win32-OpenSSH](https://github.com/PowerShell/Win32-OpenSSH) - Microsoft's OpenSSH port for Windows