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

Add support for SSH via Bastion Host (Juniper#121) #122

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
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
61 changes: 61 additions & 0 deletions netconf/transport_ssh.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ package netconf
import (
"crypto/x509"
"encoding/pem"
"errors"
"fmt"
"io/ioutil"
"net"
Expand All @@ -21,6 +22,8 @@ import (
)

const (
// bastionDefaultPort is the default port used when SSH via Bastion
bastionDefaultPort = 22
// sshDefaultPort is the default SSH port used when communicating with
// NETCONF
sshDefaultPort = 830
Expand Down Expand Up @@ -60,6 +63,52 @@ func (t *TransportSSH) Close() error {
return fmt.Errorf("No connection to close")
}

// DialWithBasstion connects and establishes SSH sessions over bastion host
//
// bastion can be an IP address (e.g) 172.16.2.1 which uses default port 22.
// Bastion can also specify port with format <host>:<port> (e.g 172.16.2.1:5001)
// target can be an IP address (e.g.) 172.16.1.1 which utlizes the default
// NETCONF over SSH port of 830. Target can also specify a port with the
// following format <host>:<port (e.g 172.16.1.1:22)
//
// config takes a ssh.ClientConfig connection. See documentation for
// go.crypto/ssh for documenation. There is a helper function SSHConfigPassword
// thar returns a ssh.ClientConfig for simple username/password authentication
func (t *TransportSSH) DialWithBasstion(bastion, target string, bastionConf, config *ssh.ClientConfig) error {
var err error

if !strings.Contains(bastion, ":") {
bastion = fmt.Sprintf("%s:%d", bastion, bastionDefaultPort)
}

bastionClient, err := ssh.Dial("tcp", bastion, bastionConf)
if err != nil {
return err
}

if !strings.Contains(target, ":") {
target = fmt.Sprintf("%s:%d", target, sshDefaultPort)
}

targetConn, err := bastionClient.Dial("tcp", target)
if err != nil {
return err
}

ncc, chans, reqs, err := ssh.NewClientConn(targetConn, target, config)
if err != nil {
return err
}

t.sshClient = ssh.NewClient(ncc, chans, reqs)
if t.sshClient == nil {
return errors.New("Error getting SSH Client for " + target + " via Bastion " + bastion)
}

err = t.setupSession()
return err
}

// Dial connects and establishes SSH sessions
//
// target can be an IP address (e.g.) 172.16.1.1 which utlizes the default
Expand Down Expand Up @@ -117,6 +166,18 @@ func NewSSHSession(conn net.Conn, config *ssh.ClientConfig) (*Session, error) {
return NewSession(t), nil
}

// DialSSHWithBastion creates a new NETCONF session using a SSH Transport.
// See TransportSSH.Dial for arguments.
func DialSSHWithBastion(bastion, target string, bastionConf, config *ssh.ClientConfig) (*Session, error) {
var t TransportSSH
err := t.DialWithBasstion(bastion, target, bastionConf, config)
if err != nil {
t.Close()
return nil, err
}
return NewSession(&t), nil
}

// DialSSH creates a new NETCONF session using a SSH Transport.
// See TransportSSH.Dial for arguments.
func DialSSH(target string, config *ssh.ClientConfig) (*Session, error) {
Expand Down