Skip to content

Commit 91f1b33

Browse files
authored
Merge pull request #453 from buildkite/chown-workspace-to-poduser
Allow running command containers as non-root user with EBS backed (and other) workspace volumes
2 parents 2495d1b + e9ecd79 commit 91f1b33

File tree

1 file changed

+67
-19
lines changed

1 file changed

+67
-19
lines changed

internal/controller/scheduler/scheduler.go

Lines changed: 67 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -555,25 +555,7 @@ func (w *worker) Build(podSpec *corev1.PodSpec, skipCheckout bool, inputs buildI
555555
)
556556
}
557557

558-
initContainers := []corev1.Container{
559-
{
560-
// This container copies buildkite-agent and tini-static into
561-
// /workspace.
562-
Name: CopyAgentContainerName,
563-
Image: w.cfg.Image,
564-
ImagePullPolicy: corev1.PullAlways,
565-
Command: []string{"cp"},
566-
Args: []string{
567-
"/usr/local/bin/buildkite-agent",
568-
"/sbin/tini-static",
569-
"/workspace",
570-
},
571-
VolumeMounts: []corev1.VolumeMount{{
572-
Name: workspaceVolume.Name,
573-
MountPath: "/workspace",
574-
}},
575-
},
576-
}
558+
initContainers := []corev1.Container{w.createWorkspaceSetupContainer(podSpec, workspaceVolume)}
577559

578560
// Only attempt the job once.
579561
podSpec.RestartPolicy = corev1.RestartPolicyNever
@@ -799,6 +781,72 @@ func PatchPodSpec(original *corev1.PodSpec, patch *corev1.PodSpec) (*corev1.PodS
799781
return &patchedSpec, nil
800782
}
801783

784+
func (w *worker) createWorkspaceSetupContainer(podSpec *corev1.PodSpec, workspaceVolume *corev1.Volume) corev1.Container {
785+
podUser, podGroup := int64(0), int64(0)
786+
if podSpec.SecurityContext != nil {
787+
if podSpec.SecurityContext.RunAsUser != nil {
788+
podUser = *(podSpec.SecurityContext.RunAsUser)
789+
}
790+
if podSpec.SecurityContext.RunAsGroup != nil {
791+
podGroup = *(podSpec.SecurityContext.RunAsGroup)
792+
}
793+
}
794+
795+
var securityContext *corev1.SecurityContext
796+
var containerArgs strings.Builder
797+
// Ensure that the checkout occurs as the user/group specified in the pod's security context.
798+
// we will create a buildkite-agent user/group in the checkout container as needed and switch
799+
// to it. The created user/group will have the uid/gid specified in the pod's security context.
800+
switch {
801+
case podUser != 0 && podGroup != 0:
802+
// The init container needs to be run as root to create the user and give it ownership to the workspace directory
803+
securityContext = &corev1.SecurityContext{
804+
RunAsUser: ptr.To[int64](0),
805+
RunAsGroup: ptr.To[int64](0),
806+
RunAsNonRoot: ptr.To(false),
807+
}
808+
809+
fmt.Fprintf(&containerArgs, "chown -R %d:%d /workspace\n", podUser, podGroup)
810+
811+
case podUser != 0 && podGroup == 0:
812+
//The init container needs to be run as root to create the user and give it ownership to the workspace directory
813+
securityContext = &corev1.SecurityContext{
814+
RunAsUser: ptr.To[int64](0),
815+
RunAsGroup: ptr.To[int64](0),
816+
RunAsNonRoot: ptr.To[bool](false),
817+
}
818+
819+
fmt.Fprintf(&containerArgs, "chown -R %d /workspace\n", podUser)
820+
821+
// If the group is not root, but the user is root, I don't think we NEED to do anything. It's fine
822+
// for the user and group to be root for the checked out repo, even though the Pod's security
823+
// context has a non-root group.
824+
default:
825+
securityContext = nil
826+
}
827+
// Init containers. These run in order before the regular containers.
828+
// We run some init containers before any specified in the given podSpec.
829+
//
830+
// We use an init container to copy buildkite-agent into /workspace.
831+
// We also use init containers to check that images can be pulled before
832+
// any other containers run.
833+
containerArgs.WriteString("\ncp /usr/local/bin/buildkite-agent /sbin/tini-static /workspace\n")
834+
return corev1.Container{
835+
// This container copies buildkite-agent and tini-static into
836+
// /workspace.
837+
Name: CopyAgentContainerName,
838+
Image: w.cfg.Image,
839+
ImagePullPolicy: w.cfg.DefaultImagePullPolicy,
840+
Command: []string{"ash"},
841+
Args: []string{"-cefx", containerArgs.String()},
842+
SecurityContext: securityContext,
843+
VolumeMounts: []corev1.VolumeMount{{
844+
Name: workspaceVolume.Name,
845+
MountPath: "/workspace",
846+
}},
847+
}
848+
}
849+
802850
func (w *worker) createCheckoutContainer(
803851
podSpec *corev1.PodSpec,
804852
env []corev1.EnvVar,

0 commit comments

Comments
 (0)