Skip to content

Commit

Permalink
port --secret and --ssh support (#323)
Browse files Browse the repository at this point in the history
* port --secret and --ssh support

* generate ssh key for tests
  • Loading branch information
alefray authored Feb 12, 2021
1 parent 91d49f9 commit 132b56c
Show file tree
Hide file tree
Showing 4 changed files with 121 additions and 2 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ PKG := github.com/genuinetools/$(NAME)
CGO_ENABLED := 1

# Set any default go build tags
BUILDTAGS ?= seccomp osusergo
BUILDTAGS ?= seccomp osusergo dfrunmount dfsecrets dfssh

include basic.mk

Expand Down
28 changes: 28 additions & 0 deletions build.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import (
"github.com/moby/buildkit/identity"
"github.com/moby/buildkit/session"
"github.com/moby/buildkit/session/filesync"
"github.com/moby/buildkit/session/sshforward/sshprovider"
"github.com/moby/buildkit/util/appcontext"
"github.com/moby/buildkit/util/progress/progressui"
"github.com/spf13/cobra"
Expand All @@ -45,6 +46,8 @@ func newBuildCommand() *cobra.Command {
tags: newListValue().WithValidator(validateTag),
buildArgs: newListValue(),
labels: newListValue(),
secrets: newListValue(),
ssh: newListValue(),
platforms: newListValue(),
cacheFrom: newListValue(),
cacheTo: newListValue(),
Expand All @@ -70,6 +73,8 @@ func newBuildCommand() *cobra.Command {
fs.Var(build.platforms, "platform", "Set platforms for which the image should be built")
fs.Var(build.buildArgs, "build-arg", "Set build-time variables")
fs.Var(build.labels, "label", "Set metadata for an image")
fs.Var(build.secrets, "secret", "Secret value exposed to the build. Format id=secretname,src=filepath")
fs.Var(build.ssh, "ssh", "Allow forwarding SSH agent to the builder. Format default|<id>[=<socket>|<key>[,<key>]]")
fs.BoolVar(&build.noConsole, "no-console", false, "Use non-console progress UI")
fs.BoolVar(&build.noCache, "no-cache", false, "Do not use cache when building the image")
fs.StringVarP(&build.output, "output", "o", "", "BuildKit output specification (e.g. type=tar,dest=build.tar)")
Expand All @@ -82,6 +87,8 @@ type buildCommand struct {
buildArgs *listValue
dockerfilePath string
labels *listValue
secrets *listValue
ssh *listValue
target string
tags *listValue
platforms *listValue
Expand Down Expand Up @@ -257,6 +264,27 @@ func (cmd *buildCommand) Run(args []string) (err error) {
}
}

// parse secrets (--secret)
if cmd.secrets.Len() > 0 {
secretProvider, err := build.ParseSecret(cmd.secrets.GetAll())
if err != nil {
return fmt.Errorf("could not parse secrets: %v", err)
}
sess.Allow(secretProvider)
}
// parse ssh (--ssh)
if cmd.ssh.Len() > 0 {
configs, err := build.ParseSSH(cmd.ssh.GetAll())
if err != nil {
return fmt.Errorf("could not parse ssh: %v", err)
}
sp, err := sshprovider.NewSSHAgentProvider(configs)
if err != nil {
return err
}
sess.Allow(sp)
}

ch := make(chan *controlapi.StatusResponse)
eg.Go(func() error {
return sess.Run(ctx, sessDialer)
Expand Down
91 changes: 91 additions & 0 deletions build_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@ package main
import (
"archive/tar"
"bytes"
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"encoding/pem"
"fmt"
"io"
"io/ioutil"
Expand Down Expand Up @@ -134,6 +138,93 @@ func TestBuildLabels(t *testing.T) {
}
}

func TestBuildMultipleSecrets(t *testing.T) {
name := "testbuildmustiplesecrets"

args := []string{"build", "-t", name, "--secret", "id=s1,src=/dev/null", "--secret", "id=s2,src=/dev/null", "-"}
_, err := doRun(args, withDockerfile(`
FROM alpine
RUN --mount=type=secret,id=s1,dst=/tmp/secret1 \
--mount=type=secret,id=s2,dst=/tmp/secret2 \
cat /tmp/secret1 /tmp/secret2
`))

if err != nil {
t.Logf("img %v failed unexpectedly: %v", args, err)
t.FailNow()
}
}

// generatePrivateKey creates a RSA Private Key of specified byte size in PEM format
func generatePrivateKeyPEM(bitSize int) ([]byte, error) {
// Private Key generation
privateKey, err := rsa.GenerateKey(rand.Reader, bitSize)
if err != nil {
return nil, err
}

// Validate Private Key
err = privateKey.Validate()
if err != nil {
return nil, err
}

// Get ASN.1 DER format
privDER := x509.MarshalPKCS1PrivateKey(privateKey)

// pem.Block
privBlock := pem.Block{
Type: "RSA PRIVATE KEY",
Headers: nil,
Bytes: privDER,
}

// Private key in PEM format
privatePEM := pem.EncodeToMemory(&privBlock)

return privatePEM, nil
}

func TestBuildSsh(t *testing.T) {
name := "testbuildssh"

tmpf, err := ioutil.TempFile("", "id_rsa_test")
if err != nil {
t.Fatalf("creating temporary file for ssh private key failed: %v", err)
}

defer os.Remove(tmpf.Name())

err = tmpf.Chmod(0600)
if err != nil {
t.Fatalf("changing file mode failed: %v", err)
}

privatePEM, err := generatePrivateKeyPEM(4096)
if err != nil {
t.Fatalf("generating private key failed: %v", err)
}

_, err = tmpf.Write(privatePEM)
if err != nil {
t.Fatalf("writing private key to temporary file failed: %v", err)
}

args := []string{"build", "-t", name, "--ssh", fmt.Sprintf("key=%s", tmpf.Name()), "-"}
_, err = doRun(args, withDockerfile(`
FROM alpine
RUN apk add openssh-client
RUN test -z "$SSH_AUTH_SOCK" && echo "Socket is absent as expected"
RUN --mount=type=ssh,id=absent ssh-add -l; test 0 -ne "$?"
RUN --mount=type=ssh,id=key ssh-add -l; test 0 -eq "$?"
`))

if err != nil {
t.Logf("img %v failed unexpectedly: %v", args, err)
t.FailNow()
}
}

func TestBuildMultipleTags(t *testing.T) {
names := []string{"testbuildmultipletags", "testbuildmultipletags:v1", "testbuildmultipletagsv1"}
args := []string{"build"}
Expand Down
2 changes: 1 addition & 1 deletion main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ func init() {
// deletes it after the tests have been run.
func TestMain(m *testing.M) {
os.Unsetenv("IMG_RUNNING_TESTS")
args := []string{"build", "-o", "testimg" + exeSuffix}
args := []string{"build", "-tags", "dfrunmount dfsecrets dfssh", "-o", "testimg" + exeSuffix}
out, err := exec.Command("go", args...).CombinedOutput()
if err != nil {
fmt.Fprintf(os.Stderr, "building testimg failed: %v\n%s\n", err, out)
Expand Down

0 comments on commit 132b56c

Please sign in to comment.