Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement support for RUN --network=none|default|host #1141

Merged
merged 9 commits into from
Sep 5, 2019
13 changes: 12 additions & 1 deletion frontend/dockerfile/dockerfile2llb/convert.go
Original file line number Diff line number Diff line change
Expand Up @@ -640,10 +640,21 @@ func dispatchRun(d *dispatchState, c *instructions.RunCommand, proxy *llb.ProxyE
}
opt = append(opt, runMounts...)

err = dispatchRunSecurity(d, c)
securityOpt, err := dispatchRunSecurity(c)
if err != nil {
return err
}
if securityOpt != nil {
opt = append(opt, securityOpt)
}

networkOpt, err := dispatchRunNetwork(c)
if err != nil {
return err
}
if networkOpt != nil {
opt = append(opt, networkOpt)
}

shlex := *dopt.shlex
shlex.RawQuotes = true
Expand Down
12 changes: 12 additions & 0 deletions frontend/dockerfile/dockerfile2llb/convert_norunnetwork.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// +build !dfrunnetwork

package dockerfile2llb

import (
"github.com/moby/buildkit/client/llb"
"github.com/moby/buildkit/frontend/dockerfile/instructions"
)

func dispatchRunNetwork(c *instructions.RunCommand) (llb.RunOption, error) {
return nil, nil
}
5 changes: 3 additions & 2 deletions frontend/dockerfile/dockerfile2llb/convert_norunsecurity.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@
package dockerfile2llb

import (
"github.com/moby/buildkit/client/llb"
"github.com/moby/buildkit/frontend/dockerfile/instructions"
)

func dispatchRunSecurity(d *dispatchState, c *instructions.RunCommand) error {
return nil
func dispatchRunSecurity(c *instructions.RunCommand) (llb.RunOption, error) {
return nil, nil
}
26 changes: 26 additions & 0 deletions frontend/dockerfile/dockerfile2llb/convert_runnetwork.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// +build dfrunnetwork

package dockerfile2llb

import (
"github.com/pkg/errors"

"github.com/moby/buildkit/client/llb"
"github.com/moby/buildkit/frontend/dockerfile/instructions"
"github.com/moby/buildkit/solver/pb"
)

func dispatchRunNetwork(c *instructions.RunCommand) (llb.RunOption, error) {
network := instructions.GetNetwork(c)

switch network {
case instructions.NetworkDefault:
return nil, nil
case instructions.NetworkNone:
return llb.Network(pb.NetMode_NONE), nil
case instructions.NetworkHost:
return llb.Network(pb.NetMode_HOST), nil
default:
return nil, errors.Errorf("unsupported network mode %q", network)
}
}
21 changes: 9 additions & 12 deletions frontend/dockerfile/dockerfile2llb/convert_runsecurity.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,23 +5,20 @@ package dockerfile2llb
import (
"github.com/pkg/errors"

"github.com/moby/buildkit/client/llb"
"github.com/moby/buildkit/frontend/dockerfile/instructions"
"github.com/moby/buildkit/solver/pb"
)

func dispatchRunSecurity(d *dispatchState, c *instructions.RunCommand) error {
func dispatchRunSecurity(c *instructions.RunCommand) (llb.RunOption, error) {
security := instructions.GetSecurity(c)

for _, sec := range security {
switch sec {
case instructions.SecurityInsecure:
d.state = d.state.Security(pb.SecurityMode_INSECURE)
case instructions.SecuritySandbox:
d.state = d.state.Security(pb.SecurityMode_SANDBOX)
default:
return errors.Errorf("unsupported security mode %q", sec)
}
switch security {
case instructions.SecurityInsecure:
return llb.Security(pb.SecurityMode_INSECURE), nil
bossmc marked this conversation as resolved.
Show resolved Hide resolved
case instructions.SecuritySandbox:
return llb.Security(pb.SecurityMode_SANDBOX), nil
default:
return nil, errors.Errorf("unsupported security mode %q", security)
}

return nil
}
177 changes: 177 additions & 0 deletions frontend/dockerfile/dockerfile_runnetwork_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
// +build dfrunnetwork

package dockerfile

import (
"context"
"fmt"
"os"
"strings"
"testing"

"github.com/containerd/continuity/fs/fstest"
"github.com/moby/buildkit/client"
"github.com/moby/buildkit/frontend/dockerfile/builder"
"github.com/moby/buildkit/util/entitlements"
"github.com/moby/buildkit/util/testutil/echoserver"
"github.com/moby/buildkit/util/testutil/integration"
"github.com/stretchr/testify/require"
)

var runNetworkTests = []integration.Test{
runDefaultNetwork,
runNoNetwork,
runHostNetwork,
runGlobalNetwork,
}

func init() {
networkTests = append(networkTests, runNetworkTests...)
}

func runDefaultNetwork(t *testing.T, sb integration.Sandbox) {
f := getFrontend(t, sb)

dockerfile := []byte(`
FROM busybox
RUN ip link show eth0
`)

dir, err := tmpdir(
fstest.CreateFile("Dockerfile", dockerfile, 0600),
)
require.NoError(t, err)
defer os.RemoveAll(dir)

c, err := client.New(context.TODO(), sb.Address())
require.NoError(t, err)
defer c.Close()

_, err = f.Solve(context.TODO(), c, client.SolveOpt{
LocalDirs: map[string]string{
builder.DefaultLocalNameDockerfile: dir,
builder.DefaultLocalNameContext: dir,
},
}, nil)

require.NoError(t, err)
}

func runNoNetwork(t *testing.T, sb integration.Sandbox) {
f := getFrontend(t, sb)

dockerfile := []byte(`
FROM busybox
RUN --network=none ! ip link show eth0
bossmc marked this conversation as resolved.
Show resolved Hide resolved
`)

dir, err := tmpdir(
fstest.CreateFile("Dockerfile", dockerfile, 0600),
)
require.NoError(t, err)
defer os.RemoveAll(dir)

c, err := client.New(context.TODO(), sb.Address())
require.NoError(t, err)
defer c.Close()

_, err = f.Solve(context.TODO(), c, client.SolveOpt{
LocalDirs: map[string]string{
builder.DefaultLocalNameDockerfile: dir,
builder.DefaultLocalNameContext: dir,
},
}, nil)

require.NoError(t, err)
}

func runHostNetwork(t *testing.T, sb integration.Sandbox) {
bossmc marked this conversation as resolved.
Show resolved Hide resolved
bossmc marked this conversation as resolved.
Show resolved Hide resolved
f := getFrontend(t, sb)

s, err := echoserver.NewTestServer("foo")
require.NoError(t, err)
addrParts := strings.Split(s.Addr().String(), ":")
port := addrParts[len(addrParts)-1]

dockerfile := fmt.Sprintf(`
FROM busybox
RUN --network=host nc 127.0.0.1 %s | grep foo
RUN ! nc -z 127.0.0.1 %s
`, port, port)

dir, err := tmpdir(
fstest.CreateFile("Dockerfile", []byte(dockerfile), 0600),
)
require.NoError(t, err)
defer os.RemoveAll(dir)

c, err := client.New(context.TODO(), sb.Address())
require.NoError(t, err)
defer c.Close()

_, err = f.Solve(context.TODO(), c, client.SolveOpt{
LocalDirs: map[string]string{
builder.DefaultLocalNameDockerfile: dir,
builder.DefaultLocalNameContext: dir,
},
AllowedEntitlements: []entitlements.Entitlement{entitlements.EntitlementNetworkHost},
}, nil)

hostAllowed := sb.Value("network.host")
switch hostAllowed {
case networkHostGranted:
require.NoError(t, err)
case networkHostDenied:
require.Error(t, err)
require.Contains(t, err.Error(), "entitlement network.host is not allowed")
default:
require.Fail(t, "unexpected network.host mode %q", hostAllowed)
}
}

func runGlobalNetwork(t *testing.T, sb integration.Sandbox) {
bossmc marked this conversation as resolved.
Show resolved Hide resolved
f := getFrontend(t, sb)

s, err := echoserver.NewTestServer("foo")
require.NoError(t, err)
addrParts := strings.Split(s.Addr().String(), ":")
port := addrParts[len(addrParts)-1]

dockerfile := fmt.Sprintf(`
FROM busybox
RUN nc 127.0.0.1 %s | grep foo
RUN --network=none ! nc -z 127.0.0.1 %s
`, port, port)

dir, err := tmpdir(
fstest.CreateFile("Dockerfile", []byte(dockerfile), 0600),
)
require.NoError(t, err)
defer os.RemoveAll(dir)

c, err := client.New(context.TODO(), sb.Address())
require.NoError(t, err)
defer c.Close()

_, err = f.Solve(context.TODO(), c, client.SolveOpt{
LocalDirs: map[string]string{
builder.DefaultLocalNameDockerfile: dir,
builder.DefaultLocalNameContext: dir,
},
AllowedEntitlements: []entitlements.Entitlement{entitlements.EntitlementNetworkHost},
FrontendAttrs: map[string]string{
"force-network-mode": "host",
},
}, nil)

hostAllowed := sb.Value("network.host")
switch hostAllowed {
case networkHostGranted:
require.NoError(t, err)
case networkHostDenied:
require.Error(t, err)
require.Contains(t, err.Error(), "entitlement network.host is not allowed")
default:
require.Fail(t, "unexpected network.host mode %q", hostAllowed)
}
}
17 changes: 9 additions & 8 deletions frontend/dockerfile/dockerfile_runsecurity_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ func testRunSecurityInsecure(t *testing.T, sb integration.Sandbox) {
dockerfile := []byte(`
FROM busybox
RUN --security=insecure [ "$(cat /proc/self/status | grep CapBnd)" == "CapBnd: 0000003fffffffff" ]
RUN [ "$(cat /proc/self/status | grep CapBnd)" == "CapBnd: 00000000a80425fb" ]
`)

dir, err := tmpdir(
Expand All @@ -52,13 +53,13 @@ RUN --security=insecure [ "$(cat /proc/self/status | grep CapBnd)" == "CapBnd: 0
AllowedEntitlements: []entitlements.Entitlement{entitlements.EntitlementSecurityInsecure},
}, nil)

secMode := sb.Value("secmode")
secMode := sb.Value("security.insecure")
switch secMode {
case securitySandbox:
case securityInsecureGranted:
require.NoError(t, err)
case securityInsecureDenied:
require.Error(t, err)
require.Contains(t, err.Error(), "entitlement security.insecure is not allowed")
case securityInsecure:
require.NoError(t, err)
default:
require.Fail(t, "unexpected secmode")
}
Expand Down Expand Up @@ -118,13 +119,13 @@ RUN [ "$(cat /proc/self/status | grep CapBnd)" == "CapBnd: 00000000a80425fb" ]
AllowedEntitlements: []entitlements.Entitlement{entitlements.EntitlementSecurityInsecure},
}, nil)

secMode := sb.Value("secmode")
secMode := sb.Value("security.insecure")
switch secMode {
case securitySandbox:
case securityInsecureGranted:
require.NoError(t, err)
case securityInsecureDenied:
require.Error(t, err)
require.Contains(t, err.Error(), "entitlement security.insecure is not allowed")
case securityInsecure:
require.NoError(t, err)
default:
require.Fail(t, "unexpected secmode")
}
Expand Down
34 changes: 29 additions & 5 deletions frontend/dockerfile/dockerfile_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -112,8 +112,12 @@ var fileOpTests = []integration.Test{
testWorkdirCopyIgnoreRelative,
}

// Tests that depend on the `security.*` entitlements
var securityTests = []integration.Test{}

// Tests that depend on the `network.*` entitlements
var networkTests = []integration.Test{}

var opts []integration.TestOpt

type frontend interface {
Expand Down Expand Up @@ -156,9 +160,14 @@ func TestIntegration(t *testing.T) {
"false": false,
}))...)
integration.Run(t, securityTests, append(opts,
integration.WithMatrix("secmode", map[string]interface{}{
"sandbox": securitySandbox,
"insecure": securityInsecure,
integration.WithMatrix("security.insecure", map[string]interface{}{
"granted": securityInsecureGranted,
"denied": securityInsecureDenied,
}))...)
integration.Run(t, networkTests, append(opts,
integration.WithMatrix("network.host", map[string]interface{}{
"granted": networkHostGranted,
"denied": networkHostDenied,
}))...)
}

Expand Down Expand Up @@ -4278,8 +4287,23 @@ func (*secModeInsecure) UpdateConfigFile(in string) string {
return in + "\n\ninsecure-entitlements = [\"security.insecure\"]\n"
}

var securitySandbox integration.ConfigUpdater = &secModeSandbox{}
var securityInsecure integration.ConfigUpdater = &secModeInsecure{}
var securityInsecureGranted integration.ConfigUpdater = &secModeInsecure{}
var securityInsecureDenied integration.ConfigUpdater = &secModeSandbox{}

type networkModeHost struct{}

func (*networkModeHost) UpdateConfigFile(in string) string {
return in + "\n\ninsecure-entitlements = [\"network.host\"]\n"
}

type networkModeSandbox struct{}

func (*networkModeSandbox) UpdateConfigFile(in string) string {
return in
}

var networkHostGranted integration.ConfigUpdater = &networkModeHost{}
var networkHostDenied integration.ConfigUpdater = &networkModeSandbox{}

func fixedWriteCloser(wc io.WriteCloser) func(map[string]string) (io.WriteCloser, error) {
return func(map[string]string) (io.WriteCloser, error) {
Expand Down
Loading