summaryrefslogtreecommitdiff
path: root/pkg/bindings
diff options
context:
space:
mode:
Diffstat (limited to 'pkg/bindings')
-rw-r--r--pkg/bindings/bindings.go43
-rw-r--r--pkg/bindings/connection.go98
2 files changed, 15 insertions, 126 deletions
diff --git a/pkg/bindings/bindings.go b/pkg/bindings/bindings.go
index 94f7a45d0..ae5610b0f 100644
--- a/pkg/bindings/bindings.go
+++ b/pkg/bindings/bindings.go
@@ -8,13 +8,7 @@
package bindings
import (
- "errors"
- "fmt"
- "io"
- "os"
-
"github.com/blang/semver"
- "golang.org/x/crypto/ssh/terminal"
)
var (
@@ -30,40 +24,3 @@ var (
// APIVersion - podman will fail to run if this value is wrong
APIVersion = semver.MustParse("1.0.0")
)
-
-// readPassword prompts for a secret and returns value input by user from stdin
-// Unlike terminal.ReadPassword(), $(echo $SECRET | podman...) is supported.
-// Additionally, all input after `<secret>/n` is queued to podman command.
-func readPassword(prompt string) (pw []byte, err error) {
- fd := int(os.Stdin.Fd())
- if terminal.IsTerminal(fd) {
- fmt.Fprint(os.Stderr, prompt)
- pw, err = terminal.ReadPassword(fd)
- fmt.Fprintln(os.Stderr)
- return
- }
-
- var b [1]byte
- for {
- n, err := os.Stdin.Read(b[:])
- // terminal.ReadPassword discards any '\r', so we do the same
- if n > 0 && b[0] != '\r' {
- if b[0] == '\n' {
- return pw, nil
- }
- pw = append(pw, b[0])
- // limit size, so that a wrong input won't fill up the memory
- if len(pw) > 1024 {
- err = errors.New("password too long, 1024 byte limit")
- }
- }
- if err != nil {
- // terminal.ReadPassword accepts EOF-terminated passwords
- // if non-empty, so we do the same
- if err == io.EOF && len(pw) > 0 {
- err = nil
- }
- return pw, err
- }
- }
-}
diff --git a/pkg/bindings/connection.go b/pkg/bindings/connection.go
index a9c61e5ae..584aa55c1 100644
--- a/pkg/bindings/connection.go
+++ b/pkg/bindings/connection.go
@@ -1,28 +1,24 @@
package bindings
import (
- "bufio"
"context"
"fmt"
"io"
- "io/ioutil"
"net"
"net/http"
"net/url"
"os"
- "path/filepath"
"strconv"
"strings"
- "sync"
"time"
"github.com/blang/semver"
+ "github.com/containers/libpod/pkg/terminal"
jsoniter "github.com/json-iterator/go"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
"golang.org/x/crypto/ssh"
"golang.org/x/crypto/ssh/agent"
- "k8s.io/client-go/util/homedir"
)
var (
@@ -31,8 +27,6 @@ var (
Host: "d",
Path: "/v" + APIVersion.String() + "/libpod",
}
- passPhrase []byte
- phraseSync sync.Once
)
type APIResponse struct {
@@ -77,7 +71,7 @@ func NewConnection(ctx context.Context, uri string) (context.Context, error) {
// For example tcp://localhost:<port>
// or unix:///run/podman/podman.sock
// or ssh://<user>@<host>[:port]/run/podman/podman.sock?secure=True
-func NewConnectionWithIdentity(ctx context.Context, uri string, passPhrase string, identities ...string) (context.Context, error) {
+func NewConnectionWithIdentity(ctx context.Context, uri string, identity string) (context.Context, error) {
var (
err error
secure bool
@@ -86,11 +80,12 @@ func NewConnectionWithIdentity(ctx context.Context, uri string, passPhrase strin
uri = v
}
- if v, found := os.LookupEnv("CONTAINER_SSHKEY"); found && len(identities) == 0 {
- identities = append(identities, v)
+ if v, found := os.LookupEnv("CONTAINER_SSHKEY"); found && len(identity) == 0 {
+ identity = v
}
- if v, found := os.LookupEnv("CONTAINER_PASSPHRASE"); found && passPhrase == "" {
+ passPhrase := ""
+ if v, found := os.LookupEnv("CONTAINER_PASSPHRASE"); found {
passPhrase = v
}
@@ -98,7 +93,6 @@ func NewConnectionWithIdentity(ctx context.Context, uri string, passPhrase strin
if err != nil {
return nil, errors.Wrapf(err, "Value of CONTAINER_HOST is not a valid url: %s", uri)
}
- // TODO Fill in missing defaults for _url...
// Now we setup the http Client to use the connection above
var connection Connection
@@ -108,7 +102,7 @@ func NewConnectionWithIdentity(ctx context.Context, uri string, passPhrase strin
if err != nil {
secure = false
}
- connection, err = sshClient(_url, secure, passPhrase, identities...)
+ connection, err = sshClient(_url, secure, passPhrase, identity)
case "unix":
if !strings.HasPrefix(uri, "unix:///") {
// autofix unix://path_element vs unix:///path_element
@@ -122,7 +116,7 @@ func NewConnectionWithIdentity(ctx context.Context, uri string, passPhrase strin
}
connection = tcpClient(_url)
default:
- return nil, errors.Errorf("'%s' is not a supported schema", _url.Scheme)
+ return nil, errors.Errorf("unable to create connection. %q is not a supported schema", _url.Scheme)
}
if err != nil {
return nil, errors.Wrapf(err, "Failed to create %sClient", _url.Scheme)
@@ -185,16 +179,14 @@ func pingNewConnection(ctx context.Context) error {
return errors.Errorf("ping response was %q", response.StatusCode)
}
-func sshClient(_url *url.URL, secure bool, passPhrase string, identities ...string) (Connection, error) {
+func sshClient(_url *url.URL, secure bool, passPhrase string, identity string) (Connection, error) {
authMethods := []ssh.AuthMethod{}
- for _, i := range identities {
- auth, err := publicKey(i, []byte(passPhrase))
- if err != nil {
- fmt.Fprint(os.Stderr, errors.Wrapf(err, "failed to parse identity %q", i).Error()+"\n")
- continue
- }
- authMethods = append(authMethods, auth)
+ auth, err := terminal.PublicKey(identity, []byte(passPhrase))
+ if err != nil {
+ return Connection{}, errors.Wrapf(err, "failed to parse identity %q", identity)
}
+ logrus.Debugf("public key signer enabled for identity %q", identity)
+ authMethods = append(authMethods, auth)
if sock, found := os.LookupEnv("SSH_AUTH_SOCK"); found {
logrus.Debugf("Found SSH_AUTH_SOCK %q, ssh-agent signer enabled", sock)
@@ -213,7 +205,7 @@ func sshClient(_url *url.URL, secure bool, passPhrase string, identities ...stri
callback := ssh.InsecureIgnoreHostKey()
if secure {
- key := hostKey(_url.Hostname())
+ key := terminal.HostKey(_url.Hostname())
if key != nil {
callback = ssh.FixedHostKey(key)
}
@@ -339,63 +331,3 @@ func (h *APIResponse) IsClientError() bool {
func (h *APIResponse) IsServerError() bool {
return h.Response.StatusCode/100 == 5
}
-
-func publicKey(path string, passphrase []byte) (ssh.AuthMethod, error) {
- key, err := ioutil.ReadFile(path)
- if err != nil {
- return nil, err
- }
-
- signer, err := ssh.ParsePrivateKey(key)
- if err != nil {
- if _, ok := err.(*ssh.PassphraseMissingError); !ok {
- return nil, err
- }
- if len(passphrase) == 0 {
- phraseSync.Do(promptPassphrase)
- passphrase = passPhrase
- }
- signer, err = ssh.ParsePrivateKeyWithPassphrase(key, passphrase)
- if err != nil {
- return nil, err
- }
- }
- return ssh.PublicKeys(signer), nil
-}
-
-func promptPassphrase() {
- phrase, err := readPassword("Key Passphrase: ")
- if err != nil {
- passPhrase = []byte{}
- return
- }
- passPhrase = phrase
-}
-
-func hostKey(host string) ssh.PublicKey {
- // parse OpenSSH known_hosts file
- // ssh or use ssh-keyscan to get initial key
- knownHosts := filepath.Join(homedir.HomeDir(), ".ssh", "known_hosts")
- fd, err := os.Open(knownHosts)
- if err != nil {
- logrus.Error(err)
- return nil
- }
-
- scanner := bufio.NewScanner(fd)
- for scanner.Scan() {
- _, hosts, key, _, _, err := ssh.ParseKnownHosts(scanner.Bytes())
- if err != nil {
- logrus.Errorf("Failed to parse known_hosts: %s", scanner.Text())
- continue
- }
-
- for _, h := range hosts {
- if h == host {
- return key
- }
- }
- }
-
- return nil
-}