Skip to content

Commit

Permalink
Implement frontend support for RUN --ents=...
Browse files Browse the repository at this point in the history
This follows syntax suggested in #950.

Example:

    RUN --ents=security.insecure cat /proc/self/status | grep CapEff
    #84 0.093 CapEff:	0000003fffffffff

Signed-off-by: Andrey Smirnov <smirnov.andrey@gmail.com>
  • Loading branch information
smira committed Jul 16, 2019
1 parent aee28f4 commit 8cc1c06
Show file tree
Hide file tree
Showing 9 changed files with 192 additions and 2 deletions.
5 changes: 5 additions & 0 deletions frontend/dockerfile/dockerfile2llb/convert.go
Original file line number Diff line number Diff line change
Expand Up @@ -647,6 +647,11 @@ func dispatchRun(d *dispatchState, c *instructions.RunCommand, proxy *llb.ProxyE
}
opt = append(opt, runMounts...)

err = dispatchRunEnts(d, c)
if err != nil {
return err
}

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

package dockerfile2llb

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

func dispatchRunEnts(d *dispatchState, c *instructions.RunCommand) error {
return nil
}
25 changes: 25 additions & 0 deletions frontend/dockerfile/dockerfile2llb/convert_runents.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// +build dfrunents

package dockerfile2llb

import (
"github.com/pkg/errors"

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

func dispatchRunEnts(d *dispatchState, c *instructions.RunCommand) error {
ents := instructions.GetEnts(c)

for _, ent := range ents {
switch ent {
case instructions.EntitlementSecurityInsecure:
d.state = d.state.Security(pb.SecurityMode_INSECURE)
default:
return errors.Errorf("unsupported entitlement %q", ent)
}
}

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

package dockerfile

import (
"context"
"os"
"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/integration"
"github.com/stretchr/testify/require"
)

var entsTests = []integration.Test{
testEntsSecurityInsecure,
}

func init() {
allTests = append(allTests, entsTests...)

}

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

dockerfile := []byte(`
FROM busybox
RUN --ents=security.insecure [ "$(cat /proc/self/status | grep CapEff)" == "CapEff: 0000003fffffffff" ]
`)

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,
},
AllowedEntitlements: []entitlements.Entitlement{entitlements.EntitlementSecurityInsecure},
}, nil)
require.NoError(t, err)
}
16 changes: 16 additions & 0 deletions frontend/dockerfile/docs/experimental.md
Original file line number Diff line number Diff line change
Expand Up @@ -138,3 +138,19 @@ $ buildctl build --frontend=dockerfile.v0 --local context=. --local dockerfile=.
You can also specify a path to `*.pem` file on the host directly instead of `$SSH_AUTH_SOCK`.
However, pem files with passphrases are not supported.

### RUN --ents=security.insecure

This runs the command without sandbox in insecure mode, which allows to run flows requiring elevated
privileges (e.g. containerd).

#### Example: check entitlements

```dockerfile
# syntax = docker/dockerfile:experimental
FROM ubuntu
RUN --ents=security.insecure cat /proc/self/status | grep CapEff
```

```
#84 0.093 CapEff: 0000003fffffffff
```
79 changes: 79 additions & 0 deletions frontend/dockerfile/instructions/commands_runents.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
// +build dfrunents

package instructions

import (
"encoding/csv"
"strings"

"github.com/pkg/errors"
)

const EntitlementSecurityInsecure = "security.insecure"

var allowedEntitlements = map[string]struct{}{
EntitlementSecurityInsecure: {},
}

func isValidEntitlement(value string) bool {
_, ok := allowedEntitlements[value]
return ok
}

type entsKeyT string

var entsKey = entsKeyT("dockerfile/run/mounts")

func init() {
parseRunPreHooks = append(parseRunPreHooks, runEntsPreHook)
parseRunPostHooks = append(parseRunPostHooks, runEntsPostHook)
}

func runEntsPreHook(cmd *RunCommand, req parseRequest) error {
st := &entState{}
st.flag = req.flags.AddStrings("ents")
cmd.setExternalValue(entsKey, st)
return nil
}

func runEntsPostHook(cmd *RunCommand, req parseRequest) error {
st := getEntsState(cmd)
if st == nil {
return errors.Errorf("no entitlements state")
}

for _, value := range st.flag.StringValues {
csvReader := csv.NewReader(strings.NewReader(value))
fields, err := csvReader.Read()
if err != nil {
return errors.Wrap(err, "failed to parse csv mounts")
}

for _, field := range fields {
if !isValidEntitlement(field) {
return errors.Errorf("entitlement %q is not valid", field)
}

st.entitlements = append(st.entitlements, field)
}
}

return nil
}

func getEntsState(cmd *RunCommand) *entState {
v := cmd.getExternalValue(entsKey)
if v == nil {
return nil
}
return v.(*entState)
}

func GetEnts(cmd *RunCommand) []string {
return getEntsState(cmd).entitlements
}

type entState struct {
flag *Flag
entitlements []string
}
2 changes: 1 addition & 1 deletion frontend/dockerfile/release/experimental/tags
Original file line number Diff line number Diff line change
@@ -1 +1 @@
dfrunmount dfsecrets dfssh
dfrunents dfrunmount dfsecrets dfssh
1 change: 1 addition & 0 deletions util/testutil/integration/containerd.go
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@ disabled_plugins = ["cri"]
"--containerd-worker=true",
"--containerd-worker-addr", address,
"--containerd-worker-labels=org.mobyproject.buildkit.worker.sandbox=true", // Include use of --containerd-worker-labels to trigger https://github.com/moby/buildkit/pull/603
"--allow-insecure-entitlement=security.insecure",
}

var upt []ConfigUpdater
Expand Down
2 changes: 1 addition & 1 deletion util/testutil/integration/oci.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ func (s *oci) New(opt ...SandboxOpt) (Sandbox, func() error, error) {
}
logs := map[string]*bytes.Buffer{}
// Include use of --oci-worker-labels to trigger https://github.com/moby/buildkit/pull/603
buildkitdArgs := []string{"buildkitd", "--oci-worker=true", "--containerd-worker=false", "--oci-worker-gc=false", "--oci-worker-labels=org.mobyproject.buildkit.worker.sandbox=true"}
buildkitdArgs := []string{"buildkitd", "--oci-worker=true", "--containerd-worker=false", "--oci-worker-gc=false", "--oci-worker-labels=org.mobyproject.buildkit.worker.sandbox=true", "--allow-insecure-entitlement=security.insecure"}

deferF := &multiCloser{}

Expand Down

0 comments on commit 8cc1c06

Please sign in to comment.