Skip to content

Commit 4866f51

Browse files
authored
Merge pull request #39365 from tiborvass/deprecate-v2-schema1
Keep but deprecate registry v2 schema1 logic and revert to libtrust-key-based engine ID
2 parents 8d13092 + 3f1cdd5 commit 4866f51

30 files changed

Lines changed: 571 additions & 972 deletions

Dockerfile

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,13 +51,25 @@ RUN apt-get update && apt-get install -y \
5151
&& make PREFIX=/build/ install-criu
5252

5353
FROM base AS registry
54+
# Install two versions of the registry. The first is an older version that
55+
# only supports schema1 manifests. The second is a newer version that supports
56+
# both. This allows integration-cli tests to cover push/pull with both schema1
57+
# and schema2 manifests.
58+
ENV REGISTRY_COMMIT_SCHEMA1 ec87e9b6971d831f0eff752ddb54fb64693e51cd
5459
ENV REGISTRY_COMMIT 47a064d4195a9b56133891bbb13620c3ac83a827
5560
RUN set -x \
5661
&& export GOPATH="$(mktemp -d)" \
5762
&& git clone https://github.com/docker/distribution.git "$GOPATH/src/github.com/docker/distribution" \
5863
&& (cd "$GOPATH/src/github.com/docker/distribution" && git checkout -q "$REGISTRY_COMMIT") \
5964
&& GOPATH="$GOPATH/src/github.com/docker/distribution/Godeps/_workspace:$GOPATH" \
6065
go build -buildmode=pie -o /build/registry-v2 github.com/docker/distribution/cmd/registry \
66+
&& case $(dpkg --print-architecture) in \
67+
amd64|ppc64*|s390x) \
68+
(cd "$GOPATH/src/github.com/docker/distribution" && git checkout -q "$REGISTRY_COMMIT_SCHEMA1"); \
69+
GOPATH="$GOPATH/src/github.com/docker/distribution/Godeps/_workspace:$GOPATH"; \
70+
go build -buildmode=pie -o /build/registry-v2-schema1 github.com/docker/distribution/cmd/registry; \
71+
;; \
72+
esac \
6173
&& rm -rf "$GOPATH"
6274

6375

cmd/dockerd/config.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ import (
1212
const (
1313
// defaultShutdownTimeout is the default shutdown timeout for the daemon
1414
defaultShutdownTimeout = 15
15+
// defaultTrustKeyFile is the default filename for the trust key
16+
defaultTrustKeyFile = "key.json"
1517
)
1618

1719
// installCommonConfigFlags adds flags to the pflag.FlagSet to configure the daemon

cmd/dockerd/daemon.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -429,6 +429,14 @@ func loadDaemonCliConfig(opts *daemonOptions) (*config.Config, error) {
429429
conf.CommonTLSOptions.KeyFile = opts.TLSOptions.KeyFile
430430
}
431431

432+
if conf.TrustKeyPath == "" {
433+
daemonConfDir, err := getDaemonConfDir(conf.Root)
434+
if err != nil {
435+
return nil, err
436+
}
437+
conf.TrustKeyPath = filepath.Join(daemonConfDir, defaultTrustKeyFile)
438+
}
439+
432440
if flags.Changed("graph") && flags.Changed("data-root") {
433441
return nil, errors.New(`cannot specify both "--graph" and "--data-root" option`)
434442
}

cmd/dockerd/daemon_unix.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,10 @@ func setDefaultUmask() error {
5858
return nil
5959
}
6060

61+
func getDaemonConfDir(_ string) (string, error) {
62+
return getDefaultDaemonConfigDir()
63+
}
64+
6165
func (cli *DaemonCli) getPlatformContainerdDaemonOpts() ([]supervisor.DaemonOpt, error) {
6266
opts := []supervisor.DaemonOpt{
6367
supervisor.WithOOMScore(cli.Config.OOMScoreAdjust),

cmd/dockerd/daemon_windows.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"fmt"
66
"net"
77
"os"
8+
"path/filepath"
89
"time"
910

1011
"github.com/docker/docker/daemon/config"
@@ -23,6 +24,10 @@ func setDefaultUmask() error {
2324
return nil
2425
}
2526

27+
func getDaemonConfDir(root string) (string, error) {
28+
return filepath.Join(root, `\config`), nil
29+
}
30+
2631
// preNotifySystem sends a message to the host when the API is active, but before the daemon is
2732
func preNotifySystem() {
2833
// start the service now to prevent timeouts waiting for daemon to start

daemon/config/config.go

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,8 @@ var flatOptions = map[string]bool{
6363
var skipValidateOptions = map[string]bool{
6464
"features": true,
6565
"builder": true,
66+
// Corresponding flag has been removed because it was already unusable
67+
"deprecated-key-path": true,
6668
}
6769

6870
// skipDuplicates contains configuration keys that
@@ -134,6 +136,12 @@ type CommonConfig struct {
134136
SocketGroup string `json:"group,omitempty"`
135137
CorsHeaders string `json:"api-cors-header,omitempty"`
136138

139+
// TrustKeyPath is used to generate the daemon ID and for signing schema 1 manifests
140+
// when pushing to a registry which does not support schema 2. This field is marked as
141+
// deprecated because schema 1 manifests are deprecated in favor of schema 2 and the
142+
// daemon ID will use a dedicated identifier not shared with exported signatures.
143+
TrustKeyPath string `json:"deprecated-key-path,omitempty"`
144+
137145
// LiveRestoreEnabled determines whether we should keep containers
138146
// alive upon daemon shutdown/start
139147
LiveRestoreEnabled bool `json:"live-restore,omitempty"`
@@ -239,7 +247,6 @@ func New() *Config {
239247
config := Config{}
240248
config.LogConfig.Config = make(map[string]string)
241249
config.ClusterOpts = make(map[string]string)
242-
243250
return &config
244251
}
245252

daemon/daemon.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -973,7 +973,7 @@ func NewDaemon(ctx context.Context, config *config.Config, pluginStore *plugin.S
973973
return nil, err
974974
}
975975

976-
uuid, err := loadOrCreateUUID(filepath.Join(config.Root, "engine_uuid"))
976+
trustKey, err := loadOrCreateTrustKey(config.TrustKeyPath)
977977
if err != nil {
978978
return nil, err
979979
}
@@ -1018,7 +1018,7 @@ func NewDaemon(ctx context.Context, config *config.Config, pluginStore *plugin.S
10181018
return nil, errors.New("Devices cgroup isn't mounted")
10191019
}
10201020

1021-
d.ID = uuid
1021+
d.ID = trustKey.PublicKey().KeyID()
10221022
d.repository = daemonRepo
10231023
d.containers = container.NewMemoryStore()
10241024
if d.containersReplica, err = container.NewViewDB(); err != nil {
@@ -1049,6 +1049,7 @@ func NewDaemon(ctx context.Context, config *config.Config, pluginStore *plugin.S
10491049
MaxConcurrentUploads: *config.MaxConcurrentUploads,
10501050
ReferenceStore: rs,
10511051
RegistryService: registryService,
1052+
TrustKey: trustKey,
10521053
})
10531054

10541055
go d.execCommandGC()

daemon/images/image_push.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ func (i *ImageService) PushImage(ctx context.Context, image, tag string, metaHea
5454
},
5555
ConfigMediaType: schema2.MediaTypeImageConfig,
5656
LayerStores: distribution.NewLayerProvidersFromStores(i.layerStores),
57+
TrustKey: i.trustKey,
5758
UploadManager: i.uploadManager,
5859
}
5960

daemon/images/service.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import (
1414
"github.com/docker/docker/layer"
1515
dockerreference "github.com/docker/docker/reference"
1616
"github.com/docker/docker/registry"
17+
"github.com/docker/libtrust"
1718
"github.com/opencontainers/go-digest"
1819
"github.com/pkg/errors"
1920
"github.com/sirupsen/logrus"
@@ -39,6 +40,7 @@ type ImageServiceConfig struct {
3940
MaxConcurrentUploads int
4041
ReferenceStore dockerreference.Store
4142
RegistryService registry.Service
43+
TrustKey libtrust.PrivateKey
4244
}
4345

4446
// NewImageService returns a new ImageService from a configuration
@@ -54,6 +56,7 @@ func NewImageService(config ImageServiceConfig) *ImageService {
5456
layerStores: config.LayerStores,
5557
referenceStore: config.ReferenceStore,
5658
registryService: config.RegistryService,
59+
trustKey: config.TrustKey,
5760
uploadManager: xfer.NewLayerUploadManager(config.MaxConcurrentUploads),
5861
}
5962
}
@@ -69,6 +72,7 @@ type ImageService struct {
6972
pruneRunning int32
7073
referenceStore dockerreference.Store
7174
registryService registry.Service
75+
trustKey libtrust.PrivateKey
7276
uploadManager *xfer.LayerUploadManager
7377
}
7478

daemon/trustkey.go

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
package daemon // import "github.com/docker/docker/daemon"
2+
3+
import (
4+
"encoding/json"
5+
"encoding/pem"
6+
"fmt"
7+
"os"
8+
"path/filepath"
9+
10+
"github.com/docker/docker/pkg/ioutils"
11+
"github.com/docker/docker/pkg/system"
12+
"github.com/docker/libtrust"
13+
)
14+
15+
// LoadOrCreateTrustKey attempts to load the libtrust key at the given path,
16+
// otherwise generates a new one
17+
// TODO: this should use more of libtrust.LoadOrCreateTrustKey which may need
18+
// a refactor or this function to be moved into libtrust
19+
func loadOrCreateTrustKey(trustKeyPath string) (libtrust.PrivateKey, error) {
20+
err := system.MkdirAll(filepath.Dir(trustKeyPath), 0755, "")
21+
if err != nil {
22+
return nil, err
23+
}
24+
trustKey, err := libtrust.LoadKeyFile(trustKeyPath)
25+
if err == libtrust.ErrKeyFileDoesNotExist {
26+
trustKey, err = libtrust.GenerateECP256PrivateKey()
27+
if err != nil {
28+
return nil, fmt.Errorf("Error generating key: %s", err)
29+
}
30+
encodedKey, err := serializePrivateKey(trustKey, filepath.Ext(trustKeyPath))
31+
if err != nil {
32+
return nil, fmt.Errorf("Error serializing key: %s", err)
33+
}
34+
if err := ioutils.AtomicWriteFile(trustKeyPath, encodedKey, os.FileMode(0600)); err != nil {
35+
return nil, fmt.Errorf("Error saving key file: %s", err)
36+
}
37+
} else if err != nil {
38+
return nil, fmt.Errorf("Error loading key file %s: %s", trustKeyPath, err)
39+
}
40+
return trustKey, nil
41+
}
42+
43+
func serializePrivateKey(key libtrust.PrivateKey, ext string) (encoded []byte, err error) {
44+
if ext == ".json" || ext == ".jwk" {
45+
encoded, err = json.Marshal(key)
46+
if err != nil {
47+
return nil, fmt.Errorf("unable to encode private key JWK: %s", err)
48+
}
49+
} else {
50+
pemBlock, err := key.PEMBlock()
51+
if err != nil {
52+
return nil, fmt.Errorf("unable to encode private key PEM: %s", err)
53+
}
54+
encoded = pem.EncodeToMemory(pemBlock)
55+
}
56+
return
57+
}

0 commit comments

Comments
 (0)