Add X-Registry-Config support

* Refactor auth pkg to support X-Registry-Config
* Refactor build endpoint to support X-Registry-Config. Supports:
  * --creds
  * --authfile
* Added X-Reference-Id Header to http.Request to support log event
  correlation
* Log headers from http.Request

Signed-off-by: Jhon Honce <jhonce@redhat.com>
This commit is contained in:
Jhon Honce
2020-09-23 08:19:05 -07:00
parent 2ee415be90
commit 5aead1509c
85 changed files with 3208 additions and 984 deletions

View File

@ -93,7 +93,7 @@ func PruneImages(w http.ResponseWriter, r *http.Request) {
})
}
//FIXME/TODO to do this exactly correct, pruneimages needs to return idrs and space-reclaimed, then we are golden
// FIXME/TODO to do this exactly correct, pruneimages needs to return idrs and space-reclaimed, then we are golden
ipr := types.ImagesPruneReport{
ImagesDeleted: idr,
SpaceReclaimed: 1, // TODO we cannot supply this right now
@ -113,7 +113,7 @@ func CommitContainer(w http.ResponseWriter, r *http.Request) {
Changes string `schema:"changes"`
Comment string `schema:"comment"`
Container string `schema:"container"`
//fromSrc string # fromSrc is currently unused
// fromSrc string # fromSrc is currently unused
Pause bool `schema:"pause"`
Repo string `schema:"repo"`
Tag string `schema:"tag"`
@ -224,7 +224,7 @@ func CreateImageFromSrc(w http.ResponseWriter, r *http.Request) {
Status string `json:"status"`
Progress string `json:"progress"`
ProgressDetail map[string]string `json:"progressDetail"`
Id string `json:"id"` //nolint
Id string `json:"id"` // nolint
}{
Status: iid,
ProgressDetail: map[string]string{},
@ -257,9 +257,9 @@ func CreateImageFromImage(w http.ResponseWriter, r *http.Request) {
fromImage = fmt.Sprintf("%s:%s", fromImage, query.Tag)
}
authConf, authfile, err := auth.GetCredentials(r)
authConf, authfile, key, err := auth.GetCredentials(r)
if err != nil {
utils.Error(w, "Something went wrong.", http.StatusBadRequest, errors.Wrapf(err, "Failed to parse %q header for %s", auth.XRegistryAuthHeader, r.URL.String()))
utils.Error(w, "Failed to retrieve repository credentials", http.StatusBadRequest, errors.Wrapf(err, "Failed to parse %q header for %s", key, r.URL.String()))
return
}
defer auth.RemoveAuthfile(authfile)
@ -299,7 +299,7 @@ func CreateImageFromImage(w http.ResponseWriter, r *http.Request) {
Error string `json:"error"`
Progress string `json:"progress"`
ProgressDetail map[string]string `json:"progressDetail"`
Id string `json:"id"` //nolint
Id string `json:"id"` // nolint
}{
Status: fmt.Sprintf("pulling image (%s) from %s", img.Tag, strings.Join(img.Names(), ", ")),
ProgressDetail: map[string]string{},

View File

@ -2,7 +2,6 @@ package compat
import (
"context"
"encoding/base64"
"encoding/json"
"fmt"
"io"
@ -11,13 +10,13 @@ import (
"os"
"path/filepath"
"strconv"
"strings"
"github.com/containers/buildah"
"github.com/containers/buildah/imagebuildah"
"github.com/containers/image/v5/types"
"github.com/containers/podman/v2/libpod"
"github.com/containers/podman/v2/pkg/api/handlers"
"github.com/containers/podman/v2/pkg/api/handlers/utils"
"github.com/containers/podman/v2/pkg/auth"
"github.com/containers/podman/v2/pkg/channel"
"github.com/containers/storage/pkg/archive"
"github.com/gorilla/schema"
@ -26,15 +25,6 @@ import (
)
func BuildImage(w http.ResponseWriter, r *http.Request) {
authConfigs := map[string]handlers.AuthConfig{}
if hdr, found := r.Header["X-Registry-Config"]; found && len(hdr) > 0 {
authConfigsJSON := base64.NewDecoder(base64.URLEncoding, strings.NewReader(hdr[0]))
if json.NewDecoder(authConfigsJSON).Decode(&authConfigs) != nil {
utils.BadRequest(w, "X-Registry-Config", hdr[0], json.NewDecoder(authConfigsJSON).Decode(&authConfigs))
return
}
}
if hdr, found := r.Header["Content-Type"]; found && len(hdr) > 0 {
contentType := hdr[0]
switch contentType {
@ -151,6 +141,14 @@ func BuildImage(w http.ResponseWriter, r *http.Request) {
}
}
creds, authfile, key, err := auth.GetCredentials(r)
if err != nil {
// Credential value(s) not returned as their value is not human readable
utils.BadRequest(w, key.String(), "n/a", err)
return
}
defer auth.RemoveAuthfile(authfile)
// Channels all mux'ed in select{} below to follow API build protocol
stdout := channel.NewWriter(make(chan []byte, 1))
defer stdout.Close()
@ -179,6 +177,10 @@ func BuildImage(w http.ResponseWriter, r *http.Request) {
Err: auxout,
ReportWriter: reporter,
OutputFormat: buildah.Dockerv2ImageManifest,
SystemContext: &types.SystemContext{
AuthFilePath: authfile,
DockerAuthConfig: creds,
},
CommonBuildOpts: &buildah.CommonBuildOptions{
CPUPeriod: query.CpuPeriod,
CPUQuota: query.CpuQuota,

View File

@ -49,9 +49,9 @@ func PushImage(w http.ResponseWriter, r *http.Request) {
return
}
authConf, authfile, err := auth.GetCredentials(r)
authConf, authfile, key, err := auth.GetCredentials(r)
if err != nil {
utils.Error(w, "Something went wrong.", http.StatusBadRequest, errors.Wrapf(err, "Failed to parse %q header for %s", auth.XRegistryAuthHeader, r.URL.String()))
utils.Error(w, "Something went wrong.", http.StatusBadRequest, errors.Wrapf(err, "Failed to parse %q header for %s", key, r.URL.String()))
return
}
defer auth.RemoveAuthfile(authfile)

View File

@ -438,9 +438,9 @@ func PushImage(w http.ResponseWriter, r *http.Request) {
return
}
authConf, authfile, err := auth.GetCredentials(r)
authConf, authfile, key, err := auth.GetCredentials(r)
if err != nil {
utils.Error(w, "Something went wrong.", http.StatusBadRequest, errors.Wrapf(err, "Failed to parse %q header for %s", auth.XRegistryAuthHeader, r.URL.String()))
utils.Error(w, "Failed to retrieve repository credentials", http.StatusBadRequest, errors.Wrapf(err, "Failed to parse %q header for %s", key, r.URL.String()))
return
}
defer auth.RemoveAuthfile(authfile)

View File

@ -74,9 +74,9 @@ func ImagesPull(w http.ResponseWriter, r *http.Request) {
return
}
authConf, authfile, err := auth.GetCredentials(r)
authConf, authfile, key, err := auth.GetCredentials(r)
if err != nil {
utils.Error(w, "Something went wrong.", http.StatusBadRequest, errors.Wrapf(err, "Failed to parse %q header for %s", auth.XRegistryAuthHeader, r.URL.String()))
utils.Error(w, "Failed to retrieve repository credentials", http.StatusBadRequest, errors.Wrapf(err, "Failed to parse %q header for %s", key, r.URL.String()))
return
}
defer auth.RemoveAuthfile(authfile)

View File

@ -48,9 +48,9 @@ func PlayKube(w http.ResponseWriter, r *http.Request) {
utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "error closing temporary file"))
return
}
authConf, authfile, err := auth.GetCredentials(r)
authConf, authfile, key, err := auth.GetCredentials(r)
if err != nil {
utils.Error(w, "Something went wrong.", http.StatusBadRequest, errors.Wrapf(err, "Failed to parse %q header for %s", auth.XRegistryAuthHeader, r.URL.String()))
utils.Error(w, "Failed to retrieve repository credentials", http.StatusBadRequest, errors.Wrapf(err, "Failed to parse %q header for %s", key, r.URL.String()))
return
}
defer auth.RemoveAuthfile(authfile)

View File

@ -7,7 +7,9 @@ import (
"runtime"
"github.com/containers/podman/v2/pkg/api/handlers/utils"
log "github.com/sirupsen/logrus"
"github.com/containers/podman/v2/pkg/auth"
"github.com/google/uuid"
"github.com/sirupsen/logrus"
)
// APIHandler is a wrapper to enhance HandlerFunc's and remove redundant code
@ -19,7 +21,7 @@ func (s *APIServer) APIHandler(h http.HandlerFunc) http.HandlerFunc {
if err != nil {
buf := make([]byte, 1<<20)
n := runtime.Stack(buf, true)
log.Warnf("Recovering from API handler panic: %v, %s", err, buf[:n])
logrus.Warnf("Recovering from API handler panic: %v, %s", err, buf[:n])
// Try to inform client things went south... won't work if handler already started writing response body
utils.InternalServerError(w, fmt.Errorf("%v", err))
}
@ -27,10 +29,23 @@ func (s *APIServer) APIHandler(h http.HandlerFunc) http.HandlerFunc {
// Wrapper to hide some boiler plate
fn := func(w http.ResponseWriter, r *http.Request) {
log.Debugf("APIHandler -- Method: %s URL: %s", r.Method, r.URL.String())
rid := uuid.New().String()
if logrus.IsLevelEnabled(logrus.DebugLevel) {
logrus.Debugf("APIHandler(%s) -- Method: %s URL: %s", rid, r.Method, r.URL.String())
for k, v := range r.Header {
switch auth.HeaderAuthName(k) {
case auth.XRegistryConfigHeader, auth.XRegistryAuthHeader:
logrus.Debugf("APIHandler(%s) -- Header: %s: <hidden>", rid, k)
default:
logrus.Debugf("APIHandler(%s) -- Header: %s: %v", rid, k, v)
}
}
}
// Set in case handler wishes to correlate logging events
r.Header.Set("X-Reference-Id", rid)
if err := r.ParseForm(); err != nil {
log.Infof("Failed Request: unable to parse form: %q", err)
logrus.Infof("Failed Request: unable to parse form: %q (%s)", err, rid)
}
// TODO: Use r.ConnContext when ported to go 1.13