Register hosts under Containers/VMs/Docker with encrypted key storage, and require re-authentication for sensitive account changes.
74 lines
1.7 KiB
Go
74 lines
1.7 KiB
Go
package auth
|
|
|
|
import (
|
|
"fmt"
|
|
"net"
|
|
"strings"
|
|
"time"
|
|
|
|
"golang.org/x/crypto/ssh"
|
|
)
|
|
|
|
const defaultSSHPort = "22"
|
|
const sshDialTimeout = 10 * time.Second
|
|
|
|
// TestSSHConnection dials host over SSH using the given private key and username.
|
|
// Host key verification is intentionally skipped for this connectivity check;
|
|
// trust-on-first-use / known_hosts can be added later.
|
|
func TestSSHConnection(hostIP string, username string, privateKeyPEM string, passphrase string) error {
|
|
hostIP = strings.TrimSpace(hostIP)
|
|
username = strings.TrimSpace(username)
|
|
if hostIP == "" {
|
|
return fmt.Errorf("host IP is required")
|
|
}
|
|
if username == "" {
|
|
return fmt.Errorf("username is required")
|
|
}
|
|
|
|
signer, err := parseSigner(privateKeyPEM, passphrase)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
config := &ssh.ClientConfig{
|
|
User: username,
|
|
Auth: []ssh.AuthMethod{
|
|
ssh.PublicKeys(signer),
|
|
},
|
|
HostKeyCallback: ssh.InsecureIgnoreHostKey(),
|
|
Timeout: sshDialTimeout,
|
|
}
|
|
|
|
address := net.JoinHostPort(hostIP, defaultSSHPort)
|
|
client, err := ssh.Dial("tcp", address, config)
|
|
if err != nil {
|
|
return fmt.Errorf("ssh dial %s: %w", address, err)
|
|
}
|
|
defer client.Close()
|
|
return nil
|
|
}
|
|
|
|
func parseSigner(privateKeyPEM string, passphrase string) (ssh.Signer, error) {
|
|
trimmed := strings.TrimSpace(privateKeyPEM)
|
|
if trimmed == "" {
|
|
return nil, fmt.Errorf("private key is required")
|
|
}
|
|
|
|
var (
|
|
signer ssh.Signer
|
|
err error
|
|
)
|
|
if strings.TrimSpace(passphrase) == "" {
|
|
signer, err = ssh.ParsePrivateKey([]byte(trimmed))
|
|
} else {
|
|
signer, err = ssh.ParsePrivateKeyWithPassphrase(
|
|
[]byte(trimmed),
|
|
[]byte(passphrase),
|
|
)
|
|
}
|
|
if err != nil {
|
|
return nil, fmt.Errorf("parse private key: %w", err)
|
|
}
|
|
return signer, nil
|
|
}
|