mirror of
https://github.com/Grace-Solutions/Invoke-OpenSSHConfiguration.git
synced 2026-07-26 11:38:14 +00:00
e566ab15f1
- 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)
277 lines
11 KiB
Markdown
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
|