Preserving Environment Variables with sudo -E: A Practical Guide

Riteek Srivastav
3 min readJan 3, 2025

The title clearly summarizes the topic.
In this post, we delve into a practical use case that demonstrates how using the -E option with sudo can address issues with accessing environment variables during Docker builds.

Important Note:

Before using the -E flag with sudo, please check the environment variables for both the current user and sudo to ensure there are no conflicting variables. You can do this by running:

env  # Check current user's environment
sudo env # Check sudo's environment

This precaution can help prevent unexpected issues that may arise from conflicting environment settings.

Context:

For running the docker build command either you need to run it with sudo or you need to add the current user to the docker group. And this is required because of the security restrictions. For more details I would recommend this short stackoverflow answer.
I prefer running the docker build with sudo rather than adding the user to the docker group. Primary reason is, because sometimes the Docker daemon may need to access files or directories that require elevated permissions so running it under sudo expresses the intent better.

Problem:

So I had a use case where my private cli was using sudo docker build internally. Let’s say the cli name was clay which has a publish command which basically builds the docker image and publishes that image to some private docker registry. So it had code something like this (can you identify the issue in the code?).

func Build(buildtag, dockerfilePath string, secrets, buildArgs []string, noCache bool) error {
args := []string{}
args = append(args, "docker", "build", "-t", buildtag, "-f", dockerfilePath, ".")

if noCache {
args = append(args, "--no-cache")
}

for _, secret := range secrets {
args = append(args, "--secret", secret)
}

for _, buildArg := range buildArgs {
args = append(args, "--build-arg", buildArg)
}

buildCmd := exec.Command("sudo", args...)
buildCmd.Env = append(os.Environ(), "DOCKER_BUILDKIT=1")
buildCmd.Stdout = os.Stdout
buildCmd.Stderr = os.Stderr

return buildCmd.Run()
}

In my use case I had to run clay publish from github ci. Which was failing every time with the error.

DEPRECATED: The legacy builder is deprecated and will be removed in a future release.
Install the buildx component to build images with BuildKit:
https://docs.docker.com/go/buildx/

unknown flag: --secret
See 'docker build --help'.
Error: exit status 125
Error: exit status 1

This error tells that docker build is not using the buildx builder which can be enforce via env variable DOCKER_BUILDKIT.

I was surprised that the ENV variable is set in the code then why is it throwing this error, then later on I figured out that the line `buildCmd.Env = append(os.Environ(), “DOCKER_BUILDKIT=1”)` is setting the env variable for current user who is running the clay publish command and does not propagate it to the root context initiated by sudo.

Solution:

Up until now you must have figured out the solution, It took time to find out that sudo has -E option.
The correct code looks like

func Build(buildtag, dockerfilePath string, secrets, buildArgs []string, noCache bool) error {
args := []string{}
args = append(args, "build", "-t", buildtag, "-f", dockerfilePath, ".")

if noCache {
args = append(args, "--no-cache")
}

for _, secret := range secrets {
args = append(args, "--secret", secret)
}

for _, buildArg := range buildArgs {
args = append(args, "--build-arg", buildArg)
}

env := append(os.Environ(), "DOCKER_BUILDKIT=1")

buildCmd := exec.Command("sudo", append([]string{"-E", "docker"}, args...)...)
buildCmd.Env = env
buildCmd.Stdout = os.Stdout
buildCmd.Stderr = os.Stderr

return buildCmd.Run()
}

By adding -E, we ensure that the DOCKER_BUILDKITvariable is preserved when executing Docker commands with elevated privileges . This small but significant change resolved my CI pipeline issue and allowed builds to proceed smoothly.

--

--

Riteek Srivastav
Riteek Srivastav

Written by Riteek Srivastav

Writing or applying is the best way to validate your learning.

No responses yet