Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support specifying host key for ssh config #1125

Merged
merged 1 commit into from
Jan 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,6 @@ trim_trailing_whitespace = true
indent_style = space
indent_size = 4

[{package.json,*.yml,*.yaml}]
[{package.json,*.yml,*.yaml,*.proto}]
indent_style = space
indent_size = 2
6 changes: 1 addition & 5 deletions flow/connectors/postgres/ssh_wrapped_pool.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,7 @@ func NewSSHWrappedPostgresPool(
if sshConfig != nil {
sshServer = fmt.Sprintf("%s:%d", sshConfig.Host, sshConfig.Port)
var err error
clientConfig, err = utils.GetSSHClientConfig(
sshConfig.User,
sshConfig.Password,
sshConfig.PrivateKey,
)
clientConfig, err = utils.GetSSHClientConfig(sshConfig)
if err != nil {
slog.Error("Failed to get SSH client config", slog.Any("error", err))
cancel()
Expand Down
30 changes: 21 additions & 9 deletions flow/connectors/utils/ssh.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"encoding/base64"
"fmt"

"github.com/PeerDB-io/peer-flow/generated/protos"
"golang.org/x/crypto/ssh"
)

Expand All @@ -13,17 +14,17 @@ import (
// user: SSH username
// password: SSH password (can be empty if using a private key)
// privateKeyString: Private key as a string (can be empty if using a password)
func GetSSHClientConfig(user, password, privateKeyString string) (*ssh.ClientConfig, error) {
func GetSSHClientConfig(config *protos.SSHConfig) (*ssh.ClientConfig, error) {
var authMethods []ssh.AuthMethod

// Password-based authentication
if password != "" {
authMethods = append(authMethods, ssh.Password(password))
if config.Password != "" {
authMethods = append(authMethods, ssh.Password(config.Password))
}

// Private key-based authentication
if privateKeyString != "" {
pkey, err := base64.StdEncoding.DecodeString(privateKeyString)
if config.PrivateKey != "" {
pkey, err := base64.StdEncoding.DecodeString(config.PrivateKey)
if err != nil {
return nil, fmt.Errorf("failed to base64 decode private key: %w", err)
}
Expand All @@ -40,10 +41,21 @@ func GetSSHClientConfig(user, password, privateKeyString string) (*ssh.ClientCon
return nil, fmt.Errorf("no authentication methods provided")
}

return &ssh.ClientConfig{
User: user,
Auth: authMethods,
var hostKeyCallback ssh.HostKeyCallback
if config.HostKey != "" {
pubKey, err := ssh.ParsePublicKey([]byte(config.HostKey))
if err != nil {
return nil, fmt.Errorf("failed to parse host key: %w", err)
}
hostKeyCallback = ssh.FixedHostKey(pubKey)
} else {
//nolint:gosec
HostKeyCallback: ssh.InsecureIgnoreHostKey(),
hostKeyCallback = ssh.InsecureIgnoreHostKey()
}

return &ssh.ClientConfig{
User: config.User,
Auth: authMethods,
HostKeyCallback: hostKeyCallback,
}, nil
}
3 changes: 2 additions & 1 deletion protos/peers.proto
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ message SSHConfig {
string user = 3;
string password = 4;
string private_key = 5;
string host_key = 6;
}

message SnowflakeConfig {
Expand Down Expand Up @@ -115,7 +116,7 @@ enum DBType {
S3 = 5;
SQLSERVER = 6;
EVENTHUB_GROUP = 7;
CLICKHOUSE = 8;
CLICKHOUSE = 8;
}

message Peer {
Expand Down
8 changes: 8 additions & 0 deletions ui/app/peers/create/[peerType]/helpers/pg.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,13 @@ export const sshSetting = [
optional: true,
tips: 'Private key as a BASE64 string for authentication in order to SSH into your machine.',
},
{
label: 'Host Key',
stateHandler: (value: string, setter: sshSetter) =>
setter((curr) => ({ ...curr, hostKey: value })),
optional: true,
tips: 'Public key of host to mitigate MITM attacks when SSHing into your machine.',
},
];

export const blankSSHConfig: SSHConfig = {
Expand All @@ -94,6 +101,7 @@ export const blankSSHConfig: SSHConfig = {
user: '',
password: '',
privateKey: '',
hostKey: '',
};

export const blankPostgresSetting: PostgresConfig = {
Expand Down
9 changes: 3 additions & 6 deletions ui/components/PeerForms/ClickhouseConfig.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -137,12 +137,9 @@ export default function PostgresForm({ settings, setter }: ConfigProps) {
(sshConfig as SSHConfig)[
sshParam.label === 'BASE64 Private Key'
? 'privateKey'
: (sshParam.label.toLowerCase() as
| 'host'
| 'port'
| 'user'
| 'password'
| 'privateKey')
: sshParam.label === 'Host Key'
? 'hostKey'
: (sshParam.label.toLowerCase() as keyof SSHConfig)
] || ''
}
/>
Expand Down
9 changes: 3 additions & 6 deletions ui/components/PeerForms/PostgresForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -137,12 +137,9 @@ export default function PostgresForm({ settings, setter }: ConfigProps) {
(sshConfig as SSHConfig)[
sshParam.label === 'BASE64 Private Key'
? 'privateKey'
: (sshParam.label.toLowerCase() as
| 'host'
| 'port'
| 'user'
| 'password'
| 'privateKey')
: sshParam.label === 'Host Key'
? 'hostKey'
: (sshParam.label.toLowerCase() as keyof SSHConfig)
] || ''
}
/>
Expand Down
Loading