Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
P
packer
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Kristopher Ruzic
packer
Commits
cbaaf0da
Commit
cbaaf0da
authored
Jun 17, 2015
by
Mitchell Hashimoto
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
communicator/ssh: support for bastion SSH
parent
b2609db3
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
115 additions
and
2 deletions
+115
-2
communicator/ssh/connect.go
communicator/ssh/connect.go
+43
-0
helper/communicator/config.go
helper/communicator/config.go
+18
-0
helper/communicator/step_connect_ssh.go
helper/communicator/step_connect_ssh.go
+54
-2
No files found.
communicator/ssh/connect.go
View file @
cbaaf0da
package
ssh
import
(
"fmt"
"net"
"time"
"golang.org/x/crypto/ssh"
)
// ConnectFunc is a convenience method for returning a function
...
...
@@ -23,3 +26,43 @@ func ConnectFunc(network, addr string) func() (net.Conn, error) {
return
c
,
nil
}
}
// BastionConnectFunc is a convenience method for returning a function
// that connects to a host over a bastion connection.
func
BastionConnectFunc
(
bProto
string
,
bAddr
string
,
bConf
*
ssh
.
ClientConfig
,
proto
string
,
addr
string
)
func
()
(
net
.
Conn
,
error
)
{
return
func
()
(
net
.
Conn
,
error
)
{
// Connect to the bastion
bastion
,
err
:=
ssh
.
Dial
(
bProto
,
bAddr
,
bConf
)
if
err
!=
nil
{
return
nil
,
fmt
.
Errorf
(
"Error connecting to bastion: %s"
,
err
)
}
// Connect through to the end host
conn
,
err
:=
bastion
.
Dial
(
proto
,
addr
)
if
err
!=
nil
{
bastion
.
Close
()
return
nil
,
err
}
// Wrap it up so we close both things properly
return
&
bastionConn
{
Conn
:
conn
,
Bastion
:
bastion
,
},
nil
}
}
type
bastionConn
struct
{
net
.
Conn
Bastion
*
ssh
.
Client
}
func
(
c
*
bastionConn
)
Close
()
error
{
c
.
Conn
.
Close
()
return
c
.
Bastion
.
Close
()
}
helper/communicator/config.go
View file @
cbaaf0da
...
...
@@ -23,6 +23,11 @@ type Config struct {
SSHPty
bool
`mapstructure:"ssh_pty"`
SSHTimeout
time
.
Duration
`mapstructure:"ssh_timeout"`
SSHHandshakeAttempts
int
`mapstructure:"ssh_handshake_attempts"`
SSHBastionHost
string
`mapstructure:"ssh_bastion_host"`
SSHBastionPort
int
`mapstructure:"ssh_bastion_port"`
SSHBastionUsername
string
`mapstructure:"ssh_bastion_username"`
SSHBastionPassword
string
`mapstructure:"ssh_bastion_password"`
SSHBastionPrivateKey
string
`mapstructure:"ssh_bastion_private_key_file"`
// WinRM
WinRMUser
string
`mapstructure:"winrm_username"`
...
...
@@ -77,6 +82,12 @@ func (c *Config) prepareSSH(ctx *interpolate.Context) []error {
c
.
SSHHandshakeAttempts
=
10
}
if
c
.
SSHBastionHost
!=
""
{
if
c
.
SSHBastionPort
==
0
{
c
.
SSHBastionPort
=
22
}
}
// Validation
var
errs
[]
error
if
c
.
SSHUsername
==
""
{
...
...
@@ -93,6 +104,13 @@ func (c *Config) prepareSSH(ctx *interpolate.Context) []error {
}
}
if
c
.
SSHBastionHost
!=
""
{
if
c
.
SSHBastionPassword
==
""
&&
c
.
SSHBastionPrivateKey
==
""
{
errs
=
append
(
errs
,
errors
.
New
(
"ssh_bastion_password or ssh_bastion_private_key_file must be specified"
))
}
}
return
errs
}
...
...
helper/communicator/step_connect_ssh.go
View file @
cbaaf0da
...
...
@@ -4,10 +4,12 @@ import (
"errors"
"fmt"
"log"
"net"
"strings"
"time"
"github.com/mitchellh/multistep"
commonssh
"github.com/mitchellh/packer/common/ssh"
"github.com/mitchellh/packer/communicator/ssh"
"github.com/mitchellh/packer/packer"
gossh
"golang.org/x/crypto/ssh"
...
...
@@ -79,6 +81,24 @@ func (s *StepConnectSSH) Cleanup(multistep.StateBag) {
}
func
(
s
*
StepConnectSSH
)
waitForSSH
(
state
multistep
.
StateBag
,
cancel
<-
chan
struct
{})
(
packer
.
Communicator
,
error
)
{
// Determine if we're using a bastion host, and if so, retrieve
// that configuration. This configuration doesn't change so we
// do this one before entering the retry loop.
var
bProto
,
bAddr
string
var
bConf
*
gossh
.
ClientConfig
if
s
.
Config
.
SSHBastionHost
!=
""
{
// The protocol is hardcoded for now, but may be configurable one day
bProto
=
"tcp"
bAddr
=
fmt
.
Sprintf
(
"%s:%d"
,
s
.
Config
.
SSHBastionHost
,
s
.
Config
.
SSHBastionPort
)
conf
,
err
:=
sshBastionConfig
(
s
.
Config
)
if
err
!=
nil
{
return
nil
,
fmt
.
Errorf
(
"Error configuring bastion: %s"
,
err
)
}
bConf
=
conf
}
handshakeAttempts
:=
0
var
comm
packer
.
Communicator
...
...
@@ -117,10 +137,18 @@ func (s *StepConnectSSH) waitForSSH(state multistep.StateBag, cancel <-chan stru
continue
}
// Attempt to connect to SSH port
var
connFunc
func
()
(
net
.
Conn
,
error
)
address
:=
fmt
.
Sprintf
(
"%s:%d"
,
host
,
port
)
if
bAddr
!=
""
{
// We're using a bastion host, so use the bastion connfunc
connFunc
=
ssh
.
BastionConnectFunc
(
bProto
,
bAddr
,
bConf
,
"tcp"
,
address
)
}
else
{
// No bastion host, connect directly
connFunc
=
ssh
.
ConnectFunc
(
"tcp"
,
address
)
}
// Attempt to connect to SSH port
connFunc
:=
ssh
.
ConnectFunc
(
"tcp"
,
address
)
nc
,
err
:=
connFunc
()
if
err
!=
nil
{
log
.
Printf
(
"[DEBUG] TCP connection to SSH ip/port failed: %s"
,
err
)
...
...
@@ -164,3 +192,27 @@ func (s *StepConnectSSH) waitForSSH(state multistep.StateBag, cancel <-chan stru
return
comm
,
nil
}
func
sshBastionConfig
(
config
*
Config
)
(
*
gossh
.
ClientConfig
,
error
)
{
auth
:=
make
([]
gossh
.
AuthMethod
,
0
,
2
)
if
config
.
SSHBastionPassword
!=
""
{
auth
=
append
(
auth
,
gossh
.
Password
(
config
.
SSHBastionPassword
),
gossh
.
KeyboardInteractive
(
ssh
.
PasswordKeyboardInteractive
(
config
.
SSHBastionPassword
)))
}
if
config
.
SSHBastionPrivateKey
!=
""
{
signer
,
err
:=
commonssh
.
FileSigner
(
config
.
SSHBastionPrivateKey
)
if
err
!=
nil
{
return
nil
,
err
}
auth
=
append
(
auth
,
gossh
.
PublicKeys
(
signer
))
}
return
&
gossh
.
ClientConfig
{
User
:
config
.
SSHBastionUsername
,
Auth
:
auth
,
},
nil
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment