Skip to content

Commit

Permalink
fix(bubblewrap_runner): run as build 1000 by default (#1572)
Browse files Browse the repository at this point in the history
* fix(bubblewrap_runner): map host ns uid/gid to 1000 by default

Bubblewrap pipeline is run with same uid of the user that run melange,
mapped for the child user namespace, leading to possible consistency problems
on the resulting package filesystem, while standardizing uid and gid 1000.
Furthermore, passwd database is already set for the uid 1000 with name build,
instead of the user that is run as, when not explicitely specified.
The same applies to the gid map.

Signed-off-by: Massimiliano Giovagnoli <[email protected]>

* chore(bubblewrap_runner): run as build user 1000 by default

By default the build user with id 1000 is setup with Apko, so for reproducibility
it makes sense to run as 1000 by default, where not explicitely specified RunAs
different uid. When the current user that runs melange is root the userns is not
unshared and this logic is skipped. This is due to compatibility we need to ensure
where arbitrary capabilities may be needed, while otherwise by unsharing the user
namespace they all are dropped.

Signed-off-by: Massimiliano Giovagnoli <[email protected]>
Co-Authored-by: Luca Di Maio <[email protected]>

---------

Signed-off-by: Massimiliano Giovagnoli <[email protected]>
Co-authored-by: Luca Di Maio <[email protected]>
  • Loading branch information
maxgio92 and 89luca89 authored Oct 23, 2024
1 parent 2112e61 commit dfc3851
Show file tree
Hide file tree
Showing 2 changed files with 69 additions and 1 deletion.
14 changes: 13 additions & 1 deletion pkg/container/bubblewrap_runner.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,10 @@ import (

var _ Debugger = (*bubblewrap)(nil)

const BubblewrapName = "bubblewrap"
const (
BubblewrapName = "bubblewrap"
buildUserID = "1000"
)

type bubblewrap struct {
remove bool // if true, clean up temp dirs on close.
Expand Down Expand Up @@ -87,9 +90,18 @@ func (bw *bubblewrap) cmd(ctx context.Context, cfg *Config, debug bool, envOverr
"--chdir", runnerWorkdir,
"--clearenv")

// If we need to run as an user, we run as that user.
if cfg.RunAs != "" {
baseargs = append(baseargs, "--unshare-user")
baseargs = append(baseargs, "--uid", cfg.RunAs)
baseargs = append(baseargs, "--gid", cfg.RunAs)
// Else if we're not using melange as root, we force the use of the
// Apko build user. This avoids problems on machines where default
// regular user is NOT 1000.
} else if os.Getuid() > 0 {
baseargs = append(baseargs, "--unshare-user")
baseargs = append(baseargs, "--uid", buildUserID)
baseargs = append(baseargs, "--gid", buildUserID)
}

if !debug {
Expand Down
56 changes: 56 additions & 0 deletions pkg/container/bubblewrap_runner_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
// Copyright 2024 Chainguard, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package container

import (
"fmt"
"strings"
"testing"

"github.com/chainguard-dev/clog/slogtest"
)

func TestBubblewrapCmd(t *testing.T) {
tests := []struct {
name string
config *Config
expectedArgs string
}{
{
name: "With default UID and GID",
config: new(Config),
expectedArgs: fmt.Sprintf("--unshare-user --uid %s --gid %s", buildUserID, buildUserID),
},
{
name: "With config RunAs",
config: &Config{RunAs: "65535"},
expectedArgs: fmt.Sprintf("--unshare-user --uid %s --gid %s", "65535", "65535"),
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
ctx := slogtest.Context(t)
args := make([]string, 0)

cmd := new(bubblewrap).cmd(ctx, tt.config, false, nil, args...)
if cmd.Args == nil {
t.Fatalf("cmd.Args should not be nil")
}
if !strings.Contains(strings.Join(cmd.Args, " "), tt.expectedArgs) {
t.Fatalf("expected %v, found %v", tt.expectedArgs, cmd.Args)
}
})
}
}

0 comments on commit dfc3851

Please sign in to comment.