Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
112 changes: 59 additions & 53 deletions pkg/cmd/dockerregistry/dockerregistry.go
Original file line number Diff line number Diff line change
Expand Up @@ -157,21 +157,32 @@ func Execute(configFile io.Reader) {
log.Fatalf("error configuring logger: %v", err)
}

err = Start(ctx, dockerConfig, extraConfig)
// inject a logger into the uuid library. warns us if there is a problem
// with uuid generation under low entropy.
uuid.Loggerf = context.GetLogger(ctx).Warnf

context.GetLoggerWithFields(ctx, versionFields()).Info("start registry")

srv, err := NewServer(ctx, dockerConfig, extraConfig)
if err != nil {
log.Fatal(err)
}

if dockerConfig.HTTP.TLS.Certificate == "" {
context.GetLogger(ctx).Infof("listening on %s", srv.Addr)
err = srv.ListenAndServe()
} else {
context.GetLogger(ctx).Infof("listening on %s, tls", srv.Addr)
err = srv.ListenAndServeTLS(dockerConfig.HTTP.TLS.Certificate, dockerConfig.HTTP.TLS.Key)
}
if err != nil {
log.Fatal(err)
}
}

// Start runs the Docker registry. Start always returns a non-nil error.
func Start(ctx context.Context, dockerConfig *configuration.Configuration, extraConfig *registryconfig.Configuration) error {
func NewServer(ctx context.Context, dockerConfig *configuration.Configuration, extraConfig *registryconfig.Configuration) (*http.Server, error) {
setDefaultLogParameters(dockerConfig)

context.GetLoggerWithFields(ctx, versionFields()).Info("start registry")
// inject a logger into the uuid library. warns us if there is a problem
// with uuid generation under low entropy.
uuid.Loggerf = context.GetLogger(ctx).Warnf

registryClient := client.NewRegistryClient(clientcmd.NewConfig().BindToFile(extraConfig.KubeConfig))

readLimiter := newLimiter(extraConfig.Requests.Read)
Expand All @@ -186,67 +197,62 @@ func Start(ctx context.Context, dockerConfig *configuration.Configuration, extra
handler = panicHandler(handler)
handler = gorillahandlers.CombinedLoggingHandler(os.Stdout, handler)

if dockerConfig.HTTP.TLS.Certificate == "" {
context.GetLogger(ctx).Infof("listening on %v", dockerConfig.HTTP.Addr)
return http.ListenAndServe(dockerConfig.HTTP.Addr, handler)
}

var (
minVersion uint16
cipherSuites []uint16
err error
)
if s := os.Getenv("REGISTRY_HTTP_TLS_MINVERSION"); len(s) > 0 {
minVersion, err = crypto.TLSVersion(s)
if err != nil {
return fmt.Errorf("invalid TLS version %q specified in REGISTRY_HTTP_TLS_MINVERSION: %v (valid values are %q)", s, err, crypto.ValidTLSVersions())
}
}
if s := os.Getenv("REGISTRY_HTTP_TLS_CIPHERSUITES"); len(s) > 0 {
for _, cipher := range strings.Split(s, ",") {
cipherSuite, err := crypto.CipherSuite(cipher)
var tlsConf *tls.Config
if dockerConfig.HTTP.TLS.Certificate != "" {
var (
minVersion uint16
cipherSuites []uint16
err error
)
if s := os.Getenv("REGISTRY_HTTP_TLS_MINVERSION"); len(s) > 0 {
minVersion, err = crypto.TLSVersion(s)
if err != nil {
return fmt.Errorf("invalid cipher suite %q specified in REGISTRY_HTTP_TLS_CIPHERSUITES: %v (valid suites are %q)", s, err, crypto.ValidCipherSuites())
return nil, fmt.Errorf("invalid TLS version %q specified in REGISTRY_HTTP_TLS_MINVERSION: %v (valid values are %q)", s, err, crypto.ValidTLSVersions())
}
cipherSuites = append(cipherSuites, cipherSuite)
}
}
if s := os.Getenv("REGISTRY_HTTP_TLS_CIPHERSUITES"); len(s) > 0 {
for _, cipher := range strings.Split(s, ",") {
cipherSuite, err := crypto.CipherSuite(cipher)
if err != nil {
return nil, fmt.Errorf("invalid cipher suite %q specified in REGISTRY_HTTP_TLS_CIPHERSUITES: %v (valid suites are %q)", s, err, crypto.ValidCipherSuites())
}
cipherSuites = append(cipherSuites, cipherSuite)
}
}
tlsConf = crypto.SecureTLSConfig(&tls.Config{
ClientAuth: tls.NoClientCert,
MinVersion: minVersion,
CipherSuites: cipherSuites,
})

tlsConf := crypto.SecureTLSConfig(&tls.Config{
ClientAuth: tls.NoClientCert,
MinVersion: minVersion,
CipherSuites: cipherSuites,
})
if len(dockerConfig.HTTP.TLS.ClientCAs) != 0 {
pool := x509.NewCertPool()

if len(dockerConfig.HTTP.TLS.ClientCAs) != 0 {
pool := x509.NewCertPool()
for _, ca := range dockerConfig.HTTP.TLS.ClientCAs {
caPem, err := ioutil.ReadFile(ca)
if err != nil {
return nil, err
}

for _, ca := range dockerConfig.HTTP.TLS.ClientCAs {
caPem, err := ioutil.ReadFile(ca)
if err != nil {
return err
if ok := pool.AppendCertsFromPEM(caPem); !ok {
return nil, fmt.Errorf("could not add CA to pool")
}
}

if ok := pool.AppendCertsFromPEM(caPem); !ok {
return fmt.Errorf("could not add CA to pool")
for _, subj := range pool.Subjects() {
context.GetLogger(ctx).Debugf("CA Subject: %s", string(subj))
}
}

for _, subj := range pool.Subjects() {
context.GetLogger(ctx).Debugf("CA Subject: %s", string(subj))
tlsConf.ClientAuth = tls.RequireAndVerifyClientCert
tlsConf.ClientCAs = pool
}

tlsConf.ClientAuth = tls.RequireAndVerifyClientCert
tlsConf.ClientCAs = pool
}

context.GetLogger(ctx).Infof("listening on %v, tls", dockerConfig.HTTP.Addr)
server := &http.Server{
return &http.Server{
Addr: dockerConfig.HTTP.Addr,
Handler: handler,
TLSConfig: tlsConf,
}
return server.ListenAndServeTLS(dockerConfig.HTTP.TLS.Certificate, dockerConfig.HTTP.TLS.Key)
}, nil
}

// configureLogging prepares the context with a logger using the
Expand Down
2 changes: 1 addition & 1 deletion pkg/dockerregistry/server/blobdescriptorservice_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ func TestBlobDescriptorServiceIsApplied(t *testing.T) {
t.Fatalf("error parsing server url: %v", err)
}

desc, _, err := registrytest.UploadRandomTestBlob(ctx, serverURL, nil, "user/app")
desc, _, err := registrytest.UploadRandomTestBlob(ctx, serverURL.String(), nil, "user/app")
if err != nil {
t.Fatal(err)
}
Expand Down
4 changes: 2 additions & 2 deletions pkg/dockerregistry/server/pullthroughblobstore_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,11 +54,11 @@ func TestPullthroughServeBlob(t *testing.T) {
})
registrytest.AddImage(t, fos, testImage, namespace, name, "latest")

blob1Desc, blob1Content, err := registrytest.UploadRandomTestBlob(backgroundCtx, serverURL, nil, repoName)
blob1Desc, blob1Content, err := registrytest.UploadRandomTestBlob(backgroundCtx, serverURL.String(), nil, repoName)
if err != nil {
t.Fatal(err)
}
blob2Desc, blob2Content, err := registrytest.UploadRandomTestBlob(backgroundCtx, serverURL, nil, repoName)
blob2Desc, blob2Content, err := registrytest.UploadRandomTestBlob(backgroundCtx, serverURL.String(), nil, repoName)
if err != nil {
t.Fatal(err)
}
Expand Down
2 changes: 1 addition & 1 deletion pkg/dockerregistry/testutil/manifests.go
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ func CreateAndUploadTestManifest(
)

for i := 0; i < layerCount; i++ {
ds, _, err := UploadRandomTestBlob(ctx, serverURL, creds, repoName)
ds, _, err := UploadRandomTestBlob(ctx, serverURL.String(), creds, repoName)
if err != nil {
return "", "", "", nil, fmt.Errorf("unexpected error generating test blob layer: %v", err)
}
Expand Down
61 changes: 57 additions & 4 deletions pkg/dockerregistry/testutil/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"archive/tar"
"bytes"
"crypto/rand"
"encoding/json"
"fmt"
"io"
mrand "math/rand"
Expand Down Expand Up @@ -106,18 +107,18 @@ func UploadManifest(ctx context.Context, repo distribution.Repository, tag strin
}

// UploadRandomTestBlob generates a random tar file and uploads it to the given repository.
func UploadRandomTestBlob(ctx context.Context, serverURL *url.URL, creds auth.CredentialStore, repoName string) (distribution.Descriptor, []byte, error) {
func UploadRandomTestBlob(ctx context.Context, baseURL string, creds auth.CredentialStore, repoName string) (distribution.Descriptor, []byte, error) {
payload, desc, err := MakeRandomLayer()
if err != nil {
return distribution.Descriptor{}, nil, fmt.Errorf("unexpected error generating test layer file: %v", err)
}

rt, err := NewTransport(serverURL.String(), repoName, creds)
rt, err := NewTransport(baseURL, repoName, creds)
if err != nil {
return distribution.Descriptor{}, nil, err
}

repo, err := NewRepository(ctx, repoName, serverURL.String(), rt)
repo, err := NewRepository(ctx, repoName, baseURL, rt)
if err != nil {
return distribution.Descriptor{}, nil, err
}
Expand Down Expand Up @@ -180,7 +181,7 @@ func CreateRandomTarFile() ([]byte, error) {

// CreateRandomImage creates an image with a random content.
func CreateRandomImage(namespace, name string) (*imageapiv1.Image, error) {
const layersCount = 3
const layersCount = 2

layersDescs := make([]distribution.Descriptor, layersCount)
for i := range layersDescs {
Expand Down Expand Up @@ -297,3 +298,55 @@ func ping(manager challenge.Manager, endpoint, versionHeader string) ([]auth.API

return auth.APIVersions(resp, versionHeader), nil
}

// UploadSchema2Image creates a random image with a schema 2 manifest and
// uploads it to the repository.
func UploadSchema2Image(ctx context.Context, repo distribution.Repository, tag string) (distribution.Manifest, error) {
const layersCount = 2

layers := make([]distribution.Descriptor, layersCount)
for i := range layers {
content, desc, err := MakeRandomLayer()
if err != nil {
return nil, fmt.Errorf("make random layer: %v", err)
}

if err := UploadBlob(ctx, repo, desc, content); err != nil {
return nil, fmt.Errorf("upload random blob: %v", err)
}

layers[i] = desc
}

cfg := map[string]interface{}{
"rootfs": map[string]interface{}{
"diff_ids": make([]string, len(layers)),
},
"history": make([]struct{}, len(layers)),
}

configContent, err := json.Marshal(&cfg)
if err != nil {
return nil, fmt.Errorf("marshal image config: %v", err)
}

config := distribution.Descriptor{
Digest: digest.FromBytes(configContent),
Size: int64(len(configContent)),
}

if err := UploadBlob(ctx, repo, config, configContent); err != nil {
return nil, fmt.Errorf("upload image config: %v", err)
}

manifest, err := MakeSchema2Manifest(config, layers)
if err != nil {
return manifest, fmt.Errorf("make schema 2 manifest: %v", err)
}

if err := UploadManifest(ctx, repo, tag, manifest); err != nil {
return manifest, fmt.Errorf("upload schema 2 manifest: %v", err)
}

return manifest, nil
}
Loading