Add credentials to buildah from

Signed-off-by: TomSweeneyRedHat <tsweeney@redhat.com>

Add credentials to buildah from

Signed-off-by: TomSweeneyRedHat <tsweeney@redhat.com>

Closes: #204
Approved by: nalind
This commit is contained in:
TomSweeneyRedHat 2017-07-20 20:02:11 -04:00 committed by Atomic Bot
parent ee91e6b981
commit 498f0ae9d7
11 changed files with 187 additions and 6 deletions

View File

@ -5,6 +5,8 @@ go:
- tip
dist: trusty
sudo: required
services:
- docker
before_install:
- sudo add-apt-repository -y ppa:duggan/bats
- sudo apt-get -qq update

View File

@ -7,6 +7,7 @@ import (
"os"
"path/filepath"
"github.com/containers/image/types"
"github.com/containers/storage"
"github.com/containers/storage/pkg/ioutils"
"github.com/opencontainers/image-spec/specs-go/v1"
@ -122,6 +123,9 @@ type BuilderOptions struct {
// ReportWriter is an io.Writer which will be used to log the reading
// of the source image from a registry, if we end up pulling the image.
ReportWriter io.Writer
// github.com/containers/image/types SystemContext to hold credentials
// and other authentication/authorization information.
SystemContext *types.SystemContext
}
// ImportOptions are used to initialize a Builder from an existing container

View File

@ -19,6 +19,11 @@ var (
Name: "disable-compression, D",
Usage: "don't compress layers",
},
cli.StringFlag{
Name: "creds",
Value: "",
Usage: "use `username[:password]` for accessing the registry",
},
cli.StringFlag{
Name: "signature-policy",
Usage: "`pathname` of signature policy file (not usually used)",

View File

@ -2,9 +2,12 @@ package main
import (
"os"
"strings"
"syscall"
"time"
is "github.com/containers/image/storage"
"github.com/containers/image/types"
"github.com/containers/storage"
digest "github.com/opencontainers/go-digest"
"github.com/pkg/errors"
@ -108,3 +111,50 @@ func getDateAndDigestAndSize(image storage.Image, store storage.Store) (time.Tim
}
return created, manifestDigest, imgSize, err
}
// systemContextFromOptions returns a SystemContext populated with values
// per the input parameters provided by the caller for the use in authentication.
func systemContextFromOptions(c *cli.Context) (*types.SystemContext, error) {
ctx := &types.SystemContext{
DockerCertPath: c.String("cert-dir"),
}
if c.IsSet("tls-verify") {
ctx.DockerInsecureSkipTLSVerify = !c.BoolT("tls-verify")
}
if c.IsSet("creds") {
var err error
ctx.DockerAuthConfig, err = getDockerAuth(c.String("creds"))
if err != nil {
return nil, err
}
}
if c.IsSet("signature-policy") {
ctx.SignaturePolicyPath = c.String("signature-policy")
}
return ctx, nil
}
func parseCreds(creds string) (string, string, error) {
if creds == "" {
return "", "", errors.Wrapf(syscall.EINVAL, "credentials can't be empty")
}
up := strings.SplitN(creds, ":", 2)
if len(up) == 1 {
return up[0], "", nil
}
if up[0] == "" {
return "", "", errors.Wrapf(syscall.EINVAL, "username can't be empty")
}
return up[0], up[1], nil
}
func getDockerAuth(creds string) (*types.DockerAuthConfig, error) {
username, password, err := parseCreds(creds)
if err != nil {
return nil, err
}
return &types.DockerAuthConfig{
Username: username,
Password: password,
}, nil
}

View File

@ -35,6 +35,20 @@ var (
Usage: "`prefix` to prepend to the image name in order to pull the image",
Value: DefaultTransport,
},
cli.StringFlag{
Name: "cert-dir",
Value: "",
Usage: "use certificates at the specified path to access the registry",
},
cli.StringFlag{
Name: "creds",
Value: "",
Usage: "use `username[:password]` for accessing the registry",
},
cli.StringFlag{
Name: "tls-verify",
Usage: "Require HTTPS and verify certificates when accessing the registry",
},
cli.StringFlag{
Name: "signature-policy",
Usage: "`pathname` of signature policy file (not usually used)",
@ -65,12 +79,18 @@ func fromCmd(c *cli.Context) error {
if len(args) > 1 {
return errors.Errorf("too many arguments specified")
}
image := args[0]
image := args[0]
transport := DefaultTransport
if c.IsSet("transport") {
transport = c.String("transport")
}
systemContext, err := systemContextFromOptions(c)
if err != nil {
return errors.Errorf("error building system context [%v]", err)
}
pull := true
if c.IsSet("pull") {
pull = c.BoolT("pull")
@ -113,6 +133,7 @@ func fromCmd(c *cli.Context) error {
PullPolicy: pullPolicy,
Transport: transport,
SignaturePolicyPath: signaturePolicy,
SystemContext: systemContext,
}
if !quiet {
options.ReportWriter = os.Stderr

View File

@ -249,7 +249,8 @@ func (b *Builder) Commit(dest types.ImageReference, options CommitOptions) error
}
if exporting {
// Copy everything.
err = cp.Image(policyContext, dest, src, getCopyOptions(options.ReportWriter))
// TODO: add credsContext
err = cp.Image(policyContext, dest, src, getCopyOptions(options.ReportWriter, nil, nil))
if err != nil {
return errors.Wrapf(err, "error copying layers and metadata")
}
@ -321,7 +322,8 @@ func Push(image string, dest types.ImageReference, options PushOptions) error {
return errors.Wrapf(err, "error recomputing layer digests and building metadata")
}
// Copy everything.
err = cp.Image(policyContext, dest, src, getCopyOptions(options.ReportWriter))
// TODO: add credsContext
err = cp.Image(policyContext, dest, src, getCopyOptions(options.ReportWriter, nil, nil))
if err != nil {
return errors.Wrapf(err, "error copying layers and metadata")
}

View File

@ -7,9 +7,11 @@ import (
"github.com/containers/image/types"
)
func getCopyOptions(reportWriter io.Writer) *cp.Options {
func getCopyOptions(reportWriter io.Writer, sourceSystemContext *types.SystemContext, destinationSystemContext *types.SystemContext) *cp.Options {
return &cp.Options{
ReportWriter: reportWriter,
ReportWriter: reportWriter,
SourceCtx: sourceSystemContext,
DestinationCtx: destinationSystemContext,
}
}

View File

@ -618,9 +618,12 @@ return 1
"
local options_with_args="
--cert-dir
--creds
--name
--transport
--signature-policy
--tls-verify
"

View File

@ -15,6 +15,14 @@ The container ID of the container that was created. On error, -1 is returned an
## OPTIONS
**--cert-dir** *path*
Use certificates at *path* (*.crt, *.cert, *.key) to connect to the registry
**--creds** *creds*
The username and password to use to authenticate with the registry if required.
**--name** *name*
A *name* for the working container
@ -41,6 +49,10 @@ Pathname of a signature policy file to use. It is not recommended that this
option be used, as the default behavior of using the system-wide default policy
(frequently */etc/containers/policy.json*) is most often preferred.
**--tls-verify** *bool-value*
Require HTTPS and verify certificates when talking to container registries (defaults to true)
**--quiet**
If an image needs to be pulled from the registry, suppress progress output.
@ -55,5 +67,7 @@ buildah from imagename --signature-policy /etc/containers/policy.json
buildah from imagename --pull-always --transport "docker://myregistry.example.com/" --name "mycontainer"
buildah from myregistry/myrepository/imagename:imagetag --creds=myusername:mypassword
## SEE ALSO
buildah(1)

View File

@ -109,6 +109,6 @@ func pullImage(store storage.Store, options BuilderOptions, sc *types.SystemCont
logrus.Debugf("copying %q to %q", spec, name)
err = cp.Image(policyContext, destRef, srcRef, getCopyOptions(options.ReportWriter))
err = cp.Image(policyContext, destRef, srcRef, getCopyOptions(options.ReportWriter, options.SystemContext, nil))
return destRef, err
}

View File

@ -34,3 +34,81 @@ load helpers
buildah rmi ${elsewhere}
[ "$cid" = `basename ${elsewhere}`-working-container ]
}
@test "from-authenticate-cert" {
mkdir -p ${TESTDIR}/auth
# Create certifcate via openssl
openssl req -newkey rsa:4096 -nodes -sha256 -keyout ${TESTDIR}/auth/domain.key -x509 -days 2 -out ${TESTDIR}/auth/domain.crt -subj "/C=US/ST=Foo/L=Bar/O=Red Hat, Inc./CN=localhost"
# Skopeo and buildah both require *.cert file
cp ${TESTDIR}/auth/domain.crt ${TESTDIR}/auth/domain.cert
# Create a private registry that uses certificate and creds file
# docker run -d -p 5000:5000 --name registry -v ${TESTDIR}/auth:${TESTDIR}/auth:Z -e REGISTRY_HTTP_TLS_CERTIFICATE=${TESTDIR}/auth/domain.crt -e REGISTRY_HTTP_TLS_KEY=${TESTDIR}/auth/domain.key registry:2
# When more buildah auth is in place convert the below.
# docker pull alpine
# docker tag alpine localhost:5000/my-alpine
# docker push localhost:5000/my-alpine
# ctrid=$(buildah from localhost:5000/my-alpine --cert-dir ${TESTDIR}/auth)
# buildah rm $ctrid
# buildah rmi -f $(buildah --debug=false images -q)
# This should work
# ctrid=$(buildah from localhost:5000/my-alpine --cert-dir ${TESTDIR}/auth --tls-verify true)
rm -rf ${TESTDIR}/auth
# This should fail
run ctrid=$(buildah from localhost:5000/my-alpine --cert-dir ${TESTDIR}/auth --tls-verify true)
[ "$status" -ne 0 ]
# Clean up
# docker rm -f $(docker ps --all -q)
# docker rmi -f localhost:5000/my-alpine
# docker rmi -f $(docker images -q)
# buildah rm $ctrid
# buildah rmi -f $(buildah --debug=false images -q)
}
@test "from-authenticate-cert-and-creds" {
mkdir -p ${TESTDIR}/auth
# Create creds and store in ${TESTDIR}/auth/htpasswd
# docker run --entrypoint htpasswd registry:2 -Bbn testuser testpassword > ${TESTDIR}/auth/htpasswd
# Create certifcate via openssl
openssl req -newkey rsa:4096 -nodes -sha256 -keyout ${TESTDIR}/auth/domain.key -x509 -days 2 -out ${TESTDIR}/auth/domain.crt -subj "/C=US/ST=Foo/L=Bar/O=Red Hat, Inc./CN=localhost"
# Skopeo and buildah both require *.cert file
cp ${TESTDIR}/auth/domain.crt ${TESTDIR}/auth/domain.cert
# Create a private registry that uses certificate and creds file
# docker run -d -p 5000:5000 --name registry -v ${TESTDIR}/auth:${TESTDIR}/auth:Z -e "REGISTRY_AUTH=htpasswd" -e "REGISTRY_AUTH_HTPASSWD_REALM=Registry Realm" -e REGISTRY_AUTH_HTPASSWD_PATH=${TESTDIR}/auth/htpasswd -e REGISTRY_HTTP_TLS_CERTIFICATE=${TESTDIR}/auth/domain.crt -e REGISTRY_HTTP_TLS_KEY=${TESTDIR}/auth/domain.key registry:2
# When more buildah auth is in place convert the below.
# docker pull alpine
# docker login localhost:5000 --username testuser --password testpassword
# docker tag alpine localhost:5000/my-alpine
# docker push localhost:5000/my-alpine
# ctrid=$(buildah from localhost:5000/my-alpine --cert-dir ${TESTDIR}/auth)
# buildah rm $ctrid
# buildah rmi -f $(buildah --debug=false images -q)
# docker logout localhost:5000
# This should fail
run ctrid=$(buildah from localhost:5000/my-alpine --cert-dir ${TESTDIR}/auth --tls-verify true)
[ "$status" -ne 0 ]
# This should work
# ctrid=$(buildah from localhost:5000/my-alpine --cert-dir ${TESTDIR}/auth --tls-verify true --creds=testuser:testpassword)
# Clean up
rm -rf ${TESTDIR}/auth
# docker rm -f $(docker ps --all -q)
# docker rmi -f localhost:5000/my-alpine
# docker rmi -f $(docker images -q)
# buildah rm $ctrid
# buildah rmi -f $(buildah --debug=false images -q)
}