Move get{Bind,Tmpfs,Secret,SSH}Mount to run_common.go

Signed-off-by: Doug Rabson <dfr@rabson.org>
This commit is contained in:
Doug Rabson 2022-06-23 11:49:39 +01:00
parent 0832ea2f35
commit 57a73847e4
3 changed files with 265 additions and 530 deletions

View File

@ -26,6 +26,8 @@ import (
"github.com/containers/buildah/bind"
"github.com/containers/buildah/copier"
"github.com/containers/buildah/define"
"github.com/containers/buildah/internal"
internalParse "github.com/containers/buildah/internal/parse"
"github.com/containers/buildah/pkg/sshagent"
"github.com/containers/buildah/util"
"github.com/containers/common/libnetwork/etchosts"
@ -34,6 +36,7 @@ import (
nettypes "github.com/containers/common/libnetwork/types"
"github.com/containers/common/pkg/config"
"github.com/containers/common/pkg/subscriptions"
imagetypes "github.com/containers/image/v5/types"
"github.com/containers/storage"
"github.com/containers/storage/pkg/idtools"
"github.com/containers/storage/pkg/ioutils"
@ -1523,3 +1526,265 @@ func (b *Builder) runSetupRunMounts(mounts []string, sources runMountInfo, idMap
}
return finalMounts, artifacts, nil
}
func (b *Builder) getBindMount(tokens []string, context *imagetypes.SystemContext, contextDir string, stageMountPoints map[string]internal.StageMountDetails, idMaps IDMaps) (*spec.Mount, string, error) {
if contextDir == "" {
return nil, "", errors.New("Context Directory for current run invocation is not configured")
}
var optionMounts []specs.Mount
mount, image, err := internalParse.GetBindMount(context, tokens, contextDir, b.store, b.MountLabel, stageMountPoints)
if err != nil {
return nil, image, err
}
optionMounts = append(optionMounts, mount)
volumes, err := b.runSetupVolumeMounts(b.MountLabel, nil, optionMounts, idMaps)
if err != nil {
return nil, image, err
}
return &volumes[0], image, nil
}
func (b *Builder) getTmpfsMount(tokens []string, idMaps IDMaps) (*spec.Mount, error) {
var optionMounts []specs.Mount
mount, err := internalParse.GetTmpfsMount(tokens)
if err != nil {
return nil, err
}
optionMounts = append(optionMounts, mount)
volumes, err := b.runSetupVolumeMounts(b.MountLabel, nil, optionMounts, idMaps)
if err != nil {
return nil, err
}
return &volumes[0], nil
}
func (b *Builder) getSecretMount(tokens []string, secrets map[string]define.Secret, idMaps IDMaps) (*spec.Mount, string, error) {
errInvalidSyntax := errors.New("secret should have syntax id=id[,target=path,required=bool,mode=uint,uid=uint,gid=uint")
if len(tokens) == 0 {
return nil, "", errInvalidSyntax
}
var err error
var id, target string
var required bool
var uid, gid uint32
var mode uint32 = 0400
for _, val := range tokens {
kv := strings.SplitN(val, "=", 2)
switch kv[0] {
case "id":
id = kv[1]
case "target", "dst", "destination":
target = kv[1]
case "required":
required, err = strconv.ParseBool(kv[1])
if err != nil {
return nil, "", errInvalidSyntax
}
case "mode":
mode64, err := strconv.ParseUint(kv[1], 8, 32)
if err != nil {
return nil, "", errInvalidSyntax
}
mode = uint32(mode64)
case "uid":
uid64, err := strconv.ParseUint(kv[1], 10, 32)
if err != nil {
return nil, "", errInvalidSyntax
}
uid = uint32(uid64)
case "gid":
gid64, err := strconv.ParseUint(kv[1], 10, 32)
if err != nil {
return nil, "", errInvalidSyntax
}
gid = uint32(gid64)
default:
return nil, "", errInvalidSyntax
}
}
if id == "" {
return nil, "", errInvalidSyntax
}
// Default location for secretis is /run/secrets/id
if target == "" {
target = "/run/secrets/" + id
}
secr, ok := secrets[id]
if !ok {
if required {
return nil, "", fmt.Errorf("secret required but no secret with id %s found", id)
}
return nil, "", nil
}
var data []byte
var envFile string
var ctrFileOnHost string
switch secr.SourceType {
case "env":
data = []byte(os.Getenv(secr.Source))
tmpFile, err := ioutil.TempFile("/dev/shm", "buildah*")
if err != nil {
return nil, "", err
}
envFile = tmpFile.Name()
ctrFileOnHost = tmpFile.Name()
case "file":
containerWorkingDir, err := b.store.ContainerDirectory(b.ContainerID)
if err != nil {
return nil, "", err
}
data, err = ioutil.ReadFile(secr.Source)
if err != nil {
return nil, "", err
}
ctrFileOnHost = filepath.Join(containerWorkingDir, "secrets", id)
default:
return nil, "", errors.New("invalid source secret type")
}
// Copy secrets to container working dir (or tmp dir if it's an env), since we need to chmod,
// chown and relabel it for the container user and we don't want to mess with the original file
if err := os.MkdirAll(filepath.Dir(ctrFileOnHost), 0755); err != nil {
return nil, "", err
}
if err := ioutil.WriteFile(ctrFileOnHost, data, 0644); err != nil {
return nil, "", err
}
if err := label.Relabel(ctrFileOnHost, b.MountLabel, false); err != nil {
return nil, "", err
}
hostUID, hostGID, err := util.GetHostIDs(idMaps.uidmap, idMaps.gidmap, uid, gid)
if err != nil {
return nil, "", err
}
if err := os.Lchown(ctrFileOnHost, int(hostUID), int(hostGID)); err != nil {
return nil, "", err
}
if err := os.Chmod(ctrFileOnHost, os.FileMode(mode)); err != nil {
return nil, "", err
}
newMount := specs.Mount{
Destination: target,
Type: "bind",
Source: ctrFileOnHost,
Options: []string{"bind", "rprivate", "ro"},
}
return &newMount, envFile, nil
}
// getSSHMount parses the --mount type=ssh flag in the Containerfile, checks if there's an ssh source provided, and creates and starts an ssh-agent to be forwarded into the container
func (b *Builder) getSSHMount(tokens []string, count int, sshsources map[string]*sshagent.Source, idMaps IDMaps) (*spec.Mount, *sshagent.AgentServer, error) {
errInvalidSyntax := errors.New("ssh should have syntax id=id[,target=path,required=bool,mode=uint,uid=uint,gid=uint")
var err error
var id, target string
var required bool
var uid, gid uint32
var mode uint32 = 400
for _, val := range tokens {
kv := strings.SplitN(val, "=", 2)
if len(kv) < 2 {
return nil, nil, errInvalidSyntax
}
switch kv[0] {
case "id":
id = kv[1]
case "target", "dst", "destination":
target = kv[1]
case "required":
required, err = strconv.ParseBool(kv[1])
if err != nil {
return nil, nil, errInvalidSyntax
}
case "mode":
mode64, err := strconv.ParseUint(kv[1], 8, 32)
if err != nil {
return nil, nil, errInvalidSyntax
}
mode = uint32(mode64)
case "uid":
uid64, err := strconv.ParseUint(kv[1], 10, 32)
if err != nil {
return nil, nil, errInvalidSyntax
}
uid = uint32(uid64)
case "gid":
gid64, err := strconv.ParseUint(kv[1], 10, 32)
if err != nil {
return nil, nil, errInvalidSyntax
}
gid = uint32(gid64)
default:
return nil, nil, errInvalidSyntax
}
}
if id == "" {
id = "default"
}
// Default location for secretis is /run/buildkit/ssh_agent.{i}
if target == "" {
target = fmt.Sprintf("/run/buildkit/ssh_agent.%d", count)
}
sshsource, ok := sshsources[id]
if !ok {
if required {
return nil, nil, fmt.Errorf("ssh required but no ssh with id %s found", id)
}
return nil, nil, nil
}
// Create new agent from keys or socket
fwdAgent, err := sshagent.NewAgentServer(sshsource)
if err != nil {
return nil, nil, err
}
// Start ssh server, and get the host sock we're mounting in the container
hostSock, err := fwdAgent.Serve(b.ProcessLabel)
if err != nil {
return nil, nil, err
}
if err := label.Relabel(filepath.Dir(hostSock), b.MountLabel, false); err != nil {
if shutdownErr := fwdAgent.Shutdown(); shutdownErr != nil {
b.Logger.Errorf("error shutting down agent: %v", shutdownErr)
}
return nil, nil, err
}
if err := label.Relabel(hostSock, b.MountLabel, false); err != nil {
if shutdownErr := fwdAgent.Shutdown(); shutdownErr != nil {
b.Logger.Errorf("error shutting down agent: %v", shutdownErr)
}
return nil, nil, err
}
hostUID, hostGID, err := util.GetHostIDs(idMaps.uidmap, idMaps.gidmap, uid, gid)
if err != nil {
if shutdownErr := fwdAgent.Shutdown(); shutdownErr != nil {
b.Logger.Errorf("error shutting down agent: %v", shutdownErr)
}
return nil, nil, err
}
if err := os.Lchown(hostSock, int(hostUID), int(hostGID)); err != nil {
if shutdownErr := fwdAgent.Shutdown(); shutdownErr != nil {
b.Logger.Errorf("error shutting down agent: %v", shutdownErr)
}
return nil, nil, err
}
if err := os.Chmod(hostSock, os.FileMode(mode)); err != nil {
if shutdownErr := fwdAgent.Shutdown(); shutdownErr != nil {
b.Logger.Errorf("error shutting down agent: %v", shutdownErr)
}
return nil, nil, err
}
newMount := specs.Mount{
Destination: target,
Type: "bind",
Source: hostSock,
Options: []string{"bind", "rprivate", "ro"},
}
return &newMount, fwdAgent, nil
}

View File

@ -9,7 +9,6 @@ import (
"os"
"os/exec"
"path/filepath"
"strconv"
"strings"
"syscall"
"unsafe"
@ -19,11 +18,9 @@ import (
"github.com/containers/buildah/copier"
"github.com/containers/buildah/define"
"github.com/containers/buildah/internal"
internalParse "github.com/containers/buildah/internal/parse"
internalUtil "github.com/containers/buildah/internal/util"
"github.com/containers/buildah/pkg/jail"
"github.com/containers/buildah/pkg/overlay"
"github.com/containers/buildah/pkg/sshagent"
"github.com/containers/buildah/util"
"github.com/containers/common/libnetwork/resolvconf"
nettypes "github.com/containers/common/libnetwork/types"
@ -37,7 +34,6 @@ import (
"github.com/opencontainers/runtime-spec/specs-go"
spec "github.com/opencontainers/runtime-spec/specs-go"
"github.com/opencontainers/runtime-tools/generate"
"github.com/opencontainers/selinux/go-selinux/label"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
"golang.org/x/sys/unix"
@ -320,269 +316,6 @@ func (b *Builder) getCacheMount(tokens []string, stageMountPoints map[string]int
return nil, nil, errors.New("cache mounts not supported on freebsd")
}
func (b *Builder) getSecretMount(tokens []string, secrets map[string]define.Secret, idMaps IDMaps) (*spec.Mount, string, error) {
errInvalidSyntax := errors.New("secret should have syntax id=id[,target=path,required=bool,mode=uint,uid=uint,gid=uint")
if len(tokens) == 0 {
return nil, "", errInvalidSyntax
}
var err error
var id, target string
var required bool
var uid, gid uint32
var mode uint32 = 0400
for _, val := range tokens {
kv := strings.SplitN(val, "=", 2)
switch kv[0] {
case "id":
id = kv[1]
case "target", "dst", "destination":
target = kv[1]
case "required":
required, err = strconv.ParseBool(kv[1])
if err != nil {
return nil, "", errInvalidSyntax
}
case "mode":
mode64, err := strconv.ParseUint(kv[1], 8, 32)
if err != nil {
return nil, "", errInvalidSyntax
}
mode = uint32(mode64)
case "uid":
uid64, err := strconv.ParseUint(kv[1], 10, 32)
if err != nil {
return nil, "", errInvalidSyntax
}
uid = uint32(uid64)
case "gid":
gid64, err := strconv.ParseUint(kv[1], 10, 32)
if err != nil {
return nil, "", errInvalidSyntax
}
gid = uint32(gid64)
default:
return nil, "", errInvalidSyntax
}
}
if id == "" {
return nil, "", errInvalidSyntax
}
// Default location for secretis is /run/secrets/id
if target == "" {
target = "/run/secrets/" + id
}
secr, ok := secrets[id]
if !ok {
if required {
return nil, "", errors.Errorf("secret required but no secret with id %s found", id)
}
return nil, "", nil
}
var data []byte
var envFile string
var ctrFileOnHost string
switch secr.SourceType {
case "env":
data = []byte(os.Getenv(secr.Source))
tmpFile, err := ioutil.TempFile("/var/tmp", "buildah*")
if err != nil {
return nil, "", err
}
envFile = tmpFile.Name()
ctrFileOnHost = tmpFile.Name()
case "file":
containerWorkingDir, err := b.store.ContainerDirectory(b.ContainerID)
if err != nil {
return nil, "", err
}
data, err = ioutil.ReadFile(secr.Source)
if err != nil {
return nil, "", err
}
ctrFileOnHost = filepath.Join(containerWorkingDir, "secrets", id)
default:
return nil, "", errors.New("invalid source secret type")
}
// Copy secrets to container working dir (or tmp dir if it's an env), since we need to chmod,
// chown and relabel it for the container user and we don't want to mess with the original file
if err := os.MkdirAll(filepath.Dir(ctrFileOnHost), 0755); err != nil {
return nil, "", err
}
if err := ioutil.WriteFile(ctrFileOnHost, data, 0644); err != nil {
return nil, "", err
}
if err := label.Relabel(ctrFileOnHost, b.MountLabel, false); err != nil {
return nil, "", err
}
hostUID, hostGID, err := util.GetHostIDs(nil, nil, uid, gid)
if err != nil {
return nil, "", err
}
if err := os.Lchown(ctrFileOnHost, int(hostUID), int(hostGID)); err != nil {
return nil, "", err
}
if err := os.Chmod(ctrFileOnHost, os.FileMode(mode)); err != nil {
return nil, "", err
}
newMount := specs.Mount{
Destination: target,
Type: "nullfs",
Source: ctrFileOnHost,
Options: []string{"ro"},
}
return &newMount, envFile, nil
}
// getSSHMount parses the --mount type=ssh flag in the Containerfile, checks if there's an ssh source provided, and creates and starts an ssh-agent to be forwarded into the container
func (b *Builder) getSSHMount(tokens []string, count int, sshsources map[string]*sshagent.Source, idMaps IDMaps) (*spec.Mount, *sshagent.AgentServer, error) {
errInvalidSyntax := errors.New("ssh should have syntax id=id[,target=path,required=bool,mode=uint,uid=uint,gid=uint")
var err error
var id, target string
var required bool
var uid, gid uint32
var mode uint32 = 400
for _, val := range tokens {
kv := strings.SplitN(val, "=", 2)
if len(kv) < 2 {
return nil, nil, errInvalidSyntax
}
switch kv[0] {
case "id":
id = kv[1]
case "target", "dst", "destination":
target = kv[1]
case "required":
required, err = strconv.ParseBool(kv[1])
if err != nil {
return nil, nil, errInvalidSyntax
}
case "mode":
mode64, err := strconv.ParseUint(kv[1], 8, 32)
if err != nil {
return nil, nil, errInvalidSyntax
}
mode = uint32(mode64)
case "uid":
uid64, err := strconv.ParseUint(kv[1], 10, 32)
if err != nil {
return nil, nil, errInvalidSyntax
}
uid = uint32(uid64)
case "gid":
gid64, err := strconv.ParseUint(kv[1], 10, 32)
if err != nil {
return nil, nil, errInvalidSyntax
}
gid = uint32(gid64)
default:
return nil, nil, errInvalidSyntax
}
}
if id == "" {
id = "default"
}
// Default location for secretis is /run/buildkit/ssh_agent.{i}
if target == "" {
target = fmt.Sprintf("/run/buildkit/ssh_agent.%d", count)
}
sshsource, ok := sshsources[id]
if !ok {
if required {
return nil, nil, errors.Errorf("ssh required but no ssh with id %s found", id)
}
return nil, nil, nil
}
// Create new agent from keys or socket
fwdAgent, err := sshagent.NewAgentServer(sshsource)
if err != nil {
return nil, nil, err
}
// Start ssh server, and get the host sock we're mounting in the container
hostSock, err := fwdAgent.Serve(b.ProcessLabel)
if err != nil {
return nil, nil, err
}
if err := label.Relabel(filepath.Dir(hostSock), b.MountLabel, false); err != nil {
if shutdownErr := fwdAgent.Shutdown(); shutdownErr != nil {
b.Logger.Errorf("error shutting down agent: %v", shutdownErr)
}
return nil, nil, err
}
if err := label.Relabel(hostSock, b.MountLabel, false); err != nil {
if shutdownErr := fwdAgent.Shutdown(); shutdownErr != nil {
b.Logger.Errorf("error shutting down agent: %v", shutdownErr)
}
return nil, nil, err
}
hostUID, hostGID, err := util.GetHostIDs(nil, nil, uid, gid)
if err != nil {
if shutdownErr := fwdAgent.Shutdown(); shutdownErr != nil {
b.Logger.Errorf("error shutting down agent: %v", shutdownErr)
}
return nil, nil, err
}
if err := os.Lchown(hostSock, int(hostUID), int(hostGID)); err != nil {
if shutdownErr := fwdAgent.Shutdown(); shutdownErr != nil {
b.Logger.Errorf("error shutting down agent: %v", shutdownErr)
}
return nil, nil, err
}
if err := os.Chmod(hostSock, os.FileMode(mode)); err != nil {
if shutdownErr := fwdAgent.Shutdown(); shutdownErr != nil {
b.Logger.Errorf("error shutting down agent: %v", shutdownErr)
}
return nil, nil, err
}
newMount := specs.Mount{
Destination: target,
Type: "nullfs",
Source: hostSock,
Options: []string{"ro"},
}
return &newMount, fwdAgent, nil
}
func (b *Builder) getBindMount(tokens []string, context *imagetypes.SystemContext, contextDir string, stageMountPoints map[string]internal.StageMountDetails, idMaps IDMaps) (*spec.Mount, string, error) {
if contextDir == "" {
return nil, "", errors.New("Context Directory for current run invocation is not configured")
}
var optionMounts []specs.Mount
mount, image, err := internalParse.GetBindMount(context, tokens, contextDir, b.store, b.MountLabel, stageMountPoints)
if err != nil {
return nil, image, err
}
optionMounts = append(optionMounts, mount)
volumes, err := b.runSetupVolumeMounts(b.MountLabel, nil, optionMounts, idMaps)
if err != nil {
return nil, image, err
}
return &volumes[0], image, nil
}
func (b *Builder) getTmpfsMount(tokens []string, idMaps IDMaps) (*spec.Mount, error) {
var optionMounts []specs.Mount
mount, err := internalParse.GetTmpfsMount(tokens)
if err != nil {
return nil, err
}
optionMounts = append(optionMounts, mount)
volumes, err := b.runSetupVolumeMounts(b.MountLabel, nil, optionMounts, idMaps)
if err != nil {
return nil, err
}
return &volumes[0], nil
}
func (b *Builder) cleanupTempVolumes() {
for tempVolume, val := range b.TempVolumes {
if val {

View File

@ -25,7 +25,6 @@ import (
internalUtil "github.com/containers/buildah/internal/util"
"github.com/containers/buildah/pkg/overlay"
"github.com/containers/buildah/pkg/parse"
"github.com/containers/buildah/pkg/sshagent"
"github.com/containers/buildah/util"
"github.com/containers/common/libnetwork/resolvconf"
nettypes "github.com/containers/common/libnetwork/types"
@ -1176,37 +1175,6 @@ func checkIdsGreaterThan5(ids []spec.LinuxIDMapping) bool {
return false
}
func (b *Builder) getBindMount(tokens []string, context *imagetypes.SystemContext, contextDir string, stageMountPoints map[string]internal.StageMountDetails, idMaps IDMaps) (*spec.Mount, string, error) {
if contextDir == "" {
return nil, "", errors.New("Context Directory for current run invocation is not configured")
}
var optionMounts []specs.Mount
mount, image, err := internalParse.GetBindMount(context, tokens, contextDir, b.store, b.MountLabel, stageMountPoints)
if err != nil {
return nil, image, err
}
optionMounts = append(optionMounts, mount)
volumes, err := b.runSetupVolumeMounts(b.MountLabel, nil, optionMounts, idMaps)
if err != nil {
return nil, image, err
}
return &volumes[0], image, nil
}
func (b *Builder) getTmpfsMount(tokens []string, idMaps IDMaps) (*spec.Mount, error) {
var optionMounts []specs.Mount
mount, err := internalParse.GetTmpfsMount(tokens)
if err != nil {
return nil, err
}
optionMounts = append(optionMounts, mount)
volumes, err := b.runSetupVolumeMounts(b.MountLabel, nil, optionMounts, idMaps)
if err != nil {
return nil, err
}
return &volumes[0], nil
}
func (b *Builder) getCacheMount(tokens []string, stageMountPoints map[string]internal.StageMountDetails, idMaps IDMaps) (*spec.Mount, []string, error) {
var optionMounts []specs.Mount
mount, lockedTargets, err := internalParse.GetCacheMount(tokens, b.store, b.MountLabel, stageMountPoints)
@ -1221,237 +1189,6 @@ func (b *Builder) getCacheMount(tokens []string, stageMountPoints map[string]int
return &volumes[0], lockedTargets, nil
}
func (b *Builder) getSecretMount(tokens []string, secrets map[string]define.Secret, idMaps IDMaps) (*spec.Mount, string, error) {
errInvalidSyntax := errors.New("secret should have syntax id=id[,target=path,required=bool,mode=uint,uid=uint,gid=uint")
if len(tokens) == 0 {
return nil, "", errInvalidSyntax
}
var err error
var id, target string
var required bool
var uid, gid uint32
var mode uint32 = 0400
for _, val := range tokens {
kv := strings.SplitN(val, "=", 2)
switch kv[0] {
case "id":
id = kv[1]
case "target", "dst", "destination":
target = kv[1]
case "required":
required, err = strconv.ParseBool(kv[1])
if err != nil {
return nil, "", errInvalidSyntax
}
case "mode":
mode64, err := strconv.ParseUint(kv[1], 8, 32)
if err != nil {
return nil, "", errInvalidSyntax
}
mode = uint32(mode64)
case "uid":
uid64, err := strconv.ParseUint(kv[1], 10, 32)
if err != nil {
return nil, "", errInvalidSyntax
}
uid = uint32(uid64)
case "gid":
gid64, err := strconv.ParseUint(kv[1], 10, 32)
if err != nil {
return nil, "", errInvalidSyntax
}
gid = uint32(gid64)
default:
return nil, "", errInvalidSyntax
}
}
if id == "" {
return nil, "", errInvalidSyntax
}
// Default location for secretis is /run/secrets/id
if target == "" {
target = "/run/secrets/" + id
}
secr, ok := secrets[id]
if !ok {
if required {
return nil, "", fmt.Errorf("secret required but no secret with id %s found", id)
}
return nil, "", nil
}
var data []byte
var envFile string
var ctrFileOnHost string
switch secr.SourceType {
case "env":
data = []byte(os.Getenv(secr.Source))
tmpFile, err := ioutil.TempFile("/dev/shm", "buildah*")
if err != nil {
return nil, "", err
}
envFile = tmpFile.Name()
ctrFileOnHost = tmpFile.Name()
case "file":
containerWorkingDir, err := b.store.ContainerDirectory(b.ContainerID)
if err != nil {
return nil, "", err
}
data, err = ioutil.ReadFile(secr.Source)
if err != nil {
return nil, "", err
}
ctrFileOnHost = filepath.Join(containerWorkingDir, "secrets", id)
default:
return nil, "", errors.New("invalid source secret type")
}
// Copy secrets to container working dir (or tmp dir if it's an env), since we need to chmod,
// chown and relabel it for the container user and we don't want to mess with the original file
if err := os.MkdirAll(filepath.Dir(ctrFileOnHost), 0755); err != nil {
return nil, "", err
}
if err := ioutil.WriteFile(ctrFileOnHost, data, 0644); err != nil {
return nil, "", err
}
if err := label.Relabel(ctrFileOnHost, b.MountLabel, false); err != nil {
return nil, "", err
}
hostUID, hostGID, err := util.GetHostIDs(idMaps.uidmap, idMaps.gidmap, uid, gid)
if err != nil {
return nil, "", err
}
if err := os.Lchown(ctrFileOnHost, int(hostUID), int(hostGID)); err != nil {
return nil, "", err
}
if err := os.Chmod(ctrFileOnHost, os.FileMode(mode)); err != nil {
return nil, "", err
}
newMount := specs.Mount{
Destination: target,
Type: "bind",
Source: ctrFileOnHost,
Options: []string{"bind", "rprivate", "ro"},
}
return &newMount, envFile, nil
}
// getSSHMount parses the --mount type=ssh flag in the Containerfile, checks if there's an ssh source provided, and creates and starts an ssh-agent to be forwarded into the container
func (b *Builder) getSSHMount(tokens []string, count int, sshsources map[string]*sshagent.Source, idMaps IDMaps) (*spec.Mount, *sshagent.AgentServer, error) {
errInvalidSyntax := errors.New("ssh should have syntax id=id[,target=path,required=bool,mode=uint,uid=uint,gid=uint")
var err error
var id, target string
var required bool
var uid, gid uint32
var mode uint32 = 400
for _, val := range tokens {
kv := strings.SplitN(val, "=", 2)
if len(kv) < 2 {
return nil, nil, errInvalidSyntax
}
switch kv[0] {
case "id":
id = kv[1]
case "target", "dst", "destination":
target = kv[1]
case "required":
required, err = strconv.ParseBool(kv[1])
if err != nil {
return nil, nil, errInvalidSyntax
}
case "mode":
mode64, err := strconv.ParseUint(kv[1], 8, 32)
if err != nil {
return nil, nil, errInvalidSyntax
}
mode = uint32(mode64)
case "uid":
uid64, err := strconv.ParseUint(kv[1], 10, 32)
if err != nil {
return nil, nil, errInvalidSyntax
}
uid = uint32(uid64)
case "gid":
gid64, err := strconv.ParseUint(kv[1], 10, 32)
if err != nil {
return nil, nil, errInvalidSyntax
}
gid = uint32(gid64)
default:
return nil, nil, errInvalidSyntax
}
}
if id == "" {
id = "default"
}
// Default location for secretis is /run/buildkit/ssh_agent.{i}
if target == "" {
target = fmt.Sprintf("/run/buildkit/ssh_agent.%d", count)
}
sshsource, ok := sshsources[id]
if !ok {
if required {
return nil, nil, fmt.Errorf("ssh required but no ssh with id %s found", id)
}
return nil, nil, nil
}
// Create new agent from keys or socket
fwdAgent, err := sshagent.NewAgentServer(sshsource)
if err != nil {
return nil, nil, err
}
// Start ssh server, and get the host sock we're mounting in the container
hostSock, err := fwdAgent.Serve(b.ProcessLabel)
if err != nil {
return nil, nil, err
}
if err := label.Relabel(filepath.Dir(hostSock), b.MountLabel, false); err != nil {
if shutdownErr := fwdAgent.Shutdown(); shutdownErr != nil {
b.Logger.Errorf("error shutting down agent: %v", shutdownErr)
}
return nil, nil, err
}
if err := label.Relabel(hostSock, b.MountLabel, false); err != nil {
if shutdownErr := fwdAgent.Shutdown(); shutdownErr != nil {
b.Logger.Errorf("error shutting down agent: %v", shutdownErr)
}
return nil, nil, err
}
hostUID, hostGID, err := util.GetHostIDs(idMaps.uidmap, idMaps.gidmap, uid, gid)
if err != nil {
if shutdownErr := fwdAgent.Shutdown(); shutdownErr != nil {
b.Logger.Errorf("error shutting down agent: %v", shutdownErr)
}
return nil, nil, err
}
if err := os.Lchown(hostSock, int(hostUID), int(hostGID)); err != nil {
if shutdownErr := fwdAgent.Shutdown(); shutdownErr != nil {
b.Logger.Errorf("error shutting down agent: %v", shutdownErr)
}
return nil, nil, err
}
if err := os.Chmod(hostSock, os.FileMode(mode)); err != nil {
if shutdownErr := fwdAgent.Shutdown(); shutdownErr != nil {
b.Logger.Errorf("error shutting down agent: %v", shutdownErr)
}
return nil, nil, err
}
newMount := specs.Mount{
Destination: target,
Type: "bind",
Source: hostSock,
Options: []string{"bind", "rprivate", "ro"},
}
return &newMount, fwdAgent, nil
}
// cleanupRunMounts cleans up run mounts so they only appear in this run.
func (b *Builder) cleanupRunMounts(context *imagetypes.SystemContext, mountpoint string, artifacts *runMountArtifacts) error {
for _, agent := range artifacts.Agents {