# RouterOS SSH Key Deployment (v7.18+) Deploying SSH public keys to RouterOS v7 via CLI over SSH is surprisingly finicky. This doc catalogs what works and what doesn't. ## What DOES work ### Method A — `/file/add name="" contents=""` (v7 clean, no FTP needed) This is the most reliable method discovered. Works on RouterOS 7.18.2 (CCR2004): ``` # Create file with the public key content /file/add name="wisp-key.txt" contents="ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAA... wisp-backup" # Import the key for a user /user ssh-keys import public-key-file="wisp-key.txt" user=shonuff # Clean up the source file /file/remove [find name="wisp-key.txt"] ``` **Limitations:** The `contents=` value is part of the SSH command string. RouterOS SSH session seems to have a ~170 character line limit. The Ed25519 key line is ~92 chars — fits fine. An RSA 4096 key line (~500+ chars) would NOT fit. **Escaping:** The key content does NOT contain `$`, `\`, or `"` in the base64-encoded section, so double quotes around `contents=` work without escaping. If you ever deploy a key that does contain these, use hex encoding (Method C below). ### Method B — `/user ssh-keys/add user= key=` (native, no file at all) RouterOS v7 supports creating the SSH key directly without a file intermediary. This is the cleanest approach: ```routeros /user ssh-keys/add user=shonuff key="ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAA... wisp-backup" ``` Same line-length limitation as Method A (~170 chars over SSH). For keys that exceed this, use Method A (`/file/add contents=`) which is verified compatible. **Note:** This method is verified working on RouterOS 7.18.2. The `user ssh-keys print` command requires the `full` group to read (or a user with policy privileges) — `write` group gets "Permission denied" when listing but the key import itself succeeds and SSH key auth works. Test via `ssh -i key user@host /system identity print`. ### Method C — Hex-encoded script (for long keys) ### Method C — Hex-encoded script (for long keys) For RSA keys longer than the SSH line limit, write the key as a RouterOS script using hex escapes: ``` /system script add name=deploy-key source=":local key \"\\73\\73\\68...\"; :put \$key file=wisp-key.txt" /system script run deploy-key /user ssh-keys import public-key-file=wisp-key.txt user=wisp-backup ``` Generate the hex escape string from Python: ```python key = "ssh-ed25519 ..." hex_escaped = ''.join(f'\\{b:02X}' for b in key.encode()) ``` ## What does NOT work ### ❌ `:put ... file=` — Syntax error on RouterOS 7.18 ``` :put "abc123" file=test.txt # expected end of command ``` The `file=` parameter does not exist on `:put` in RouterOS 7.18. This is a frequently-seen outdated suggestion in forum posts. It was removed or never existed in 7.x. ### ❌ `:put ... file="test.txt"` — Same error, with or without quotes. ### ❌ `:convert from=base64` with long strings truncated by SSH line limit The `:convert from=base64` command itself works (verified with short test), but the base64 string + command prefix exceeds RouterOS's SSH line length limit (~170 chars). ### ❌ SCP/SFTP — "exec request failed on channel 0" MikroTik RouterOS does not support the SCP or SFTP subsystems over SSH (verified on 7.18.2). Even with `scp -O` legacy protocol flag, the router rejects the channel request. ### ❌ FTP — disabled by default FTP service is installed but disabled (`/ip service print` shows `X` flag). You can temporarily enable it, but the `write` user group has `!ftp` policy by default. The `full` group does have FTP. Enabling FTP+changing user group is possible but a hassle vs Method A. ## Key verification After importing, verify key-based auth works: ```bash ssh -i ~/.ssh/wisp_rsa user@192.168.88.1 /system identity print ``` Once an SSH key is assigned to a RouterOS user, password-based SSH login is automatically disabled for that user (RouterOS v7 behavior, not a bug). ## Permission notes - **`write` group:** Can *use* SSH keys (key auth works), but trying `/user ssh-keys print` returns "Permission denied". Import still succeeds (`exit 0`). Test via `ssh -i key user@host /system resource print` instead. - **`full` group:** Can list and manage SSH keys. If you need to verify keys from SSH, use `full` or `read` group with correct policy. - The `!ftp` policy in `write` group blocks both FTP *and* `/tool/fetch` — anything that tries the FTP subsystem. Not a bug, documented behavior. ## Cleanup Remove the intermediate `.txt` key file after successful import: ``` /file/remove [find name="wisp-key.txt"] ```