Change auth methods to opt-out, keep key generation opt-in

Authentication methods now ENABLED by default (opt-out):
- -DisablePubkeyAuthentication (was -EnablePubkeyAuthentication)
- -DisablePasswordAuthentication (unchanged)
- -DisableCertificateAuthentication (was -EnableCertificateAuthentication)

Key generation remains OPT-IN:
- -GenerateKeyPair still requires explicit use

Config changes:
- All auth settings now idempotent (only modify if value differs)
- Certificate auth auto-enables if CA bundle exists
- Disabling cert auth comments out TrustedUserCAKeys line

Updated README with new parameter names and examples
This commit is contained in:
GraceSolutions
2026-05-04 19:58:41 -04:00
parent bb1d0d7420
commit dc57ef82fc
2 changed files with 94 additions and 58 deletions
+80 -42
View File
@@ -67,13 +67,13 @@
[Int]$KeyBits, [Int]$KeyBits,
[Parameter(Mandatory=$False)] [Parameter(Mandatory=$False)]
[Switch]$EnablePubkeyAuthentication, [Switch]$DisablePubkeyAuthentication,
[Parameter(Mandatory=$False)] [Parameter(Mandatory=$False)]
[Switch]$DisablePasswordAuthentication, [Switch]$DisablePasswordAuthentication,
[Parameter(Mandatory=$False)] [Parameter(Mandatory=$False)]
[Switch]$EnableCertificateAuthentication, [Switch]$DisableCertificateAuthentication,
[Parameter(Mandatory=$False)] [Parameter(Mandatory=$False)]
[Switch]$TrustWindowsCertificateAuthorities, [Switch]$TrustWindowsCertificateAuthorities,
@@ -679,59 +679,65 @@ Switch (Test-ProcessElevationStatus)
$SSHDConfigContent = [System.IO.File]::ReadAllText($SSHDConfigPath.FullName) $SSHDConfigContent = [System.IO.File]::ReadAllText($SSHDConfigPath.FullName)
$SSHDConfigModified = $False $SSHDConfigModified = $False
#region Enable PubkeyAuthentication #region Configure PubkeyAuthentication (enabled by default, opt-out)
Switch ($EnablePubkeyAuthentication.IsPresent -eq $True) $PubkeyAuthPattern = '(?m)^#?\s*PubkeyAuthentication\s+.*$'
$PubkeyAuthValue = Switch ($DisablePubkeyAuthentication.IsPresent) { {($_ -eq $True)} {'no'} Default {'yes'} }
$PubkeyAuthReplacement = "PubkeyAuthentication $($PubkeyAuthValue)"
Switch ($SSHDConfigContent -imatch $PubkeyAuthPattern)
{ {
{($_ -eq $True)} {($_ -eq $True)}
{ {
$PubkeyAuthPattern = '(?m)^#?\s*PubkeyAuthentication\s+.*$' $CurrentMatch = [System.Text.RegularExpressions.Regex]::Match($SSHDConfigContent, $PubkeyAuthPattern)
$PubkeyAuthReplacement = 'PubkeyAuthentication yes'
Switch ($SSHDConfigContent -imatch $PubkeyAuthPattern) Switch ($CurrentMatch.Value -ine $PubkeyAuthReplacement)
{ {
{($_ -eq $True)} {($_ -eq $True)}
{ {
$SSHDConfigContent = [System.Text.RegularExpressions.Regex]::Replace($SSHDConfigContent, $PubkeyAuthPattern, $PubkeyAuthReplacement) $SSHDConfigContent = [System.Text.RegularExpressions.Regex]::Replace($SSHDConfigContent, $PubkeyAuthPattern, $PubkeyAuthReplacement)
$SSHDConfigModified = $True $SSHDConfigModified = $True
$WriteLogMessage.Invoke(0, @("Enabled PubkeyAuthentication.")) $WriteLogMessage.Invoke(0, @("Configured PubkeyAuthentication: $($PubkeyAuthValue)"))
}
Default
{
$SSHDConfigContent = $SSHDConfigContent + "`r`n$($PubkeyAuthReplacement)"
$SSHDConfigModified = $True
$WriteLogMessage.Invoke(0, @("Added PubkeyAuthentication setting."))
} }
} }
} }
Default
{
$SSHDConfigContent = $SSHDConfigContent + "`r`n$($PubkeyAuthReplacement)"
$SSHDConfigModified = $True
$WriteLogMessage.Invoke(0, @("Added PubkeyAuthentication: $($PubkeyAuthValue)"))
}
} }
#endregion #endregion
#region Disable PasswordAuthentication #region Configure PasswordAuthentication (enabled by default, opt-out)
Switch ($DisablePasswordAuthentication.IsPresent -eq $True) $PasswordAuthPattern = '(?m)^#?\s*PasswordAuthentication\s+.*$'
$PasswordAuthValue = Switch ($DisablePasswordAuthentication.IsPresent) { {($_ -eq $True)} {'no'} Default {'yes'} }
$PasswordAuthReplacement = "PasswordAuthentication $($PasswordAuthValue)"
Switch ($SSHDConfigContent -imatch $PasswordAuthPattern)
{ {
{($_ -eq $True)} {($_ -eq $True)}
{ {
$PasswordAuthPattern = '(?m)^#?\s*PasswordAuthentication\s+.*$' $CurrentMatch = [System.Text.RegularExpressions.Regex]::Match($SSHDConfigContent, $PasswordAuthPattern)
$PasswordAuthReplacement = 'PasswordAuthentication no'
Switch ($SSHDConfigContent -imatch $PasswordAuthPattern) Switch ($CurrentMatch.Value -ine $PasswordAuthReplacement)
{ {
{($_ -eq $True)} {($_ -eq $True)}
{ {
$SSHDConfigContent = [System.Text.RegularExpressions.Regex]::Replace($SSHDConfigContent, $PasswordAuthPattern, $PasswordAuthReplacement) $SSHDConfigContent = [System.Text.RegularExpressions.Regex]::Replace($SSHDConfigContent, $PasswordAuthPattern, $PasswordAuthReplacement)
$SSHDConfigModified = $True $SSHDConfigModified = $True
$WriteLogMessage.Invoke(0, @("Disabled PasswordAuthentication.")) $WriteLogMessage.Invoke(0, @("Configured PasswordAuthentication: $($PasswordAuthValue)"))
}
Default
{
$SSHDConfigContent = $SSHDConfigContent + "`r`n$($PasswordAuthReplacement)"
$SSHDConfigModified = $True
$WriteLogMessage.Invoke(0, @("Added PasswordAuthentication setting (disabled)."))
} }
} }
} }
Default
{
$SSHDConfigContent = $SSHDConfigContent + "`r`n$($PasswordAuthReplacement)"
$SSHDConfigModified = $True
$WriteLogMessage.Invoke(0, @("Added PasswordAuthentication: $($PasswordAuthValue)"))
}
} }
#endregion #endregion
@@ -775,38 +781,70 @@ Switch (Test-ProcessElevationStatus)
} }
#endregion #endregion
#region Configure TrustedUserCAKeys for Certificate Authentication #region Configure TrustedUserCAKeys for Certificate Authentication (enabled by default if CA bundle exists, opt-out)
Switch (($EnableCertificateAuthentication.IsPresent -eq $True) -and ($TrustWindowsCertificateAuthorities.IsPresent -eq $True)) $CABundleFileName = 'OpenSSH-TrustedCertificateAuthorities-LocalMachine.pem'
[System.IO.FileInfo]$CABundlePath = [System.IO.Path]::Combine($OpenSSHProgramDataDirectory.FullName, $CABundleFileName)
#Use __PROGRAMDATA__ variable for sshd_config (portable path)
$CABundleConfigPath = "__PROGRAMDATA__/ssh/$($CABundleFileName)"
$TrustedCAKeysPattern = '(?m)^#?\s*TrustedUserCAKeys\s+.*$'
Switch ($DisableCertificateAuthentication.IsPresent -eq $True)
{ {
{($_ -eq $True)} {($_ -eq $True)}
{ {
$CABundleFileName = 'OpenSSH-TrustedCertificateAuthorities-LocalMachine.pem' #Disable: Comment out TrustedUserCAKeys if it exists
[System.IO.FileInfo]$CABundlePath = [System.IO.Path]::Combine($OpenSSHProgramDataDirectory.FullName, $CABundleFileName) Switch ($SSHDConfigContent -imatch $TrustedCAKeysPattern)
{
#Use __PROGRAMDATA__ variable for sshd_config (portable path) {($_ -eq $True)}
$CABundleConfigPath = "__PROGRAMDATA__/ssh/$($CABundleFileName)" {
$CurrentMatch = [System.Text.RegularExpressions.Regex]::Match($SSHDConfigContent, $TrustedCAKeysPattern)
Switch ($CABundlePath.Exists)
Switch ($CurrentMatch.Value -inotmatch '^#')
{
{($_ -eq $True)}
{
$SSHDConfigContent = [System.Text.RegularExpressions.Regex]::Replace($SSHDConfigContent, $TrustedCAKeysPattern, "#$($CurrentMatch.Value)")
$SSHDConfigModified = $True
$WriteLogMessage.Invoke(0, @("Disabled TrustedUserCAKeys (commented out)."))
}
}
}
}
}
Default
{
#Enable: Configure TrustedUserCAKeys if CA bundle exists
Switch ($CABundlePath.Exists -eq $True)
{ {
{($_ -eq $True)} {($_ -eq $True)}
{ {
$TrustedCAKeysPattern = '(?m)^#?\s*TrustedUserCAKeys\s+.*$'
$TrustedCAKeysReplacement = "TrustedUserCAKeys $($CABundleConfigPath)" $TrustedCAKeysReplacement = "TrustedUserCAKeys $($CABundleConfigPath)"
Switch ($SSHDConfigContent -imatch $TrustedCAKeysPattern) Switch ($SSHDConfigContent -imatch $TrustedCAKeysPattern)
{ {
{($_ -eq $True)} {($_ -eq $True)}
{ {
$SSHDConfigContent = [System.Text.RegularExpressions.Regex]::Replace($SSHDConfigContent, $TrustedCAKeysPattern, $TrustedCAKeysReplacement) $CurrentMatch = [System.Text.RegularExpressions.Regex]::Match($SSHDConfigContent, $TrustedCAKeysPattern)
$SSHDConfigModified = $True
$WriteLogMessage.Invoke(0, @("Configured TrustedUserCAKeys to `"$($CABundleConfigPath)`".")) Switch ($CurrentMatch.Value -ine $TrustedCAKeysReplacement)
{
{($_ -eq $True)}
{
$SSHDConfigContent = [System.Text.RegularExpressions.Regex]::Replace($SSHDConfigContent, $TrustedCAKeysPattern, $TrustedCAKeysReplacement)
$SSHDConfigModified = $True
$WriteLogMessage.Invoke(0, @("Configured TrustedUserCAKeys: $($CABundleConfigPath)"))
}
}
} }
Default Default
{ {
$SSHDConfigContent = $SSHDConfigContent + "`r`n$($TrustedCAKeysReplacement)" $SSHDConfigContent = $SSHDConfigContent + "`r`n$($TrustedCAKeysReplacement)"
$SSHDConfigModified = $True $SSHDConfigModified = $True
$WriteLogMessage.Invoke(0, @("Added TrustedUserCAKeys setting.")) $WriteLogMessage.Invoke(0, @("Added TrustedUserCAKeys: $($CABundleConfigPath)"))
} }
} }
} }
+14 -16
View File
@@ -34,12 +34,12 @@ cd Invoke-OpenSSHConfiguration
|-----------|------|-------------| |-----------|------|-------------|
| `-Mode` | String | Installation mode: `Client` or `Server` | | `-Mode` | String | Installation mode: `Client` or `Server` |
| `-PublicKeyList` | String[] | Array of public keys to add to `administrators_authorized_keys` | | `-PublicKeyList` | String[] | Array of public keys to add to `administrators_authorized_keys` |
| `-GenerateKeyPair` | Switch | Generate SSH host key pair | | `-GenerateKeyPair` | Switch | Generate SSH host key pair (opt-in) |
| `-KeyType` | String | Key algorithm: `rsa`, `ecdsa`, `ed25519` (default: `ed25519`) | | `-KeyType` | String | Key algorithm: `rsa`, `ecdsa`, `ed25519` (default: `ed25519`) |
| `-KeyBits` | Int | Key size: 256, 384, 521 (ECDSA) or 2048, 3072, 4096 (RSA) | | `-KeyBits` | Int | Key size: 256, 384, 521 (ECDSA) or 2048, 3072, 4096 (RSA) |
| `-EnablePubkeyAuthentication` | Switch | Enable `PubkeyAuthentication yes` in sshd_config | | `-DisablePubkeyAuthentication` | Switch | Disable public key authentication (enabled by default) |
| `-DisablePasswordAuthentication` | Switch | Disable password authentication (`PasswordAuthentication no`) | | `-DisablePasswordAuthentication` | Switch | Disable password authentication (enabled by default) |
| `-EnableCertificateAuthentication` | Switch | Configure `TrustedUserCAKeys` for certificate auth | | `-DisableCertificateAuthentication` | Switch | Disable certificate authentication (enabled by default if CA bundle exists) |
| `-TrustWindowsCertificateAuthorities` | Switch | Export Windows CA certificates to PEM bundle | | `-TrustWindowsCertificateAuthorities` | Switch | Export Windows CA certificates to PEM bundle |
| `-CAInclusionExpression` | String | Regex to filter CAs by Subject or Thumbprint (include matches) | | `-CAInclusionExpression` | String | Regex to filter CAs by Subject or Thumbprint (include matches) |
| `-CAExclusionExpression` | String | Regex to filter CAs by Subject or Thumbprint (exclude matches) | | `-CAExclusionExpression` | String | Regex to filter CAs by Subject or Thumbprint (exclude matches) |
@@ -96,22 +96,20 @@ This exports all unexpired Root and Intermediate CA certificates from the Window
### Full Server Configuration ### Full Server Configuration
```powershell ```powershell
# All auth methods enabled by default, just add keys and trust CAs
.\Invoke-OpenSSHConfiguration.ps1 -Mode Server ` .\Invoke-OpenSSHConfiguration.ps1 -Mode Server `
-PublicKeyList @('ssh-ed25519 AAAAC3NzaC1lZDI1NTE5... admin@corp') ` -PublicKeyList @('ssh-ed25519 AAAAC3NzaC1lZDI1NTE5... admin@corp') `
-GenerateKeyPair ` -GenerateKeyPair `
-KeyType ed25519 ` -KeyType ed25519 `
-TrustWindowsCertificateAuthorities ` -TrustWindowsCertificateAuthorities `
-EnableCertificateAuthentication `
-EnablePubkeyAuthentication `
-DisablePasswordAuthentication `
-LogDirectory 'C:\Logs\OpenSSH' -LogDirectory 'C:\Logs\OpenSSH'
``` ```
### Hardened Server (Keys Only, No Passwords) ### Hardened Server (Keys Only, No Passwords)
```powershell ```powershell
# Disable password auth, keep pubkey and cert auth enabled
.\Invoke-OpenSSHConfiguration.ps1 -Mode Server ` .\Invoke-OpenSSHConfiguration.ps1 -Mode Server `
-EnablePubkeyAuthentication `
-DisablePasswordAuthentication -DisablePasswordAuthentication
``` ```
@@ -121,20 +119,17 @@ This exports all unexpired Root and Intermediate CA certificates from the Window
# Only trust CAs with "Corp" or "Enterprise" in the subject # Only trust CAs with "Corp" or "Enterprise" in the subject
.\Invoke-OpenSSHConfiguration.ps1 -Mode Server ` .\Invoke-OpenSSHConfiguration.ps1 -Mode Server `
-TrustWindowsCertificateAuthorities ` -TrustWindowsCertificateAuthorities `
-CAInclusionExpression '(Corp|Enterprise)' ` -CAInclusionExpression '(Corp|Enterprise)'
-EnableCertificateAuthentication
# Trust all CAs except Microsoft root CAs # Trust all CAs except Microsoft root CAs
.\Invoke-OpenSSHConfiguration.ps1 -Mode Server ` .\Invoke-OpenSSHConfiguration.ps1 -Mode Server `
-TrustWindowsCertificateAuthorities ` -TrustWindowsCertificateAuthorities `
-CAExclusionExpression 'Microsoft' ` -CAExclusionExpression 'Microsoft'
-EnableCertificateAuthentication
# Trust specific CA by thumbprint pattern # Trust specific CA by thumbprint pattern
.\Invoke-OpenSSHConfiguration.ps1 -Mode Server ` .\Invoke-OpenSSHConfiguration.ps1 -Mode Server `
-TrustWindowsCertificateAuthorities ` -TrustWindowsCertificateAuthorities `
-CAInclusionExpression '^A1B2C3' ` -CAInclusionExpression '^A1B2C3'
-EnableCertificateAuthentication
``` ```
### Custom SFTP Server Path ### Custom SFTP Server Path
@@ -210,13 +205,16 @@ The toolkit includes reusable functions in `Toolkit\Functions\`:
- No certificate expiry warnings - No certificate expiry warnings
### Features Implemented ### Features Implemented
-Password authentication control (`-DisablePasswordAuthentication`) -Authentication methods enabled by default (opt-out via `-Disable*` switches)
- PubKey, Password, Certificate auth all enabled unless explicitly disabled
- ✅ Key generation opt-in (`-GenerateKeyPair`)
- ✅ Service auto-start and start (automatic, no switches needed) - ✅ Service auto-start and start (automatic, no switches needed)
- ✅ Windows Firewall rules (automatic per-profile: Domain, Private, Public) - ✅ Windows Firewall rules (automatic per-profile: Domain, Private, Public)
- ✅ Port configuration (`-SSHPort`, default 22) - ✅ Port configuration (`-SSHPort`, default 22)
- ✅ Config backup before modification (automatic timestamped backups) - ✅ Config backup before modification (automatic, keeps last 3)
- ✅ Config validation (`sshd -t`) before restart with automatic rollback - ✅ Config validation (`sshd -t`) before restart with automatic rollback
- ✅ CA selection via regex (`-CAInclusionExpression`, `-CAExclusionExpression`) - ✅ CA selection via regex (`-CAInclusionExpression`, `-CAExclusionExpression`)
- ✅ Session user certificate access (reads from HKEY_USERS when running as SYSTEM)
- ✅ SFTP subsystem (configured automatically, custom path via `-SFTPSubsystemPath`) - ✅ SFTP subsystem (configured automatically, custom path via `-SFTPSubsystemPath`)
## Troubleshooting ## Troubleshooting