# Daftarkan SSH public key ke Mikrotik RouterOS # Usage: .\scripts\setup-ssh-mikrotik.ps1 # .\scripts\setup-ssh-mikrotik.ps1 -SkipUpload # # Catatan: # - RouterOS 7.5 butuh key RSA (ed25519 user key baru di 7.12+). # - Setelah import key, RouterOS default menolak password untuk user yang punya key. # Skrip ini mengaktifkan password-authentication=yes agar password tetap jadi fallback. param( [ValidateSet("ed25519", "rsa")] [string]$KeyType = "rsa", [switch]$SkipUpload, [switch]$NoPasswordFallback ) $HostAddr = "10.100.1.1" $SshPort = 255 $SshMac = "hmac-sha1" $SshUser = "admin" $KeyFile = if ($KeyType -eq "rsa") { Join-Path $env:USERPROFILE ".ssh\id_rsa_mikrotik" } else { Join-Path $env:USERPROFILE ".ssh\id_ed25519" } $PubFile = "$KeyFile.pub" $RemotePub = "mikrotik_admin.pub" $SshOpts = @( "-o", "MACs=$SshMac", "-o", "StrictHostKeyChecking=accept-new", "-o", "IdentitiesOnly=yes" ) $SshTarget = "${SshUser}@${HostAddr}" function Get-MikrotikKeyArgs { $args = @("-i", $KeyFile) + $SshOpts if ($KeyType -eq "rsa") { $args = @("-o", "PubkeyAcceptedAlgorithms=rsa-sha2-256,rsa-sha2-512,ssh-rsa") + $args } return $args } function Ensure-KeyPair { if ((Test-Path $KeyFile) -and (Test-Path $PubFile)) { return } Write-Host "Membuat key pair $KeyType ..." $comment = if ($KeyType -eq "rsa") { "${SshUser}@$(hostname)-mikrotik" } else { "${SshUser}@$(hostname)" } $keygenCmd = if ($KeyType -eq "rsa") { "ssh-keygen -t rsa -b 4096 -f `"$KeyFile`" -C `"$comment`" -N `"`" -q" } else { "ssh-keygen -t ed25519 -f `"$KeyFile`" -C `"$comment`" -N `"`" -q" } cmd /c $keygenCmd if ($LASTEXITCODE -ne 0) { throw "ssh-keygen gagal (exit $LASTEXITCODE)." } if (-not ((Test-Path $KeyFile) -and (Test-Path $PubFile))) { throw "Key pair tidak ditemukan setelah ssh-keygen: $KeyFile" } } function Normalize-PubFile { $content = (Get-Content $PubFile -Raw).Trim() if ($content -notmatch '^(ssh-rsa|ssh-ed25519) ') { throw "Format public key tidak valid: $PubFile" } [System.IO.File]::WriteAllText($PubFile, "$content`n", [System.Text.UTF8Encoding]::new($false)) } function Invoke-MikrotikSsh { param( [string]$RemoteCmd, [switch]$UseKey ) $args = @("-p", $SshPort, "-m", $SshMac) + $SshOpts if ($UseKey) { $args += Get-MikrotikKeyArgs $args += @("-o", "BatchMode=yes") } $args += @($SshTarget, $RemoteCmd) $output = & ssh @args 2>&1 foreach ($line in $output) { Write-Host $line } return @{ Output = ($output | Out-String).Trim() ExitCode = $LASTEXITCODE } } function Invoke-ScpUpload { $args = @("-P", $SshPort) + $SshOpts + @($PubFile, "${SshTarget}:$RemotePub") & scp @args if ($LASTEXITCODE -ne 0) { throw "Upload public key gagal (scp exit $LASTEXITCODE)." } } function Invoke-MikrotikImport { Write-Host " > hapus key lama user $SshUser (jika ada) ..." Invoke-MikrotikSsh "/user ssh-keys remove [find user=$SshUser]" | Out-Null Write-Host " > /user ssh-keys import ..." $import = Invoke-MikrotikSsh "/user ssh-keys import public-key-file=$RemotePub user=$SshUser" if ($import.ExitCode -ne 0) { throw "Import key gagal (ssh exit $($import.ExitCode))." } if ($import.Output -match '(?i)(unable to load|wrong format|failure|error)') { throw "RouterOS menolak file key: $($import.Output)" } Write-Host " > /user ssh-keys print" $print = Invoke-MikrotikSsh "/user ssh-keys print" if ($print.ExitCode -ne 0) { throw "Gagal membaca daftar key (ssh exit $($print.ExitCode))." } if ($print.Output -notmatch '(?i)(ssh-rsa|ssh-ed25519|key-owner=admin|user=admin)') { throw "Import selesai tanpa error, tapi key admin tidak terlihat. Output:`n$($print.Output)" } if (-not $NoPasswordFallback) { Write-Host " > /ip ssh set password-authentication=yes" $sshPolicy = Invoke-MikrotikSsh "/ip ssh set password-authentication=yes" if ($sshPolicy.ExitCode -ne 0) { Write-Warning "Gagal set password-authentication=yes. Password bisa terkunci jika key login gagal." } } Write-Host " > /file remove $RemotePub" $cleanup = Invoke-MikrotikSsh "/file remove $RemotePub" if ($cleanup.ExitCode -ne 0) { Write-Warning "Key terimport, tapi gagal hapus $RemotePub di router." } } function Test-KeyLogin { $args = @( "-o", "BatchMode=yes", "-p", $SshPort, "-m", $SshMac ) + (Get-MikrotikKeyArgs) + @( $SshTarget, "/system identity print" ) $output = & ssh @args 2>&1 foreach ($line in $output) { Write-Host $line } if ($LASTEXITCODE -ne 0) { throw @" Verifikasi key login gagal. Jika password admin juga ditolak setelah import key, hapus key di RouterOS: /user ssh-keys remove [find user=admin] /ip ssh set password-authentication=yes Lalu jalankan ulang skrip ini. "@ } } Write-Host "=== Setup SSH key ke Mikrotik ===" Write-Host "Target : $SshTarget (port $SshPort)" Write-Host "Key : $KeyFile" if ($KeyType -eq "ed25519") { Write-Host "Info : ed25519 butuh RouterOS 7.12+ (router ini RouterOS 7.5 -> gunakan -KeyType rsa)" } else { Write-Host "Info : RSA untuk RouterOS 7.5" } Write-Host "Info : IdentitiesOnly=yes — hanya key Mikrotik yang dikirim (bukan id_ed25519 dari ssh-agent)" Write-Host "" Ensure-KeyPair Normalize-PubFile if (-not $SkipUpload) { Write-Host "Langkah 1/3: upload public key (masukkan password admin jika diminta) ..." Invoke-ScpUpload } else { Write-Host "Langkah 1/3: dilewati (-SkipUpload, pakai $RemotePub yang sudah ada di router)" } Write-Host "" Write-Host "Langkah 2/3: import key di RouterOS (masukkan password admin jika diminta) ..." Invoke-MikrotikImport Write-Host "" Write-Host "Langkah 3/3: verifikasi login tanpa password ..." Test-KeyLogin Write-Host "" Write-Host "Selesai. Login berikutnya:" Write-Host " .\scripts\ssh-mikrotik.ps1" Write-Host " ssh -i `"$KeyFile`" -o IdentitiesOnly=yes -m $SshMac $SshTarget -p $SshPort"