An ssh-copy-id alternative for Windows OpenSSH servers.
Connects via password authentication and automatically deploys your public key. Handles all Windows-specific pitfalls (BOM, Admin branching, ACL). Sets proper ACL on both the .ssh directory and key file using well-known SIDs for cross-locale compatibility.
Download binaries from GitLab Releases / GitHub Releases, or:
go install gitlab.com/kwrkb/ssh-pushkey@latestssh-pushkey user@hostEnter your password and the rest is fully automated.
When -i is not specified, ssh-pushkey discovers a public key automatically (same logic as ssh-copy-id):
- ssh-agent — runs
ssh-add -L; uses the first key if available - File fallback — globs
~/.ssh/id_*.puband picks the newest by modification time - If neither source provides a key, exits with an error
Supported key types include ed25519, rsa, ecdsa, and FIDO/U2F (sk-ssh-ed25519, sk-ecdsa-sha2-nistp256).
| Flag | Default | Description |
|---|---|---|
-i |
(auto-discover) | Path to the public key file |
-p |
22 |
SSH port number |
--insecure |
false |
Skip host key verification (not recommended) |
--version |
- | Show version |
# Auto-discover key and deploy
ssh-pushkey admin@192.168.1.10
# Specify key and port
ssh-pushkey -i ~/.ssh/id_rsa.pub -p 2222 user@server- Connects via SSH with password authentication
- Detects whether the user is in the Administrators group
- Checks if
administrators_authorized_keysis enabled insshd_config - Writes the public key in BOM-less UTF-8 to the appropriate file
- Sets ACL on both the
.sshdirectory and key file viaicaclsusing well-known SIDs (SYSTEM,Administrators, current user)
| User type | Key destination |
|---|---|
Admin (administrators_authorized_keys enabled) |
C:\ProgramData\ssh\administrators_authorized_keys |
| Admin (disabled) / Regular user | ~\.ssh\authorized_keys |
By default, ssh-pushkey verifies the remote host's key against ~/.ssh/known_hosts, the same as OpenSSH. On first connection to an unknown host, you'll be prompted to verify the fingerprint (Trust on First Use). Accepted keys are automatically added to your known_hosts file.
If the host key has changed since a previous connection, you'll be prompted to confirm the update. This handles legitimate key rotations while still alerting you to potential MITM attacks.
Hashed known_hosts entries (HashKnownHosts yes) are fully supported — both matching and writing preserve the hashed format.
Use --insecure to skip host key verification. This is not recommended as it makes the connection vulnerable to man-in-the-middle attacks, potentially exposing your password.
ACL entries use well-known SIDs (S-1-5-18 for SYSTEM, S-1-5-32-544 for Administrators) instead of localized group names, ensuring correct behavior on non-English Windows installations and domain environments.
go build -ldflags "-X main.version=$(git describe --tags --abbrev=0)" -o ssh-pushkeygo test ./...Integration tests connect to a real Windows OpenSSH server. They are gated behind the integration build tag and skipped when the required environment variables are not set.
Setup:
-
Copy the example env file and edit it:
cp .env.integration.example .env.integration # Edit .env.integration with your host/user -
Add your password (not stored in the file for security):
read -rs SSH_TEST_PASSWORD && export SSH_TEST_PASSWORD
-
Run:
source .env.integration && go test -tags=integration -v ./...
Environment variables:
| Variable | Required | Description |
|---|---|---|
SSH_TEST_HOST |
Yes | Windows SSH server IP or hostname |
SSH_TEST_USER |
Yes | SSH username |
SSH_TEST_PASSWORD |
Yes | SSH password (use read -rs to set) |
SSH_TEST_PORT |
No | SSH port (default: 22) |
SSH_TEST_PUBKEY |
No | Path to public key (default: ~/.ssh/id_ed25519.pub) |
See CHANGELOG.md for release history.
MIT
