1
0
mirror of https://github.com/containers/buildah.git synced 2025-07-31 15:24:26 +03:00

add --sign-by to bud/commit/push, --remove-signatures for pull/push

Add the --sign-by option to `buildah build-using-dockerfile`,
`buildah commit`, `buildah push`, and `buildah manifest push`.  Add the
`--remove-signatures` option to `buildah pull`, `buildah push`, and
`buildah manifest push`.  We just pass them to the image library, which
does all of the heavy lifting.

Signed-off-by: Nalin Dahyabhai <nalin@redhat.com>

Closes: #2085
Approved by: rhatdan
This commit is contained in:
Nalin Dahyabhai
2020-01-15 12:23:38 -05:00
committed by Atomic Bot
parent ca0819f640
commit a925f79cc3
21 changed files with 200 additions and 31 deletions

View File

@ -16,7 +16,7 @@ import (
"github.com/spf13/cobra"
)
type budResults struct {
type budOptions struct {
*buildahcli.LayerResults
*buildahcli.BudResults
*buildahcli.UserNSResults
@ -45,7 +45,7 @@ func init() {
Long: budDescription,
//Flags: sortFlags(append(append(buildahcli.BudFlags, buildahcli.LayerFlags...), buildahcli.FromAndBudFlags...)),
RunE: func(cmd *cobra.Command, args []string) error {
br := budResults{
br := budOptions{
&layerFlagsResults,
&budFlagResults,
&userNSResults,
@ -90,7 +90,7 @@ func getDockerfiles(files []string) []string {
return dockerfiles
}
func budCmd(c *cobra.Command, inputArgs []string, iopts budResults) error {
func budCmd(c *cobra.Command, inputArgs []string, iopts budOptions) error {
output := ""
tags := []string{}
if c.Flag("tag").Changed {
@ -340,6 +340,7 @@ func budCmd(c *cobra.Command, inputArgs []string, iopts budResults) error {
TransientMounts: transientMounts,
Devices: devices,
DefaultEnv: defaultContainerConfig.GetDefaultEnv(),
SignBy: iopts.SignBy,
}
if iopts.Quiet {

View File

@ -31,6 +31,7 @@ type commitInputOptions struct {
referenceTime string
rm bool
signaturePolicy string
signBy string
squash bool
tlsVerify bool
}
@ -70,6 +71,7 @@ func init() {
flags.BoolVar(&opts.omitTimestamp, "omit-timestamp", false, "set created timestamp to epoch 0 to allow for deterministic builds")
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`")
flags.StringVar(&opts.signBy, "sign-by", "", "sign the image using a GPG key with the specified `FINGERPRINT`")
if err := flags.MarkHidden("reference-time"); err != nil {
panic(fmt.Sprintf("error marking reference-time as hidden: %v", err))
@ -175,6 +177,7 @@ func commitCmd(c *cobra.Command, args []string, iopts commitInputOptions) error
Squash: iopts.squash,
BlobDirectory: iopts.blobCache,
OmitTimestamp: iopts.omitTimestamp,
SignBy: iopts.signBy,
}
if !iopts.quiet {
options.ReportWriter = os.Stderr

View File

@ -38,8 +38,8 @@ type manifestAnnotateOpts = struct {
}
type manifestInspectOpts = struct{}
type manifestPushOpts = struct {
purge, quiet, all, tlsVerify bool
authfile, certDir, creds, digestfile, signaturePolicy string
purge, quiet, all, tlsVerify, removeSignatures bool
authfile, certDir, creds, digestfile, signaturePolicy, signBy string
}
func init() {
@ -194,6 +194,8 @@ func init() {
flags.StringVar(&manifestPushOpts.certDir, "cert-dir", "", "use certificates at the specified path to access the registry")
flags.StringVar(&manifestPushOpts.creds, "creds", "", "use `[username[:password]]` for accessing the registry")
flags.StringVar(&manifestPushOpts.digestfile, "digestfile", "", "after copying the image, write the digest of the resulting digest to the file")
flags.BoolVarP(&manifestPushOpts.removeSignatures, "remove-signatures", "", false, "don't copy signatures when pushing images")
flags.StringVar(&manifestPushOpts.signBy, "sign-by", "", "sign the image using a GPG key with the specified `FINGERPRINT`")
flags.StringVar(&manifestPushOpts.signaturePolicy, "signature-policy", "", "`pathname` of signature policy file (not usually used)")
if err := flags.MarkHidden("signature-policy"); err != nil {
panic(fmt.Sprintf("error marking signature-policy as hidden: %v", err))
@ -642,6 +644,8 @@ func manifestPushCmd(c *cobra.Command, args []string, opts manifestPushOpts) err
SystemContext: systemContext,
ImageListSelection: cp.CopySpecificImages,
Instances: nil,
RemoveSignatures: opts.removeSignatures,
SignBy: opts.signBy,
}
if opts.all {
options.ImageListSelection = cp.CopyAllImages

View File

@ -12,22 +12,23 @@ import (
"github.com/spf13/cobra"
)
type pullResults struct {
allTags bool
authfile string
blobCache string
certDir string
creds string
overrideArch string
overrideOS string
signaturePolicy string
quiet bool
tlsVerify bool
type pullOptions struct {
allTags bool
authfile string
blobCache string
certDir string
creds string
overrideArch string
overrideOS string
signaturePolicy string
quiet bool
removeSignatures bool
tlsVerify bool
}
func init() {
var (
opts pullResults
opts pullOptions
pullDescription = ` Pulls an image from a registry and stores it locally.
An image can be pulled using its tag or digest. If a tag is not
@ -54,6 +55,7 @@ func init() {
flags.StringVar(&opts.blobCache, "blob-cache", "", "store copies of pulled image blobs in the specified directory")
flags.StringVar(&opts.certDir, "cert-dir", "", "use certificates at the specified path to access the registry")
flags.StringVar(&opts.creds, "creds", "", "use `[username[:password]]` for accessing the registry")
flags.BoolVarP(&opts.removeSignatures, "remove-signatures", "", false, "don't copy signatures when pulling image")
flags.StringVar(&opts.signaturePolicy, "signature-policy", "", "`pathname` of signature policy file (not usually used)")
if err := flags.MarkHidden("signature-policy"); err != nil {
panic(fmt.Sprintf("error marking signature-policy as hidden: %v", err))
@ -75,7 +77,7 @@ func init() {
rootCmd.AddCommand(pullCommand)
}
func pullCmd(c *cobra.Command, args []string, iopts pullResults) error {
func pullCmd(c *cobra.Command, args []string, iopts pullOptions) error {
if len(args) == 0 {
return errors.Errorf("an image name must be specified")
}
@ -106,6 +108,7 @@ func pullCmd(c *cobra.Command, args []string, iopts pullResults) error {
BlobDirectory: iopts.blobCache,
AllTags: iopts.allTags,
ReportWriter: os.Stderr,
RemoveSignatures: iopts.removeSignatures,
}
if iopts.quiet {

View File

@ -20,7 +20,7 @@ import (
"github.com/spf13/cobra"
)
type pushResults struct {
type pushOptions struct {
authfile string
blobCache string
certDir string
@ -29,13 +29,15 @@ type pushResults struct {
disableCompression bool
format string
quiet bool
removeSignatures bool
signaturePolicy string
signBy string
tlsVerify bool
}
func init() {
var (
opts pushResults
opts pushOptions
pushDescription = fmt.Sprintf(`
Pushes an image to a specified location.
@ -71,6 +73,8 @@ func init() {
flags.BoolVarP(&opts.disableCompression, "disable-compression", "D", false, "don't compress layers")
flags.StringVarP(&opts.format, "format", "f", "", "manifest type (oci, v2s1, or v2s2) to use when saving image using the 'dir:' transport (default is manifest type of source)")
flags.BoolVarP(&opts.quiet, "quiet", "q", false, "don't output progress information when pushing images")
flags.BoolVarP(&opts.removeSignatures, "remove-signatures", "", false, "don't copy signatures when pushing image")
flags.StringVar(&opts.signBy, "sign-by", "", "sign the image using a GPG key with the specified `FINGERPRINT`")
flags.StringVar(&opts.signaturePolicy, "signature-policy", "", "`pathname` of signature policy file (not usually used)")
if err := flags.MarkHidden("signature-policy"); err != nil {
panic(fmt.Sprintf("error marking signature-policy as hidden: %v", err))
@ -83,7 +87,7 @@ func init() {
rootCmd.AddCommand(pushCommand)
}
func pushCmd(c *cobra.Command, args []string, iopts pushResults) error {
func pushCmd(c *cobra.Command, args []string, iopts pushOptions) error {
var src, destSpec string
if err := buildahcli.VerifyFlagsArgsOrder(args); err != nil {
@ -167,6 +171,8 @@ func pushCmd(c *cobra.Command, args []string, iopts pushResults) error {
Store: store,
SystemContext: systemContext,
BlobDirectory: iopts.blobCache,
RemoveSignatures: iopts.removeSignatures,
SignBy: iopts.signBy,
}
if !iopts.quiet {
options.ReportWriter = os.Stderr

View File

@ -81,6 +81,8 @@ type CommitOptions struct {
// OmitTimestamp forces epoch 0 as created timestamp to allow for
// deterministic, content-addressable builds.
OmitTimestamp bool
// SignBy is the fingerprint of a GPG key to use for signing the image.
SignBy string
}
// PushOptions can be used to alter how an image is copied somewhere.
@ -115,6 +117,11 @@ type PushOptions struct {
// the user will be displayed, this is best used for logging.
// The default is false.
Quiet bool
// SignBy is the fingerprint of a GPG key to use for signing the image.
SignBy string
// RemoveSignatures causes any existing signatures for the image to be
// discarded for the pushed copy.
RemoveSignatures bool
}
var (
@ -294,7 +301,7 @@ func (b *Builder) Commit(ctx context.Context, dest types.ImageReference, options
systemContext.DirForceCompress = true
}
var manifestBytes []byte
if manifestBytes, err = cp.Image(ctx, policyContext, maybeCachedDest, maybeCachedSrc, getCopyOptions(b.store, options.ReportWriter, nil, systemContext, "")); err != nil {
if manifestBytes, err = cp.Image(ctx, policyContext, maybeCachedDest, maybeCachedSrc, getCopyOptions(b.store, options.ReportWriter, nil, systemContext, "", false, options.SignBy)); err != nil {
return imgID, nil, "", errors.Wrapf(err, "error copying layers and metadata for container %q", b.ContainerID)
}
// If we've got more names to attach, and we know how to do that for
@ -426,7 +433,7 @@ func Push(ctx context.Context, image string, dest types.ImageReference, options
systemContext.DirForceCompress = true
}
var manifestBytes []byte
if manifestBytes, err = cp.Image(ctx, policyContext, dest, maybeCachedSrc, getCopyOptions(options.Store, options.ReportWriter, nil, systemContext, options.ManifestType)); err != nil {
if manifestBytes, err = cp.Image(ctx, policyContext, dest, maybeCachedSrc, getCopyOptions(options.Store, options.ReportWriter, nil, systemContext, options.ManifestType, options.RemoveSignatures, options.SignBy)); err != nil {
return nil, "", errors.Wrapf(err, "error copying layers and metadata from %q to %q", transports.ImageName(maybeCachedSrc), transports.ImageName(dest))
}
if options.ReportWriter != nil {

View File

@ -18,7 +18,7 @@ const (
DOCKER = "docker"
)
func getCopyOptions(store storage.Store, reportWriter io.Writer, sourceSystemContext *types.SystemContext, destinationSystemContext *types.SystemContext, manifestType string) *cp.Options {
func getCopyOptions(store storage.Store, reportWriter io.Writer, sourceSystemContext *types.SystemContext, destinationSystemContext *types.SystemContext, manifestType string, removeSignatures bool, addSigner string) *cp.Options {
sourceCtx := getSystemContext(store, nil, "")
if sourceSystemContext != nil {
*sourceCtx = *sourceSystemContext
@ -33,6 +33,8 @@ func getCopyOptions(store storage.Store, reportWriter io.Writer, sourceSystemCon
SourceCtx: sourceCtx,
DestinationCtx: destinationCtx,
ForceManifestMIMEType: manifestType,
RemoveSignatures: removeSignatures,
SignBy: addSigner,
}
}

View File

@ -326,6 +326,7 @@ return 1
--format
-f
--iidfile
--sign-by
"
local all_options="$options_with_args $boolean_options"
@ -415,6 +416,7 @@ return 1
--runtime-flag
--security-opt
--shm-size
--sign-by
-t
--tag
--target
@ -577,6 +579,7 @@ return 1
--quiet
-q
--tls-verify
--remove-signatures
"
local options_with_args="
@ -603,6 +606,7 @@ return 1
--quiet
-q
--tls-verify
--remove-signatures
"
local options_with_args="
@ -611,6 +615,7 @@ return 1
--creds
--format
-f
--sign-by
"
local all_options="$options_with_args $boolean_options"
@ -810,6 +815,7 @@ return 1
--help
-h
--all
--remove-signatures
"
local options_with_args="
@ -818,6 +824,7 @@ return 1
--creds
--digestfile
--purge
--sign-by
--tls-verify
"

View File

@ -414,6 +414,10 @@ Size of `/dev/shm`. The format is `<number><unit>`. `number` must be greater tha
Unit is optional and can be `b` (bytes), `k` (kilobytes), `m`(megabytes), or `g` (gigabytes).
If you omit the unit, the system uses bytes. If you omit the size entirely, the system uses `64m`.
**--sign-by** *fingerprint*
Sign the built image using the GPG key that matches the specified fingerprint.
**--squash**
Squash all of the new image's layers (including those inherited from a base image) into a single new layer.

View File

@ -64,6 +64,10 @@ When writing the output image, suppress progress output.
Remove the container and its content after committing it to an image.
Default leaves the container and its content in place.
**--sign-by** *fingerprint*
Sign the new image using the GPG key that matches the specified fingerprint.
**--squash**
Squash all of the new image's layers (including those inherited from a base image) into a single new layer.

View File

@ -47,6 +47,14 @@ After copying the image, write the digest of the resulting image to the file.
Delete the manifest list or image index from local storage if pushing succeeds.
**--remove-signatures**
Don't copy signatures when pushing images.
**--sign-by** *fingerprint*
Sign the pushed images using the GPG key that matches the specified fingerprint.
**--tls-verify** *bool-value*
Require HTTPS and verify certificates when talking to container registries (defaults to true)

View File

@ -66,6 +66,10 @@ value can be entered. The password is entered without echo.
If an image needs to be pulled from the registry, suppress progress output.
**--remove-signatures**
Don't copy signatures when pulling images.
**--shm-size**=""
Size of `/dev/shm`. The format is `<number><unit>`. `number` must be greater than `0`.

View File

@ -1,4 +1,4 @@
# buildah-push"1" "June 2017" "buildah"
# buildah-push "1" "June 2017" "buildah"
## NAME
buildah\-push - Push an image from local storage to elsewhere.
@ -74,6 +74,14 @@ Manifest Type (oci, v2s1, or v2s2) to use when saving image to directory using t
When writing the output image, suppress progress output.
**--remove-signatures**
Don't copy signatures when pushing images.
**--sign-by** *fingerprint*
Sign the pushed image using the GPG key that matches the specified fingerprint.
**--tls-verify** *bool-value*
Require HTTPS and verify certificates when talking to container registries (defaults to true)

View File

@ -1,4 +1,4 @@
# buildah-rename "9" "July 2018" "buildah"
# buildah-rename "1" "July 2018" "buildah"
## NAME
buildah\-rename - Rename a local container.

View File

@ -152,12 +152,14 @@ type BuildOptions struct {
ForceRmIntermediateCtrs bool
// BlobDirectory is a directory which we'll use for caching layer blobs.
BlobDirectory string
// Target the targeted FROM in the Dockerfile to build
// Target the targeted FROM in the Dockerfile to build.
Target string
// Devices are the additional devices to add to the containers
// Devices are the additional devices to add to the containers.
Devices []configs.Device
//DefaultEnv for containers
// DefaultEnv for containers.
DefaultEnv []string
// SignBy is the fingerprint of a GPG key to use for signing images.
SignBy string
}
// BuildDockerfiles parses a set of one or more Dockerfiles (which may be

View File

@ -93,6 +93,7 @@ type Executor struct {
buildArgs map[string]string
capabilities []string
devices []configs.Device
signBy string
}
// NewExecutor creates a new instance of the imagebuilder.Executor interface.
@ -149,6 +150,7 @@ func NewExecutor(store storage.Store, options BuildOptions, mainNode *parser.Nod
buildArgs: options.Args,
capabilities: options.Capabilities,
devices: options.Devices,
signBy: options.SignBy,
}
if exec.err == nil {
exec.err = os.Stderr

View File

@ -1203,6 +1203,7 @@ func (s *StageExecutor) commit(ctx context.Context, ib *imagebuilder.Builder, cr
Squash: s.executor.squash,
EmptyLayer: emptyLayer,
BlobDirectory: s.executor.blobDirectory,
SignBy: s.executor.signBy,
}
imgID, _, manifestDigest, err := s.builder.Commit(ctx, imageRef, options)
if err != nil {

View File

@ -53,6 +53,8 @@ type PushOptions struct {
ImageListSelection cp.ImageListSelection // set to either CopySystemImage, CopyAllImages, or CopySpecificImages
Instances []digest.Digest // instances to copy if ImageListSelection == CopySpecificImages
ReportWriter io.Writer // will be used to log the writing of the list and any blobs
SignBy string // fingerprint of GPG key to use to sign images
RemoveSignatures bool // true to discard signatures in images
}
// Create creates a new list containing information about the specified image,
@ -211,6 +213,8 @@ func (l *list) Push(ctx context.Context, dest types.ImageReference, options Push
SourceCtx: options.SystemContext,
DestinationCtx: options.SystemContext,
ReportWriter: options.ReportWriter,
RemoveSignatures: options.RemoveSignatures,
SignBy: options.SignBy,
}
// Copy whatever we were asked to copy.

View File

@ -70,6 +70,7 @@ type BudResults struct {
Runtime string
RuntimeFlags []string
SignaturePolicy string
SignBy string
Squash bool
Tag []string
Target string
@ -168,8 +169,9 @@ func GetBudFlags(flags *BudResults) pflag.FlagSet {
fs.BoolVar(&flags.Rm, "rm", true, "Remove intermediate containers after a successful build")
// "runtime" definition moved to avoid name collision in podman build. Defined in cmd/buildah/bud.go.
fs.StringSliceVar(&flags.RuntimeFlags, "runtime-flag", []string{}, "add global flags for the container runtime")
fs.StringVar(&flags.SignBy, "sign-by", "", "sign the image using a GPG key with the specified `FINGERPRINT`")
fs.StringVar(&flags.SignaturePolicy, "signature-policy", "", "`pathname` of signature policy file (not usually used)")
fs.BoolVar(&flags.Squash, "squash", false, "Squash newly built layers into a single new layer.")
fs.BoolVar(&flags.Squash, "squash", false, "squash newly built layers into a single new layer")
fs.StringArrayVarP(&flags.Tag, "tag", "t", []string{}, "tagged `name` to apply to the built image")
fs.StringVar(&flags.Target, "target", "", "set the target build stage to build")
fs.BoolVar(&flags.TLSVerify, "tls-verify", true, "require HTTPS and verify certificates when accessing the registry")

View File

@ -49,6 +49,9 @@ type PullOptions struct {
// AllTags is a boolean value that determines if all tagged images
// will be downloaded from the repository. The default is false.
AllTags bool
// RemoveSignatures causes any existing signatures for the image to be
// discarded when pulling it.
RemoveSignatures bool
}
func localImageNameForReference(ctx context.Context, store storage.Store, srcRef types.ImageReference) (string, error) {
@ -260,7 +263,7 @@ func pullImage(ctx context.Context, store storage.Store, srcRef types.ImageRefer
}()
logrus.Debugf("copying %q to %q", transports.ImageName(srcRef), destName)
if _, err := cp.Image(ctx, policyContext, maybeCachedDestRef, srcRef, getCopyOptions(store, options.ReportWriter, sc, nil, "")); err != nil {
if _, err := cp.Image(ctx, policyContext, maybeCachedDestRef, srcRef, getCopyOptions(store, options.ReportWriter, sc, nil, "", options.RemoveSignatures, "")); err != nil {
logrus.Debugf("error copying src image [%q] to dest image [%q] err: %v", transports.ImageName(srcRef), destName, err)
return nil, err
}

94
tests/sign.bats Normal file
View File

@ -0,0 +1,94 @@
#!/usr/bin/env bats
load helpers
@test "commit-pull-push-signatures" {
if ! which gpg > /dev/null 2> /dev/null ; then
skip 'gpg command not found in $PATH'
fi
export GNUPGHOME=${TESTDIR}/.gnupg
cat > genkey-answers <<- EOF
%echo Generating a basic OpenPGP key
Key-Type: RSA
Key-Length: 512
Name-Real: Amanda Lorian
Name-Comment: Mandy to her friends
Name-Email: amanda@localhost
%commit
%echo done
EOF
gpg --batch --gen-key < genkey-answers
mkdir -p ${TESTDIR}/signed-image ${TESTDIR}/unsigned-image
run_buildah from --quiet --pull=false --signature-policy ${TESTSDIR}/policy.json alpine
cid=$output
run_buildah commit --signature-policy ${TESTSDIR}/policy.json --sign-by amanda@localhost $cid signed-alpine-image
# Pushing should preserve the signature.
run_buildah push --signature-policy ${TESTSDIR}/policy.json signed-alpine-image dir:${TESTDIR}/signed-image
ls -l ${TESTDIR}/signed-image/
test -s ${TESTDIR}/signed-image/signature-1
# Pushing with --remove-signatures should remove the signature.
run_buildah push --signature-policy ${TESTSDIR}/policy.json --remove-signatures signed-alpine-image dir:${TESTDIR}/unsigned-image
ls -l ${TESTDIR}/unsigned-image/
! test -s ${TESTDIR}/unsigned-image/signature-1
run_buildah commit --signature-policy ${TESTSDIR}/policy.json $cid unsigned-alpine-image
# Pushing with --sign-by should fail add the signature to a dir: location, if it tries to add them.
run_buildah 1 push --signature-policy ${TESTSDIR}/policy.json --sign-by amanda@localhost unsigned-alpine-image dir:${TESTDIR}/signed-image
expect_output --substring "Cannot determine canonical Docker reference"
# Clear out images, so that we don't have leftover signatures when we pull in an image that will end up
# causing us to merge its contents with the image with the same ID.
run_buildah rmi -a -f
# Pulling with --remove-signatures should remove signatures, and pushing should have none to keep.
run_buildah pull --signature-policy ${TESTSDIR}/policy.json --quiet dir:${TESTDIR}/signed-image
imageID="$output"
run_buildah push --signature-policy ${TESTSDIR}/policy.json "$imageID" dir:${TESTDIR}/unsigned-image
ls -l ${TESTDIR}/unsigned-image/
! test -s ${TESTDIR}/unsigned-image/signature-1
# Build a manifest list and try to push the list with signatures.
run_buildah manifest create list
run_buildah manifest add list $imageID
run_buildah 1 manifest push --signature-policy ${TESTSDIR}/policy.json --sign-by amanda@localhost --all list dir:${TESTDIR}/signed-image
expect_output --substring "Cannot determine canonical Docker reference"
run_buildah manifest push --signature-policy ${TESTSDIR}/policy.json --all list dir:${TESTDIR}/unsigned-image
}
@test "build-with-dockerfile-signatures" {
if ! which gpg > /dev/null 2> /dev/null ; then
skip 'gpg command not found in $PATH'
fi
export GNUPGHOME=${TESTDIR}/.gnupg
cat > genkey-answers <<- EOF
%echo Generating a basic OpenPGP key
Key-Type: RSA
Key-Length: 512
Name-Real: Amanda Lorian
Name-Comment: Mandy to her friends
Name-Email: amanda@localhost
%commit
%echo done
EOF
gpg --batch --gen-key < genkey-answers
cat > Dockerfile <<- EOF
FROM scratch
ADD Dockerfile /
EOF
# We should be able to sign at build-time.
run_buildah bud --signature-policy ${TESTSDIR}/policy.json --sign-by amanda@localhost -t signed-scratch-image .
mkdir -p ${TESTDIR}/signed-image
# Pushing should preserve the signature.
run_buildah push --signature-policy ${TESTSDIR}/policy.json signed-scratch-image dir:${TESTDIR}/signed-image
ls -l ${TESTDIR}/signed-image/
test -s ${TESTDIR}/signed-image/signature-1
}