ssh agent support

This commit is contained in:
TP Honey
2023-01-17 14:12:59 +00:00
parent 84d8664c70
commit d70414892d
5 changed files with 52 additions and 51 deletions

2
.gitignore vendored
View File

@@ -1,3 +1,5 @@
release release
coverage.out coverage.out
vendor vendor
.vscode/
Dockerfile

View File

@@ -274,10 +274,10 @@ func main() {
Usage: "platform value to pass to docker", Usage: "platform value to pass to docker",
EnvVar: "PLUGIN_PLATFORM", EnvVar: "PLUGIN_PLATFORM",
}, },
cli.StringSliceFlag{ cli.StringFlag{
Name: "ssh-agent", Name: "ssh-agent-key",
Usage: "mount ssh agent", Usage: "ssh agent key to use",
EnvVar: "PLUGIN_SSH_AGENT", EnvVar: "PLUGIN_SSH_AGENT_KEY",
}, },
} }
@@ -323,7 +323,7 @@ func run(c *cli.Context) error {
AddHost: c.StringSlice("add-host"), AddHost: c.StringSlice("add-host"),
Quiet: c.Bool("quiet"), Quiet: c.Bool("quiet"),
Platform: c.String("platform"), Platform: c.String("platform"),
SSHAgent: c.StringSlice("ssh-agent"), SSHAgentKey: c.String("ssh-agent-key"),
}, },
Daemon: docker.Daemon{ Daemon: docker.Daemon{
Registry: c.String("docker.registry"), Registry: c.String("docker.registry"),

View File

@@ -1,9 +1,10 @@
//go:build !windows
// +build !windows // +build !windows
package docker package docker
import ( import (
"io/ioutil" "io"
"os" "os"
) )
@@ -17,8 +18,8 @@ func (p Plugin) startDaemon() {
cmd.Stdout = os.Stdout cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr cmd.Stderr = os.Stderr
} else { } else {
cmd.Stdout = ioutil.Discard cmd.Stdout = io.Discard
cmd.Stderr = ioutil.Discard cmd.Stderr = io.Discard
} }
go func() { go func() {
trace(cmd) trace(cmd)

View File

@@ -1,10 +1,7 @@
package docker package docker
import ( import (
"encoding/base64"
"fmt" "fmt"
"io/ioutil"
"log"
"os" "os"
"os/exec" "os/exec"
"path/filepath" "path/filepath"
@@ -13,11 +10,6 @@ import (
"time" "time"
) )
const (
SSHAgentSockPath = "/tmp/drone-ssh-agent-sock"
SSHPrivateKeyFromEnv = "SSH_KEY"
)
type ( type (
// Daemon defines Docker daemon parameters. // Daemon defines Docker daemon parameters.
Daemon struct { Daemon struct {
@@ -71,7 +63,8 @@ type (
AddHost []string // Docker build add-host AddHost []string // Docker build add-host
Quiet bool // Docker build quiet Quiet bool // Docker build quiet
Platform string // Docker build platform Platform string // Docker build platform
SSHAgent []string // Docker build ssh SSHAgentKey string // Docker build ssh agent key
SSHKeyPath string // Docker build ssh key path
} }
// Plugin defines the Docker plugin parameters. // Plugin defines the Docker plugin parameters.
@@ -153,7 +146,7 @@ func (p Plugin) Exec() error {
os.MkdirAll(dockerHome, 0600) os.MkdirAll(dockerHome, 0600)
path := filepath.Join(dockerHome, "config.json") path := filepath.Join(dockerHome, "config.json")
err := ioutil.WriteFile(path, []byte(p.Login.Config), 0600) err := os.WriteFile(path, []byte(p.Login.Config), 0600)
if err != nil { if err != nil {
return fmt.Errorf("Error writing config.json: %s", err) return fmt.Errorf("Error writing config.json: %s", err)
} }
@@ -189,10 +182,12 @@ func (p Plugin) Exec() error {
} }
// setup for using ssh agent (https://docs.docker.com/develop/develop-images/build_enhancements/#using-ssh-to-access-private-data-in-builds) // setup for using ssh agent (https://docs.docker.com/develop/develop-images/build_enhancements/#using-ssh-to-access-private-data-in-builds)
if p.Build.SSHAgentKey != "" {
if len(p.Build.SSHAgent) > 0 { var sshErr error
fmt.Printf("ssh agent set to \"%s\"\n", p.Build.SSHAgent) p.Build.SSHKeyPath, sshErr = writeSSHPrivateKey(p.Build.SSHAgentKey)
cmds = append(cmds, commandSSHAgentForwardingSetup(p.Build)...) if sshErr != nil {
return sshErr
}
} }
cmds = append(cmds, commandBuild(p.Build)) // docker build cmds = append(cmds, commandBuild(p.Build)) // docker build
@@ -344,8 +339,8 @@ func commandBuild(build Build) *exec.Cmd {
if build.Platform != "" { if build.Platform != "" {
args = append(args, "--platform", build.Platform) args = append(args, "--platform", build.Platform)
} }
for _, sshagent := range build.SSHAgent { if build.SSHKeyPath != "" {
args = append(args, "--ssh", sshagent) args = append(args, "--ssh", build.SSHKeyPath)
} }
if build.AutoLabel { if build.AutoLabel {
@@ -373,7 +368,7 @@ func commandBuild(build Build) *exec.Cmd {
} }
// we need to enable buildkit, for secret support and ssh agent support // we need to enable buildkit, for secret support and ssh agent support
if build.Secret != "" || len(build.SecretEnvs) > 0 || len(build.SecretFiles) > 0 || len(build.SSHAgent) > 0 { if build.Secret != "" || len(build.SecretEnvs) > 0 || len(build.SecretFiles) > 0 || build.SSHAgentKey != "" {
os.Setenv("DOCKER_BUILDKIT", "1") os.Setenv("DOCKER_BUILDKIT", "1")
} }
return exec.Command(dockerExe, args...) return exec.Command(dockerExe, args...)
@@ -526,38 +521,21 @@ func commandRmi(tag string) *exec.Cmd {
return exec.Command(dockerExe, "rmi", tag) return exec.Command(dockerExe, "rmi", tag)
} }
func commandSSHAgentForwardingSetup(build Build) []*exec.Cmd { func writeSSHPrivateKey(key string) (path string, err error) {
cmds := make([]*exec.Cmd, 0)
if err := writeSSHPrivateKey(); err != nil {
log.Fatalf("unable to setup ssh agent forwarding: %s", err)
}
os.Setenv("SSH_AUTH_SOCK", SSHAgentSockPath)
cmds = append(cmds, exec.Command("ssh-agent", "-a", SSHAgentSockPath))
cmds = append(cmds, exec.Command("ssh-add"))
return cmds
}
func writeSSHPrivateKey() error {
privateKeyBase64 := os.Getenv(SSHPrivateKeyFromEnv)
if privateKeyBase64 == "" {
return fmt.Errorf("%s must be defined and contain the base64 encoded private key to use for ssh agent forwarding", SSHPrivateKeyFromEnv)
}
var err error
privateKey, err := base64.StdEncoding.DecodeString(privateKeyBase64)
if err != nil {
return fmt.Errorf("unable to base64 decode private key")
}
home, err := os.UserHomeDir() home, err := os.UserHomeDir()
if err != nil { if err != nil {
return fmt.Errorf("unable to determine home directory: %s", err) return "", fmt.Errorf("unable to determine home directory: %s", err)
} }
if err := os.MkdirAll(filepath.Join(home, ".ssh"), 0700); err != nil { if err := os.MkdirAll(filepath.Join(home, ".ssh"), 0700); err != nil {
return fmt.Errorf("unable to create .ssh directory: %s", err) return "", fmt.Errorf("unable to create .ssh directory: %s", err)
} }
if err := os.WriteFile(filepath.Join(home, ".ssh", "id_rsa"), privateKey, 0400); err != nil { pathToKey := filepath.Join(home, ".ssh", "id_rsa")
return fmt.Errorf("unable to write ssh key: %s", err) if err := os.WriteFile(pathToKey, []byte(key), 0400); err != nil {
return "", fmt.Errorf("unable to write ssh key %s: %s", pathToKey, err)
} }
return nil path = fmt.Sprintf("default=%s", pathToKey)
return path, nil
} }
// trace writes each command to stdout with the command wrapped in an xml // trace writes each command to stdout with the command wrapped in an xml

View File

@@ -135,6 +135,26 @@ func TestCommandBuild(t *testing.T) {
"test/platform", "test/platform",
), ),
}, },
{
name: "ssh agent",
build: Build{
Name: "plugins/drone-docker:latest",
Dockerfile: "Dockerfile",
Context: ".",
SSHKeyPath: "id_rsa=/root/.ssh/id_rsa",
},
want: exec.Command(
dockerExe,
"build",
"--rm=true",
"-f",
"Dockerfile",
"-t",
"plugins/drone-docker:latest",
".",
"--ssh id_rsa=/root/.ssh/id_rsa",
),
},
} }
for _, tc := range tcs { for _, tc := range tcs {