0
0
mirror of https://github.com/bpg/terraform-provider-proxmox.git synced 2025-07-01 11:02:59 +00:00

feat(provider): add support for ssh-agent on Windows (#1270)

* feat(provider): add support for `ssh-agent` on Windows

Signed-off-by: Brian Karshick <Sparta142@users.noreply.github.com>
This commit is contained in:
Brian 2024-05-09 23:00:44 -04:00 committed by GitHub
parent 6ae9b581df
commit ccf4834c16
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 61 additions and 11 deletions

View File

@ -116,9 +116,11 @@ This allows the provider to use the SSH agent configured by the user, and to sup
You can find more details on the SSH Agent [here](https://www.digitalocean.com/community/tutorials/ssh-essentials-working-with-ssh-servers-clients-and-keys#adding-your-ssh-keys-to-an-ssh-agent-to-avoid-typing-the-passphrase). You can find more details on the SSH Agent [here](https://www.digitalocean.com/community/tutorials/ssh-essentials-working-with-ssh-servers-clients-and-keys#adding-your-ssh-keys-to-an-ssh-agent-to-avoid-typing-the-passphrase).
The SSH agent authentication takes precedence over the `private_key` and `password` authentication. The SSH agent authentication takes precedence over the `private_key` and `password` authentication.
-> By default on Windows, the provider will assume the SSH agent is at `\\.\pipe\openssh-ssh-agent`.
### SSH Private Key ### SSH Private Key
In some cases where SSH agent is not available, for example when running Terraform from a Windows machine, or when using a CI/CD pipeline that does not support SSH agent forwarding, In some cases where SSH agent is not available, for example when using a CI/CD pipeline that does not support SSH agent forwarding,
you can use the `private_key` argument in the `ssh` block (or alternatively `PROXMOX_VE_SSH_PRIVATE_KEY` environment variable) to provide the private key for the SSH connection. you can use the `private_key` argument in the `ssh` block (or alternatively `PROXMOX_VE_SSH_PRIVATE_KEY` environment variable) to provide the private key for the SSH connection.
The private key mut not be encrypted, and must be in PEM format. The private key mut not be encrypted, and must be in PEM format.

1
go.mod
View File

@ -5,6 +5,7 @@ go 1.22
toolchain go1.22.3 toolchain go1.22.3
require ( require (
github.com/Microsoft/go-winio v0.6.2
github.com/avast/retry-go/v4 v4.6.0 github.com/avast/retry-go/v4 v4.6.0
github.com/brianvoe/gofakeit/v7 v7.0.3 github.com/brianvoe/gofakeit/v7 v7.0.3
github.com/google/go-cmp v0.6.0 github.com/google/go-cmp v0.6.0

4
go.sum
View File

@ -1,7 +1,7 @@
dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk= dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk=
dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk=
github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow= github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
github.com/ProtonMail/go-crypto v1.1.0-alpha.0 h1:nHGfwXmFvJrSR9xu8qL7BkO4DqTHXE9N5vPhgY2I+j0= github.com/ProtonMail/go-crypto v1.1.0-alpha.0 h1:nHGfwXmFvJrSR9xu8qL7BkO4DqTHXE9N5vPhgY2I+j0=
github.com/ProtonMail/go-crypto v1.1.0-alpha.0/go.mod h1:rA3QumHc/FZ8pAHreoekgiAbzpNsfQAosU5td4SnOrE= github.com/ProtonMail/go-crypto v1.1.0-alpha.0/go.mod h1:rA3QumHc/FZ8pAHreoekgiAbzpNsfQAosU5td4SnOrE=
github.com/agext/levenshtein v1.2.3 h1:YB2fHEn0UJagG8T1rrWknE3ZQzWM06O8AMAatNn7lmo= github.com/agext/levenshtein v1.2.3 h1:YB2fHEn0UJagG8T1rrWknE3ZQzWM06O8AMAatNn7lmo=

View File

@ -78,9 +78,13 @@ func NewClient(
socks5Server string, socks5Username string, socks5Password string, socks5Server string, socks5Username string, socks5Password string,
nodeResolver NodeResolver, nodeResolver NodeResolver,
) (Client, error) { ) (Client, error) {
if agent && runtime.GOOS != "linux" && runtime.GOOS != "darwin" && runtime.GOOS != "freebsd" { if agent &&
runtime.GOOS != "linux" &&
runtime.GOOS != "darwin" &&
runtime.GOOS != "freebsd" &&
runtime.GOOS != "windows" {
return nil, errors.New( return nil, errors.New(
"the ssh agent flag is only supported on POSIX systems, please set it to 'false'" + "the ssh agent flag is only supported on POSIX and Windows systems, please set it to 'false'" +
" or remove it from your provider configuration", " or remove it from your provider configuration",
) )
} }
@ -531,12 +535,7 @@ func (c *client) createSSHClientAgent(
kh knownhosts.HostKeyCallback, kh knownhosts.HostKeyCallback,
sshHost string, sshHost string,
) (*ssh.Client, error) { ) (*ssh.Client, error) {
if c.agentSocket == "" { conn, err := dialSocket(c.agentSocket)
return nil, errors.New("failed connecting to SSH agent socket: the socket file is not defined, " +
"authentication will fall back to password")
}
conn, err := net.Dial("unix", c.agentSocket)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed connecting to SSH auth socket '%s': %w", c.agentSocket, err) return nil, fmt.Errorf("failed connecting to SSH auth socket '%s': %w", c.agentSocket, err)
} }

View File

@ -0,0 +1,24 @@
//go:build !windows
package ssh
import (
"errors"
"fmt"
"net"
)
// dialSocket dials a Unix domain socket.
func dialSocket(address string) (net.Conn, error) {
if address == "" {
return nil, errors.New("failed connecting to SSH agent socket: the socket file is not defined, " +
"authentication will fall back to password")
}
conn, err := net.Dial("unix", address)
if err != nil {
return nil, fmt.Errorf("error dialing unix socket: %w", err)
}
return conn, nil
}

View File

@ -0,0 +1,24 @@
//go:build windows
package ssh
import (
"fmt"
"net"
"github.com/Microsoft/go-winio"
)
// dialSocket dials a Windows named pipe. If address is empty, it dials the default ssh-agent pipe.
func dialSocket(address string) (net.Conn, error) {
if address == "" {
address = `\\.\pipe\openssh-ssh-agent`
}
conn, err := winio.DialPipe(address, nil)
if err != nil {
return nil, fmt.Errorf("error dialing named pipe: %w", err)
}
return conn, nil
}