fix ValueString (wtf?) and add ssh bits
This commit is contained in:
parent
02c675c796
commit
07d47aba28
4
go.mod
4
go.mod
|
@ -8,6 +8,7 @@ require (
|
|||
github.com/hashicorp/terraform-plugin-go v0.14.3
|
||||
github.com/hashicorp/terraform-plugin-log v0.7.0
|
||||
github.com/hashicorp/terraform-plugin-sdk/v2 v2.24.1
|
||||
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d
|
||||
)
|
||||
|
||||
require (
|
||||
|
@ -59,7 +60,6 @@ require (
|
|||
github.com/vmihailenco/msgpack/v4 v4.3.12 // indirect
|
||||
github.com/vmihailenco/tagparser v0.1.1 // indirect
|
||||
github.com/zclconf/go-cty v1.12.1 // indirect
|
||||
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d // indirect
|
||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b // indirect
|
||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f // indirect
|
||||
golang.org/x/text v0.4.0 // indirect
|
||||
|
@ -67,4 +67,4 @@ require (
|
|||
google.golang.org/genproto v0.0.0-20200711021454-869866162049 // indirect
|
||||
google.golang.org/grpc v1.51.0 // indirect
|
||||
google.golang.org/protobuf v1.28.1 // indirect
|
||||
)
|
||||
)
|
||||
|
|
|
@ -47,12 +47,11 @@ func (p *SystemProvider) Configure(ctx context.Context, req provider.ConfigureRe
|
|||
var data SystemProviderModel
|
||||
|
||||
resp.Diagnostics.Append(req.Config.Get(ctx, &data)...)
|
||||
|
||||
if resp.Diagnostics.HasError() {
|
||||
return
|
||||
}
|
||||
|
||||
client, err := system.NewSystemManagerFromUri(data.ConnectionString.String())
|
||||
client, err := system.NewSystemManagerFromUri(data.ConnectionString.ValueString())
|
||||
if err != nil {
|
||||
resp.Diagnostics.AddError(
|
||||
"Unable to create System Manager API client",
|
||||
|
|
|
@ -0,0 +1,98 @@
|
|||
package system
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net"
|
||||
"net/url"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/crypto/ssh"
|
||||
"golang.org/x/crypto/ssh/agent"
|
||||
"golang.org/x/crypto/ssh/knownhosts"
|
||||
)
|
||||
|
||||
func getKnownHosts() (ssh.HostKeyCallback, error) {
|
||||
homedir, err := os.UserHomeDir()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("need homedir: %s", err)
|
||||
}
|
||||
return knownhosts.New(fmt.Sprintf("%s/.ssh/known_hosts", homedir))
|
||||
}
|
||||
|
||||
func expandHome(path string) string {
|
||||
if strings.HasPrefix(path, "~/") {
|
||||
dirname, _ := os.UserHomeDir()
|
||||
path = filepath.Join(dirname, path[2:])
|
||||
}
|
||||
return path
|
||||
}
|
||||
|
||||
func NewSSHConfigFromUrl(u *url.URL) (string, int, *ssh.ClientConfig, error) {
|
||||
port := 22
|
||||
portStr := u.Port()
|
||||
if portStr != "" {
|
||||
port, _ = strconv.Atoi(portStr)
|
||||
}
|
||||
|
||||
knownHostsCallback, err := getKnownHosts()
|
||||
if err != nil {
|
||||
return "", -1, nil, fmt.Errorf("couldn't load known hosts: %s", err)
|
||||
}
|
||||
|
||||
username := u.User.Username()
|
||||
password, _ := u.User.Password()
|
||||
sshConfig := &ssh.ClientConfig{
|
||||
User: username,
|
||||
HostKeyCallback: knownHostsCallback,
|
||||
}
|
||||
|
||||
extraArguments, err := url.ParseQuery(u.RawQuery)
|
||||
if err != nil {
|
||||
return "", -1, nil, err
|
||||
}
|
||||
|
||||
sshKeyPath, hasSshKeyPath := extraArguments["ssh_key_path"]
|
||||
agentValue, hasAgent := extraArguments["agent"]
|
||||
|
||||
if username != "" && hasSshKeyPath {
|
||||
log.Printf("using ssh key: %s", sshKeyPath)
|
||||
key, err := ioutil.ReadFile(expandHome(sshKeyPath[0]))
|
||||
if err != nil {
|
||||
return "", -1, nil, fmt.Errorf("read private key: %s", err)
|
||||
}
|
||||
signer, err := ssh.ParsePrivateKey(key)
|
||||
if err != nil {
|
||||
return "", -1, nil, fmt.Errorf("parse private key: %v", err)
|
||||
}
|
||||
sshConfig.Auth = []ssh.AuthMethod{
|
||||
ssh.PublicKeys(signer),
|
||||
}
|
||||
} else if hasAgent && agentValue[0] == "yes" {
|
||||
socket := os.Getenv("SSH_AUTH_SOCK")
|
||||
if socket == "" {
|
||||
return "", -1, nil, fmt.Errorf("requested ssh-agent but $SSH_AUTH_SOCK is unset")
|
||||
}
|
||||
conn, err := net.Dial("unix", socket)
|
||||
if err != nil {
|
||||
return "", -1, nil, fmt.Errorf("Failed to open SSH_AUTH_SOCK: %v", err)
|
||||
}
|
||||
agentClient := agent.NewClient(conn)
|
||||
sshConfig.Auth = []ssh.AuthMethod{
|
||||
ssh.PublicKeysCallback(agentClient.Signers),
|
||||
}
|
||||
} else if username != "" && password != "" {
|
||||
log.Printf("using ssh password")
|
||||
sshConfig.Auth = []ssh.AuthMethod{
|
||||
ssh.Password(password),
|
||||
}
|
||||
} else {
|
||||
return "", -1, nil, fmt.Errorf("no credential supplied, need user with password or ?ssh_key_path=<path> or ?agent=yes")
|
||||
}
|
||||
|
||||
return u.Host, port, sshConfig, nil
|
||||
}
|
|
@ -1,5 +1,11 @@
|
|||
package system
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"golang.org/x/crypto/ssh"
|
||||
"net/url"
|
||||
)
|
||||
|
||||
// SystemManager providers the functionality to interrogate / interact with target systems
|
||||
type SystemManager struct {
|
||||
connection *SystemConnection
|
||||
|
@ -21,8 +27,27 @@ func (s *SystemManager) Test() error {
|
|||
|
||||
// SystemConnection provides an unopinionated interface for interacting with remote systems on a low level
|
||||
type SystemConnection struct {
|
||||
client *ssh.Client
|
||||
}
|
||||
|
||||
func NewSystemConnectionFromUri(uri string) (*SystemConnection, error) {
|
||||
return nil, nil
|
||||
|
||||
//return nil, fmt.Errorf("using uri: '%s'", uri)
|
||||
|
||||
sshUrl, err := url.Parse(uri)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid ssh uri: %s", err)
|
||||
}
|
||||
|
||||
sshHost, sshPort, sshConfig, err := NewSSHConfigFromUrl(sshUrl)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("ssh failed: %s", err)
|
||||
}
|
||||
sshClient, err := ssh.Dial("tcp", fmt.Sprintf("%s:%d", sshHost, sshPort), sshConfig)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("dial failed: %s", err)
|
||||
}
|
||||
return &SystemConnection{
|
||||
client: sshClient,
|
||||
}, nil
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue