Skip to content
This repository has been archived by the owner on Jun 12, 2021. It is now read-only.

Commit

Permalink
Add support for attributes discussed in #89.
Browse files Browse the repository at this point in the history
  • Loading branch information
radekg committed Nov 4, 2018
1 parent 94d24fb commit 9524b06
Show file tree
Hide file tree
Showing 4 changed files with 123 additions and 33 deletions.
8 changes: 8 additions & 0 deletions README.md
Expand Up @@ -149,6 +149,10 @@ resource "aws_instance" "test_box" {
connect_timeout_seconds = 10
connection_attempts = 10
ssh_keyscan_timeout = 60
insecure_no_strict_host_key_checking = false
insecure_bastion_no_strict_host_key_checking = false
user_known_hosts_file = ""
bastion_user_known_hosts_file = ""
}
remote {
use_sudo = true
Expand Down Expand Up @@ -225,6 +229,10 @@ None of the boolean attributes can be specified in `defaults`. Neither `playbook
- `ansible_ssh_settings.connect_timeout_seconds`: SSH `ConnectTimeout`, default `10` seconds
- `ansible_ssh_settings.connection_attempts`: SSH `ConnectionAttempts`, default `10`
- `ansible_ssh_settings.ssh_keyscan_timeout`: when `ssh-keyscan` is used, how long to try fetching the host key until failing, default `60` seconds
- `ansible_ssh_settings.insecure_no_strict_host_key_checking`: if `true`, host key checking will be disabled when connecting to the target host, default `false`; when connecting via bastion, bastion will not execute any SSH keyscan
- `ansible_ssh_settings.insecure_bastion_no_strict_host_key_checking`: if `true`, host key checking will be disabled when connecting to the bastion host, default `false`
- `ansible_ssh_settings.user_known_hosts_file`: used only when `ansible_ssh_settings.insecure_no_strict_host_key_checking=false`; if set, the provided path will be used instead of an auto-generate known hosts file; when executing via bastion host, it allows the administrator to provide a known hosts file, no SSH keyscan will be executed on the bastion; default `empty string`
- `ansible_ssh_settings.bastion_user_known_hosts_file`: used only when `ansible_ssh_settings.insecure_bastion_no_strict_host_key_checking=false`; if set, the provided path will be used instead of an auto-generate known hosts file

#### Remote

Expand Down
51 changes: 33 additions & 18 deletions mode/mode_local.go
Expand Up @@ -100,28 +100,43 @@ func (v *LocalMode) Run(plays []*types.Play, ansibleSSHSettings *types.AnsibleSS
return err
}
defer sshClient.Close()
if target.hostKey() == "" {
v.o.Output(fmt.Sprintf("Host key not given, executing ssh-keyscan on bastion: %s@%s:%d",
if !ansibleSSHSettings.InsecureNoStrictHostKeyChecking() {
if ansibleSSHSettings.UserKnownHostsFile() == "" {
if target.hostKey() == "" {
v.o.Output(fmt.Sprintf("Host key not given, executing ssh-keyscan on bastion: %s@%s:%d",
bastion.user(),
bastion.host(),
bastion.port()))
targetKnownHosts, err := newBastionKeyScan(v.o,
sshClient,
target.host(),
target.port(),
ansibleSSHSettings.SSHKeyscanSeconds()).scan()
if err != nil {
return err
}
// ssh-keyscan gave us full lines with hosts, like this:
// <ip> ecdsa-sha2-nistp256 AAAA...
// <ip> ssh-rsa AAAAB...
// <ip> ssh-ed25519 AAAAC...
knownHosts = append(knownHosts, targetKnownHosts)
} else {
knownHosts = append(knownHosts, fmt.Sprintf("%s %s", target.host(), target.hostKey()))
}
} else {
v.o.Output(fmt.Sprintf("bastion %s@%s:%d will use '%s' as a user known hosts file",
bastion.user(),
bastion.host(),
bastion.port(),
ansibleSSHSettings.UserKnownHostsFile()))
}
knownHosts = append(knownHosts, fmt.Sprintf("%s %s", bastion.host(), bastion.hostKey()))
} else {
v.o.Output(fmt.Sprintf("target host StrictHostKeyChecking=no, not verifying host keys on bastion: %s@%s:%d",
bastion.user(),
bastion.host(),
bastion.port()))
targetKnownHosts, err := newBastionKeyScan(v.o,
sshClient,
target.host(),
target.port(),
ansibleSSHSettings.SSHKeyscanSeconds()).scan()
if err != nil {
return err
}
// ssh-keyscan gave us full lines with hosts, like this:
// <ip> ecdsa-sha2-nistp256 AAAA...
// <ip> ssh-rsa AAAAB...
// <ip> ssh-ed25519 AAAAC...
knownHosts = append(knownHosts, targetKnownHosts)
} else {
knownHosts = append(knownHosts, fmt.Sprintf("%s %s", target.host(), target.hostKey()))
}
knownHosts = append(knownHosts, fmt.Sprintf("%s %s", bastion.host(), bastion.hostKey()))
} else {
if target.hostKey() == "" {

Expand Down
64 changes: 58 additions & 6 deletions types/ansible_ssh_settings.go
Expand Up @@ -9,9 +9,13 @@ import (

// AnsibleSSHSettings represents Ansible process SSH settings.
type AnsibleSSHSettings struct {
connectTimeoutSeconds int
connectAttempts int
sshKeyscanSeconds int
connectTimeoutSeconds int
connectAttempts int
sshKeyscanSeconds int
insecureNoStrictHostKeyChecking bool
insecureBastionNoStrictHostKeyChecking bool
userKnownHostsFile string
bastionUserKnownHostsFile string
}

const (
Expand All @@ -20,9 +24,13 @@ const (
ansibleSSHDefaultConnectAttempts = 10
ansibleSSHDefaultSSHKeyscanSeconds = 60
// attribute names:
ansibleSSHAttributeConnectTimeoutSeconds = "connect_timeout_seconds"
ansibleSSHAttributeConnectAttempts = "connection_attempts"
ansibleSSHAttributeSSHKeyscanSeconds = "ssh_keyscan_timeout"
ansibleSSHAttributeConnectTimeoutSeconds = "connect_timeout_seconds"
ansibleSSHAttributeConnectAttempts = "connection_attempts"
ansibleSSHAttributeSSHKeyscanSeconds = "ssh_keyscan_timeout"
ansibleSSHAttributeInsecureNoStrictHostKeyChecking = "insecure_no_strict_host_key_checking"
ansibleSSHAttributeInsecureBastionNoStrictHostKeyChecking = "insecure_bastion_no_strict_host_key_checking"
ansibleSSHAttributeUserKnownHostsFile = "user_known_hosts_file"
ansibleSSHAttributeBastionUserKnownHostsFile = "bastion_user_known_hosts_file"
// environment variable names:
ansibleSSHEnvConnectTimeoutSeconds = "TF_PROVISIONER_ANSIBLE_SSH_CONNECT_TIMEOUT_SECONDS"
ansibleSSHEnvConnectAttempts = "TF_PROVISIONER_ANSIBLE_SSH_CONNECTION_ATTEMPTS"
Expand Down Expand Up @@ -66,6 +74,26 @@ func NewAnsibleSSHSettingsSchema() *schema.Schema {
return ansibleSSHDefaultSSHKeyscanSeconds, nil
},
},
ansibleSSHAttributeInsecureNoStrictHostKeyChecking: &schema.Schema{
Type: schema.TypeBool,
Optional: true,
Default: false,
},
ansibleSSHAttributeInsecureBastionNoStrictHostKeyChecking: &schema.Schema{
Type: schema.TypeBool,
Optional: true,
Default: false,
},
ansibleSSHAttributeUserKnownHostsFile: &schema.Schema{
Type: schema.TypeString,
Optional: true,
Default: "",
},
ansibleSSHAttributeBastionUserKnownHostsFile: &schema.Schema{
Type: schema.TypeString,
Optional: true,
Default: "",
},
},
},
}
Expand All @@ -83,6 +111,10 @@ func NewAnsibleSSHSettingsFromInterface(i interface{}, ok bool) *AnsibleSSHSetti
v.connectTimeoutSeconds = vals[ansibleSSHAttributeConnectTimeoutSeconds].(int)
v.connectAttempts = vals[ansibleSSHAttributeConnectAttempts].(int)
v.sshKeyscanSeconds = vals[ansibleSSHAttributeSSHKeyscanSeconds].(int)
v.insecureNoStrictHostKeyChecking = vals[ansibleSSHAttributeInsecureNoStrictHostKeyChecking].(bool)
v.insecureBastionNoStrictHostKeyChecking = vals[ansibleSSHAttributeInsecureBastionNoStrictHostKeyChecking].(bool)
v.userKnownHostsFile = vals[ansibleSSHAttributeUserKnownHostsFile].(string)
v.bastionUserKnownHostsFile = vals[ansibleSSHAttributeBastionUserKnownHostsFile].(string)
}
return v
}
Expand All @@ -101,3 +133,23 @@ func (v *AnsibleSSHSettings) ConnectAttempts() int {
func (v *AnsibleSSHSettings) SSHKeyscanSeconds() int {
return v.sshKeyscanSeconds
}

// InsecureNoStrictHostKeyChecking if true, SSH to the target host uses -o StrictHostKeyChecking=no.
func (v *AnsibleSSHSettings) InsecureNoStrictHostKeyChecking() bool {
return v.insecureNoStrictHostKeyChecking
}

// InsecureBastionNoStrictHostKeyChecking if true, SSH to the bastion host uses -o StrictHostKeyChecking=no.
func (v *AnsibleSSHSettings) InsecureBastionNoStrictHostKeyChecking() bool {
return v.insecureBastionNoStrictHostKeyChecking
}

// UserKnownHostsFile returns a path to the user known hosts file for the target host.
func (v *AnsibleSSHSettings) UserKnownHostsFile() string {
return v.userKnownHostsFile
}

// BastionUserKnownHostsFile returns a path to the user known hosts file for the bastion host.
func (v *AnsibleSSHSettings) BastionUserKnownHostsFile() string {
return v.bastionUserKnownHostsFile
}
33 changes: 24 additions & 9 deletions types/play.go
Expand Up @@ -496,18 +496,33 @@ func (v *Play) toCommandArguments(ansibleArgs LocalModeAnsibleArgs, ansibleSSHSe

sshExtraAgrsOptions := make([]string, 0)
sshExtraAgrsOptions = append(sshExtraAgrsOptions, fmt.Sprintf("-p %d", ansibleArgs.Port))
sshExtraAgrsOptions = append(sshExtraAgrsOptions, fmt.Sprintf("-o UserKnownHostsFile=%s", ansibleArgs.KnownHostsFile))
sshExtraAgrsOptions = append(sshExtraAgrsOptions, fmt.Sprintf("-o ConnectTimeout=%d", ansibleSSHSettings.ConnectTimeoutSeconds()))
sshExtraAgrsOptions = append(sshExtraAgrsOptions, fmt.Sprintf("-o ConnectionAttempts=%d", ansibleSSHSettings.ConnectAttempts()))
if ansibleSSHSettings.InsecureNoStrictHostKeyChecking() {
sshExtraAgrsOptions = append(sshExtraAgrsOptions, "-o StrictHostKeyChecking=no")
} else {
if ansibleSSHSettings.UserKnownHostsFile() != "" {
sshExtraAgrsOptions = append(sshExtraAgrsOptions, fmt.Sprintf("-o UserKnownHostsFile=%s", ansibleSSHSettings.UserKnownHostsFile()))
} else {
sshExtraAgrsOptions = append(sshExtraAgrsOptions, fmt.Sprintf("-o UserKnownHostsFile=%s", ansibleArgs.KnownHostsFile))
}
}
if ansibleArgs.BastionHost != "" {
sshExtraAgrsOptions = append(
sshExtraAgrsOptions,
fmt.Sprintf(
"-o ProxyCommand=\"ssh -p %d -W %%h:%%p %s@%s -o UserKnownHostsFile=%s\"",
ansibleArgs.BastionPort,
ansibleArgs.BastionUsername,
ansibleArgs.BastionHost,
ansibleArgs.KnownHostsFile))
proxyCommand := "-o ProxyCommand=\"ssh"
proxyCommand = fmt.Sprintf("%s -p %d", proxyCommand, ansibleArgs.BastionPort)
proxyCommand = fmt.Sprintf("%s -W %%h:%%p %s@%s", proxyCommand, ansibleArgs.BastionUsername, ansibleArgs.BastionHost)
if ansibleSSHSettings.InsecureBastionNoStrictHostKeyChecking() {
proxyCommand = fmt.Sprintf("%s -o StrictHostKeyChecking=no", proxyCommand)
} else {
if ansibleSSHSettings.BastionUserKnownHostsFile() != "" {
proxyCommand = fmt.Sprintf("%s -o UserKnownHostsFile=%s", proxyCommand, ansibleSSHSettings.BastionUserKnownHostsFile())
} else {
proxyCommand = fmt.Sprintf("%s -o UserKnownHostsFile=%s", proxyCommand, ansibleArgs.KnownHostsFile)
}
}
proxyCommand = fmt.Sprintf("%s\"", proxyCommand)

sshExtraAgrsOptions = append(sshExtraAgrsOptions, proxyCommand)
if ansibleArgs.BastionPemFile == "" && os.Getenv("SSH_AUTH_SOCK") != "" {
sshExtraAgrsOptions = append(sshExtraAgrsOptions, "-o ForwardAgent=yes")
}
Expand Down

0 comments on commit 9524b06

Please sign in to comment.