Add --unsetenv option to buildah commit and build

This option will allow users to remove environment variables from the
final image.

Fixes: https://github.com/containers/buildah/issues/3512

Signed-off-by: Daniel J Walsh <dwalsh@redhat.com>
This commit is contained in:
Daniel J Walsh 2021-11-01 16:52:48 -04:00
parent 50ebc901d6
commit a5d9f1cb28
No known key found for this signature in database
GPG Key ID: A2DF901DABE2C028
12 changed files with 91 additions and 9 deletions

View File

@ -381,6 +381,7 @@ func buildCmd(c *cobra.Command, inputArgs []string, iopts buildOptions) error {
Excludes: excludes,
Timestamp: timestamp,
Platforms: platforms,
UnsetEnvs: iopts.UnsetEnvs,
}
if iopts.Quiet {
options.ReportWriter = ioutil.Discard

View File

@ -11,6 +11,7 @@ import (
"github.com/containers/buildah/pkg/parse"
"github.com/containers/buildah/util"
"github.com/containers/common/pkg/auth"
"github.com/containers/common/pkg/completion"
"github.com/containers/image/v5/pkg/shortnames"
storageTransport "github.com/containers/image/v5/storage"
"github.com/containers/image/v5/transports/alltransports"
@ -40,6 +41,7 @@ type commitInputOptions struct {
tlsVerify bool
encryptionKeys []string
encryptLayers []int
unsetenvs []string
}
func init() {
@ -59,30 +61,45 @@ func init() {
buildah commit containerID docker://localhost:5000/imageId`,
}
commitCommand.SetUsageTemplate(UsageTemplate())
flags := commitCommand.Flags()
commitListFlagSet(commitCommand, &opts)
rootCmd.AddCommand(commitCommand)
}
func commitListFlagSet(cmd *cobra.Command, opts *commitInputOptions) {
flags := cmd.Flags()
flags.SetInterspersed(false)
flags.StringVar(&opts.authfile, "authfile", auth.GetDefaultAuthFile(), "path of the authentication file. Use REGISTRY_AUTH_FILE environment variable to override")
_ = cmd.RegisterFlagCompletionFunc("authfile", completion.AutocompleteDefault)
flags.StringVar(&opts.blobCache, "blob-cache", "", "assume image blobs in the specified directory will be available for pushing")
flags.StringSliceVar(&opts.encryptionKeys, "encryption-key", nil, "key with the encryption protocol to use needed to encrypt the image (e.g. jwe:/path/to/key.pem)")
flags.IntSliceVar(&opts.encryptLayers, "encrypt-layer", nil, "layers to encrypt, 0-indexed layer indices with support for negative indexing (e.g. 0 is the first layer, -1 is the last layer). If not defined, will encrypt all layers if encryption-key flag is specified")
if err := flags.MarkHidden("blob-cache"); err != nil {
panic(fmt.Sprintf("error marking blob-cache as hidden: %v", err))
}
flags.StringSliceVar(&opts.encryptionKeys, "encryption-key", nil, "key with the encryption protocol to use needed to encrypt the image (e.g. jwe:/path/to/key.pem)")
_ = cmd.RegisterFlagCompletionFunc("encryption-key", completion.AutocompleteDefault)
flags.IntSliceVar(&opts.encryptLayers, "encrypt-layer", nil, "layers to encrypt, 0-indexed layer indices with support for negative indexing (e.g. 0 is the first layer, -1 is the last layer). If not defined, will encrypt all layers if encryption-key flag is specified")
_ = cmd.RegisterFlagCompletionFunc("encryption-key", completion.AutocompleteNone)
flags.StringVar(&opts.certDir, "cert-dir", "", "use certificates at the specified path to access the registry")
_ = cmd.RegisterFlagCompletionFunc("cirt-dir", completion.AutocompleteDefault)
flags.StringVar(&opts.creds, "creds", "", "use `[username[:password]]` for accessing the registry")
_ = cmd.RegisterFlagCompletionFunc("creds", completion.AutocompleteNone)
flags.BoolVarP(&opts.disableCompression, "disable-compression", "D", true, "don't compress layers")
flags.StringVarP(&opts.format, "format", "f", defaultFormat(), "`format` of the image manifest and metadata")
_ = cmd.RegisterFlagCompletionFunc("format", completion.AutocompleteNone)
flags.StringVar(&opts.manifest, "manifest", "", "adds created image to the specified manifest list. Creates manifest list if it does not exist")
_ = cmd.RegisterFlagCompletionFunc("manifest", completion.AutocompleteNone)
flags.StringVar(&opts.iidfile, "iidfile", "", "write the image ID to the file")
_ = cmd.RegisterFlagCompletionFunc("iidfile", completion.AutocompleteDefault)
flags.BoolVar(&opts.omitTimestamp, "omit-timestamp", false, "set created timestamp to epoch 0 to allow for deterministic builds")
flags.Int64Var(&opts.timestamp, "timestamp", 0, "set created timestamp to epoch seconds to allow for deterministic builds, defaults to current time")
_ = cmd.RegisterFlagCompletionFunc("timestamp", completion.AutocompleteNone)
flags.BoolVarP(&opts.quiet, "quiet", "q", false, "don't output progress information when writing images")
flags.StringVar(&opts.referenceTime, "reference-time", "", "set the timestamp on the image to match the named `file`")
_ = cmd.RegisterFlagCompletionFunc("reference-time", completion.AutocompleteNone)
flags.StringVar(&opts.signBy, "sign-by", "", "sign the image using a GPG key with the specified `FINGERPRINT`")
_ = cmd.RegisterFlagCompletionFunc("sign-by", completion.AutocompleteNone)
if err := flags.MarkHidden("omit-timestamp"); err != nil {
panic(fmt.Sprintf("error marking omit-timestamp as hidden: %v", err))
}
@ -92,6 +109,7 @@ func init() {
flags.BoolVar(&opts.rm, "rm", false, "remove the container and its content after committing it to an image. Default leaves the container and its content in place.")
flags.StringVar(&opts.signaturePolicy, "signature-policy", "", "`pathname` of signature policy file (not usually used)")
_ = cmd.RegisterFlagCompletionFunc("signature-policy", completion.AutocompleteDefault)
if err := flags.MarkHidden("signature-policy"); err != nil {
panic(fmt.Sprintf("error marking signature-policy as hidden: %v", err))
@ -100,8 +118,8 @@ func init() {
flags.BoolVar(&opts.squash, "squash", false, "produce an image with only one layer")
flags.BoolVar(&opts.tlsVerify, "tls-verify", true, "Require HTTPS and verify certificates when accessing the registry. TLS verification cannot be used when talking to an insecure registry.")
rootCmd.AddCommand(commitCommand)
flags.StringSliceVar(&opts.unsetenvs, "unsetenv", nil, "unset env from final image")
_ = cmd.RegisterFlagCompletionFunc("unsetenv", completion.AutocompleteNone)
}
func commitCmd(c *cobra.Command, args []string, iopts commitInputOptions) error {
@ -190,6 +208,7 @@ func commitCmd(c *cobra.Command, args []string, iopts commitInputOptions) error
SignBy: iopts.signBy,
OciEncryptConfig: encConfig,
OciEncryptLayers: encLayers,
UnsetEnvs: iopts.unsetenvs,
}
exclusiveFlags := 0
if c.Flag("reference-time").Changed {

View File

@ -101,6 +101,8 @@ type CommitOptions struct {
// integers in the slice represent 0-indexed layer indices, with support for negative
// indexing. i.e. 0 is the first layer, -1 is the last (top-most) layer.
OciEncryptLayers *[]int
// UnsetEnvs is a list of environments to not add to final image.
UnsetEnvs []string
}
var (

View File

@ -240,4 +240,6 @@ type BuildOptions struct {
// to match the set of platforms for which all of the build's base
// images are available. If this field is set, Platforms is ignored.
AllPlatforms bool
// UnsetEnvs is a list of environments to not add to final image.
UnsetEnvs []string
}

View File

@ -586,6 +586,10 @@ include:
"sigpending": maximum number of pending signals (ulimit -i)
"stack": maximum stack size (ulimit -s)
**--unsetenv** *env*
Unset environment variables from the final image.
**--userns** *how*
Sets the configuration for user namespaces when handling `RUN` instructions.

View File

@ -101,6 +101,10 @@ When --timestamp is set, the created timestamp is always set to the time specifi
Require HTTPS and verification of certificates when talking to container registries (defaults to true). TLS verification cannot be used when talking to an insecure registry.
**--unsetenv** *env*
Unset environment variables from the final image.
## EXAMPLE
This example saves an image based on the container.

View File

@ -752,11 +752,31 @@ func (b *Builder) makeImageRef(options CommitOptions) (types.ImageReference, err
if manifestType == "" {
manifestType = define.OCIv1ImageManifest
}
oconfig, err := json.Marshal(&b.OCIv1)
oci1 := b.OCIv1
docker := b.Docker
for _, u := range options.UnsetEnvs {
var env []string
for _, e := range oci1.Config.Env {
if strings.HasPrefix(e, u+"=") {
continue
}
env = append(env, e)
}
oci1.Config.Env = env
env = []string{}
for _, e := range docker.Config.Env {
if strings.HasPrefix(e, u+"=") {
continue
}
env = append(env, e)
}
docker.Config.Env = env
}
oconfig, err := json.Marshal(&oci1)
if err != nil {
return nil, errors.Wrapf(err, "error encoding OCI-format image configuration %#v", b.OCIv1)
}
dconfig, err := json.Marshal(&b.Docker)
dconfig, err := json.Marshal(&docker)
if err != nil {
return nil, errors.Wrapf(err, "error encoding docker-format image configuration %#v", b.Docker)
}

View File

@ -126,6 +126,7 @@ type Executor struct {
secrets map[string]define.Secret
sshsources map[string]*sshagent.Source
logPrefix string
unsetEnvs []string
}
type imageTypeAndHistoryAndDiffIDs struct {
@ -270,6 +271,7 @@ func newExecutor(logger *logrus.Logger, logPrefix string, store storage.Store, o
secrets: secrets,
sshsources: sshsources,
logPrefix: logPrefix,
unsetEnvs: options.UnsetEnvs,
}
if exec.err == nil {
exec.err = os.Stderr

View File

@ -1403,6 +1403,7 @@ func (s *StageExecutor) commit(ctx context.Context, createdBy string, emptyLayer
RetryDelay: s.executor.retryPullPushDelay,
HistoryTimestamp: s.executor.timestamp,
Manifest: s.executor.manifest,
UnsetEnvs: s.executor.unsetEnvs,
}
imgID, _, manifestDigest, err := s.builder.Commit(ctx, imageRef, options)
if err != nil {

View File

@ -87,6 +87,7 @@ type BudResults struct {
Jobs int
LogRusage bool
RusageLogFile string
UnsetEnvs []string
}
// FromAndBugResults represents the results for common flags
@ -231,6 +232,7 @@ func GetBudFlags(flags *BudResults) pflag.FlagSet {
fs.Int64Var(&flags.Timestamp, "timestamp", 0, "set created timestamp to the specified epoch seconds to allow for deterministic builds, defaults to current time")
fs.BoolVar(&flags.TLSVerify, "tls-verify", true, "require HTTPS and verify certificates when accessing the registry")
fs.String("variant", "", "override the `variant` of the specified image")
fs.StringSliceVar(&flags.UnsetEnvs, "unsetenv", nil, "Unset environment variable from final image")
return fs
}
@ -263,6 +265,7 @@ func GetBudFlagsCompletions() commonComp.FlagCompletions {
flagCompletion["target"] = commonComp.AutocompleteNone
flagCompletion["timestamp"] = commonComp.AutocompleteNone
flagCompletion["variant"] = commonComp.AutocompleteNone
flagCompletion["unsetenv"] = commonComp.AutocompleteNone
return flagCompletion
}

View File

@ -454,6 +454,17 @@ symlink(subdir)"
expect_output "${target}-working-container"
}
@test "build --unsetenv PATH" {
_prefetch alpine
target=scratch-image
run_buildah build --unsetenv PATH --signature-policy ${TESTSDIR}/policy.json -t oci-${target} ${TESTSDIR}/bud/from-scratch
run_buildah inspect --type=image --format '{{.OCIv1.Config.Env}}' oci-${target}
expect_output "[]" "No Path should be defined"
run_buildah build --unsetenv PATH --signature-policy ${TESTSDIR}/policy.json --format docker -t docker-${target} ${TESTSDIR}/bud/from-scratch
run_buildah inspect --type=image --format '{{.OCIv1.Config.Env}}' docker-${target}
expect_output "[]" "No Path should be defined"
}
@test "bud-from-scratch-untagged" {
run_buildah build --iidfile ${TESTDIR}/output.iid --signature-policy ${TESTSDIR}/policy.json ${TESTSDIR}/bud/from-scratch
iid=$(cat ${TESTDIR}/output.iid)

View File

@ -39,6 +39,19 @@ load helpers
expect_output --from="$mediatype" "application/vnd.docker.image.rootfs.diff.tar.gzip"
}
@test "commit --unsetenv PATH" {
_prefetch alpine
run_buildah from --quiet --pull=false --signature-policy ${TESTSDIR}/policy.json alpine
cid=$output
run_buildah commit --unsetenv PATH --signature-policy ${TESTSDIR}/policy.json $cid alpine-image-oci
run_buildah commit --unsetenv PATH --format docker --disable-compression=false --signature-policy ${TESTSDIR}/policy.json $cid alpine-image-docker
run_buildah inspect --type=image --format '{{.OCIv1.Config.Env}}' alpine-image-oci
expect_output "[]" "No Path should be defined"
run_buildah inspect --type=image --format '{{.Docker.Config.Env}}' alpine-image-docker
expect_output "[]" "No Path should be defined"
}
@test "commit quiet test" {
_prefetch alpine
run_buildah from --quiet --pull=false --signature-policy ${TESTSDIR}/policy.json alpine