Signed-off-by: Daniel Nephin <dnephin@docker.com>
Daniel Nephin authored on 2017/09/07 00:44:11... | ... |
@@ -1,17 +1,5 @@ |
1 | 1 |
package api |
2 | 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 | 3 |
// Common constants for daemon and client. |
16 | 4 |
const ( |
17 | 5 |
// DefaultVersion of Current REST API |
... | ... |
@@ -21,45 +9,3 @@ const ( |
21 | 21 |
// command to specify that no base image is to be used. |
22 | 22 |
NoBaseImageSpecifier string = "scratch" |
23 | 23 |
) |
24 |
- |
|
25 |
-// LoadOrCreateTrustKey attempts to load the libtrust key at the given path, |
|
26 |
-// otherwise generates a new one |
|
27 |
-func LoadOrCreateTrustKey(trustKeyPath string) (libtrust.PrivateKey, error) { |
|
28 |
- err := system.MkdirAll(filepath.Dir(trustKeyPath), 0700, "") |
|
29 |
- if err != nil { |
|
30 |
- return nil, err |
|
31 |
- } |
|
32 |
- trustKey, err := libtrust.LoadKeyFile(trustKeyPath) |
|
33 |
- if err == libtrust.ErrKeyFileDoesNotExist { |
|
34 |
- trustKey, err = libtrust.GenerateECP256PrivateKey() |
|
35 |
- if err != nil { |
|
36 |
- return nil, fmt.Errorf("Error generating key: %s", err) |
|
37 |
- } |
|
38 |
- encodedKey, err := serializePrivateKey(trustKey, filepath.Ext(trustKeyPath)) |
|
39 |
- if err != nil { |
|
40 |
- return nil, fmt.Errorf("Error serializing key: %s", err) |
|
41 |
- } |
|
42 |
- if err := ioutils.AtomicWriteFile(trustKeyPath, encodedKey, os.FileMode(0600)); err != nil { |
|
43 |
- return nil, fmt.Errorf("Error saving key file: %s", err) |
|
44 |
- } |
|
45 |
- } else if err != nil { |
|
46 |
- return nil, fmt.Errorf("Error loading key file %s: %s", trustKeyPath, err) |
|
47 |
- } |
|
48 |
- return trustKey, nil |
|
49 |
-} |
|
50 |
- |
|
51 |
-func serializePrivateKey(key libtrust.PrivateKey, ext string) (encoded []byte, err error) { |
|
52 |
- if ext == ".json" || ext == ".jwk" { |
|
53 |
- encoded, err = json.Marshal(key) |
|
54 |
- if err != nil { |
|
55 |
- return nil, fmt.Errorf("unable to encode private key JWK: %s", err) |
|
56 |
- } |
|
57 |
- } else { |
|
58 |
- pemBlock, err := key.PEMBlock() |
|
59 |
- if err != nil { |
|
60 |
- return nil, fmt.Errorf("unable to encode private key PEM: %s", err) |
|
61 |
- } |
|
62 |
- encoded = pem.EncodeToMemory(pemBlock) |
|
63 |
- } |
|
64 |
- return |
|
65 |
-} |
66 | 24 |
deleted file mode 100644 |
... | ... |
@@ -1,77 +0,0 @@ |
1 |
-package api |
|
2 |
- |
|
3 |
-import ( |
|
4 |
- "io/ioutil" |
|
5 |
- "path/filepath" |
|
6 |
- "testing" |
|
7 |
- |
|
8 |
- "os" |
|
9 |
-) |
|
10 |
- |
|
11 |
-// LoadOrCreateTrustKey |
|
12 |
-func TestLoadOrCreateTrustKeyInvalidKeyFile(t *testing.T) { |
|
13 |
- tmpKeyFolderPath, err := ioutil.TempDir("", "api-trustkey-test") |
|
14 |
- if err != nil { |
|
15 |
- t.Fatal(err) |
|
16 |
- } |
|
17 |
- defer os.RemoveAll(tmpKeyFolderPath) |
|
18 |
- |
|
19 |
- tmpKeyFile, err := ioutil.TempFile(tmpKeyFolderPath, "keyfile") |
|
20 |
- if err != nil { |
|
21 |
- t.Fatal(err) |
|
22 |
- } |
|
23 |
- |
|
24 |
- if _, err := LoadOrCreateTrustKey(tmpKeyFile.Name()); err == nil { |
|
25 |
- t.Fatal("expected an error, got nothing.") |
|
26 |
- } |
|
27 |
- |
|
28 |
-} |
|
29 |
- |
|
30 |
-func TestLoadOrCreateTrustKeyCreateKey(t *testing.T) { |
|
31 |
- tmpKeyFolderPath, err := ioutil.TempDir("", "api-trustkey-test") |
|
32 |
- if err != nil { |
|
33 |
- t.Fatal(err) |
|
34 |
- } |
|
35 |
- defer os.RemoveAll(tmpKeyFolderPath) |
|
36 |
- |
|
37 |
- // Without the need to create the folder hierarchy |
|
38 |
- tmpKeyFile := filepath.Join(tmpKeyFolderPath, "keyfile") |
|
39 |
- |
|
40 |
- if key, err := LoadOrCreateTrustKey(tmpKeyFile); err != nil || key == nil { |
|
41 |
- t.Fatalf("expected a new key file, got : %v and %v", err, key) |
|
42 |
- } |
|
43 |
- |
|
44 |
- if _, err := os.Stat(tmpKeyFile); err != nil { |
|
45 |
- t.Fatalf("Expected to find a file %s, got %v", tmpKeyFile, err) |
|
46 |
- } |
|
47 |
- |
|
48 |
- // With the need to create the folder hierarchy as tmpKeyFie is in a path |
|
49 |
- // where some folders do not exist. |
|
50 |
- tmpKeyFile = filepath.Join(tmpKeyFolderPath, "folder/hierarchy/keyfile") |
|
51 |
- |
|
52 |
- if key, err := LoadOrCreateTrustKey(tmpKeyFile); err != nil || key == nil { |
|
53 |
- t.Fatalf("expected a new key file, got : %v and %v", err, key) |
|
54 |
- } |
|
55 |
- |
|
56 |
- if _, err := os.Stat(tmpKeyFile); err != nil { |
|
57 |
- t.Fatalf("Expected to find a file %s, got %v", tmpKeyFile, err) |
|
58 |
- } |
|
59 |
- |
|
60 |
- // With no path at all |
|
61 |
- defer os.Remove("keyfile") |
|
62 |
- if key, err := LoadOrCreateTrustKey("keyfile"); err != nil || key == nil { |
|
63 |
- t.Fatalf("expected a new key file, got : %v and %v", err, key) |
|
64 |
- } |
|
65 |
- |
|
66 |
- if _, err := os.Stat("keyfile"); err != nil { |
|
67 |
- t.Fatalf("Expected to find a file keyfile, got %v", err) |
|
68 |
- } |
|
69 |
-} |
|
70 |
- |
|
71 |
-func TestLoadOrCreateTrustKeyLoadValidKey(t *testing.T) { |
|
72 |
- tmpKeyFile := filepath.Join("fixtures", "keyfile") |
|
73 |
- |
|
74 |
- if key, err := LoadOrCreateTrustKey(tmpKeyFile); err != nil || key == nil { |
|
75 |
- t.Fatalf("expected a key file, got : %v and %v", err, key) |
|
76 |
- } |
|
77 |
-} |
78 | 1 |
deleted file mode 100644 |
... | ... |
@@ -1,7 +0,0 @@ |
1 |
-keyID: AWX2:I27X:WQFX:IOMK:CNAK:O7PW:VYNB:ZLKC:CVAE:YJP2:SI4A:XXAY |
|
2 |
- |
|
3 |
-MHcCAQEEILHTRWdcpKWsnORxSFyBnndJ4ROU41hMtr/GCiLVvwBQoAoGCCqGSM49 |
|
4 |
-AwEHoUQDQgAElpVFbQ2V2UQKajqdE3fVxJ+/pE/YuEFOxWbOxF2be19BY209/iky |
|
5 |
-NzeFFK7SLpQ4CBJ7zDVXOHsMzrkY/GquGA== |
... | ... |
@@ -19,7 +19,6 @@ import ( |
19 | 19 |
"time" |
20 | 20 |
|
21 | 21 |
containerd "github.com/containerd/containerd/api/grpc/types" |
22 |
- "github.com/docker/docker/api" |
|
23 | 22 |
"github.com/docker/docker/api/types" |
24 | 23 |
containertypes "github.com/docker/docker/api/types/container" |
25 | 24 |
"github.com/docker/docker/api/types/swarm" |
... | ... |
@@ -713,7 +712,7 @@ func NewDaemon(config *config.Config, registryService registry.Service, containe |
713 | 713 |
return nil, err |
714 | 714 |
} |
715 | 715 |
|
716 |
- trustKey, err := api.LoadOrCreateTrustKey(config.TrustKeyPath) |
|
716 |
+ trustKey, err := loadOrCreateTrustKey(config.TrustKeyPath) |
|
717 | 717 |
if err != nil { |
718 | 718 |
return nil, err |
719 | 719 |
} |
720 | 720 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,7 @@ |
0 |
+-----BEGIN EC PRIVATE KEY----- |
|
1 |
+keyID: AWX2:I27X:WQFX:IOMK:CNAK:O7PW:VYNB:ZLKC:CVAE:YJP2:SI4A:XXAY |
|
2 |
+ |
|
3 |
+MHcCAQEEILHTRWdcpKWsnORxSFyBnndJ4ROU41hMtr/GCiLVvwBQoAoGCCqGSM49 |
|
4 |
+AwEHoUQDQgAElpVFbQ2V2UQKajqdE3fVxJ+/pE/YuEFOxWbOxF2be19BY209/iky |
|
5 |
+NzeFFK7SLpQ4CBJ7zDVXOHsMzrkY/GquGA== |
|
6 |
+-----END EC PRIVATE KEY----- |
0 | 7 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,57 @@ |
0 |
+package daemon |
|
1 |
+ |
|
2 |
+import ( |
|
3 |
+ "encoding/json" |
|
4 |
+ "encoding/pem" |
|
5 |
+ "fmt" |
|
6 |
+ "os" |
|
7 |
+ "path/filepath" |
|
8 |
+ |
|
9 |
+ "github.com/docker/docker/pkg/ioutils" |
|
10 |
+ "github.com/docker/docker/pkg/system" |
|
11 |
+ "github.com/docker/libtrust" |
|
12 |
+) |
|
13 |
+ |
|
14 |
+// LoadOrCreateTrustKey attempts to load the libtrust key at the given path, |
|
15 |
+// otherwise generates a new one |
|
16 |
+// TODO: this should use more of libtrust.LoadOrCreateTrustKey which may need |
|
17 |
+// a refactor or this function to be moved into libtrust |
|
18 |
+func loadOrCreateTrustKey(trustKeyPath string) (libtrust.PrivateKey, error) { |
|
19 |
+ err := system.MkdirAll(filepath.Dir(trustKeyPath), 0700, "") |
|
20 |
+ if err != nil { |
|
21 |
+ return nil, err |
|
22 |
+ } |
|
23 |
+ trustKey, err := libtrust.LoadKeyFile(trustKeyPath) |
|
24 |
+ if err == libtrust.ErrKeyFileDoesNotExist { |
|
25 |
+ trustKey, err = libtrust.GenerateECP256PrivateKey() |
|
26 |
+ if err != nil { |
|
27 |
+ return nil, fmt.Errorf("Error generating key: %s", err) |
|
28 |
+ } |
|
29 |
+ encodedKey, err := serializePrivateKey(trustKey, filepath.Ext(trustKeyPath)) |
|
30 |
+ if err != nil { |
|
31 |
+ return nil, fmt.Errorf("Error serializing key: %s", err) |
|
32 |
+ } |
|
33 |
+ if err := ioutils.AtomicWriteFile(trustKeyPath, encodedKey, os.FileMode(0600)); err != nil { |
|
34 |
+ return nil, fmt.Errorf("Error saving key file: %s", err) |
|
35 |
+ } |
|
36 |
+ } else if err != nil { |
|
37 |
+ return nil, fmt.Errorf("Error loading key file %s: %s", trustKeyPath, err) |
|
38 |
+ } |
|
39 |
+ return trustKey, nil |
|
40 |
+} |
|
41 |
+ |
|
42 |
+func serializePrivateKey(key libtrust.PrivateKey, ext string) (encoded []byte, err error) { |
|
43 |
+ if ext == ".json" || ext == ".jwk" { |
|
44 |
+ encoded, err = json.Marshal(key) |
|
45 |
+ if err != nil { |
|
46 |
+ return nil, fmt.Errorf("unable to encode private key JWK: %s", err) |
|
47 |
+ } |
|
48 |
+ } else { |
|
49 |
+ pemBlock, err := key.PEMBlock() |
|
50 |
+ if err != nil { |
|
51 |
+ return nil, fmt.Errorf("unable to encode private key PEM: %s", err) |
|
52 |
+ } |
|
53 |
+ encoded = pem.EncodeToMemory(pemBlock) |
|
54 |
+ } |
|
55 |
+ return |
|
56 |
+} |
0 | 57 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,72 @@ |
0 |
+package daemon |
|
1 |
+ |
|
2 |
+import ( |
|
3 |
+ "io/ioutil" |
|
4 |
+ "os" |
|
5 |
+ "path/filepath" |
|
6 |
+ "testing" |
|
7 |
+ |
|
8 |
+ "github.com/docker/docker/internal/testutil" |
|
9 |
+ "github.com/gotestyourself/gotestyourself/fs" |
|
10 |
+ "github.com/stretchr/testify/assert" |
|
11 |
+ "github.com/stretchr/testify/require" |
|
12 |
+) |
|
13 |
+ |
|
14 |
+// LoadOrCreateTrustKey |
|
15 |
+func TestLoadOrCreateTrustKeyInvalidKeyFile(t *testing.T) { |
|
16 |
+ tmpKeyFolderPath, err := ioutil.TempDir("", "api-trustkey-test") |
|
17 |
+ require.NoError(t, err) |
|
18 |
+ defer os.RemoveAll(tmpKeyFolderPath) |
|
19 |
+ |
|
20 |
+ tmpKeyFile, err := ioutil.TempFile(tmpKeyFolderPath, "keyfile") |
|
21 |
+ require.NoError(t, err) |
|
22 |
+ |
|
23 |
+ _, err = loadOrCreateTrustKey(tmpKeyFile.Name()) |
|
24 |
+ testutil.ErrorContains(t, err, "Error loading key file") |
|
25 |
+} |
|
26 |
+ |
|
27 |
+func TestLoadOrCreateTrustKeyCreateKeyWhenFileDoesNotExist(t *testing.T) { |
|
28 |
+ tmpKeyFolderPath := fs.NewDir(t, "api-trustkey-test") |
|
29 |
+ defer tmpKeyFolderPath.Remove() |
|
30 |
+ |
|
31 |
+ // Without the need to create the folder hierarchy |
|
32 |
+ tmpKeyFile := tmpKeyFolderPath.Join("keyfile") |
|
33 |
+ |
|
34 |
+ key, err := loadOrCreateTrustKey(tmpKeyFile) |
|
35 |
+ require.NoError(t, err) |
|
36 |
+ assert.NotNil(t, key) |
|
37 |
+ |
|
38 |
+ _, err = os.Stat(tmpKeyFile) |
|
39 |
+ require.NoError(t, err, "key file doesn't exist") |
|
40 |
+} |
|
41 |
+ |
|
42 |
+func TestLoadOrCreateTrustKeyCreateKeyWhenDirectoryDoesNotExist(t *testing.T) { |
|
43 |
+ tmpKeyFolderPath := fs.NewDir(t, "api-trustkey-test") |
|
44 |
+ defer tmpKeyFolderPath.Remove() |
|
45 |
+ tmpKeyFile := tmpKeyFolderPath.Join("folder/hierarchy/keyfile") |
|
46 |
+ |
|
47 |
+ key, err := loadOrCreateTrustKey(tmpKeyFile) |
|
48 |
+ require.NoError(t, err) |
|
49 |
+ assert.NotNil(t, key) |
|
50 |
+ |
|
51 |
+ _, err = os.Stat(tmpKeyFile) |
|
52 |
+ require.NoError(t, err, "key file doesn't exist") |
|
53 |
+} |
|
54 |
+ |
|
55 |
+func TestLoadOrCreateTrustKeyCreateKeyNoPath(t *testing.T) { |
|
56 |
+ defer os.Remove("keyfile") |
|
57 |
+ key, err := loadOrCreateTrustKey("keyfile") |
|
58 |
+ require.NoError(t, err) |
|
59 |
+ assert.NotNil(t, key) |
|
60 |
+ |
|
61 |
+ _, err = os.Stat("keyfile") |
|
62 |
+ require.NoError(t, err, "key file doesn't exist") |
|
63 |
+} |
|
64 |
+ |
|
65 |
+func TestLoadOrCreateTrustKeyLoadValidKey(t *testing.T) { |
|
66 |
+ tmpKeyFile := filepath.Join("testdata", "keyfile") |
|
67 |
+ key, err := loadOrCreateTrustKey(tmpKeyFile) |
|
68 |
+ require.NoError(t, err) |
|
69 |
+ expected := "AWX2:I27X:WQFX:IOMK:CNAK:O7PW:VYNB:ZLKC:CVAE:YJP2:SI4A:XXAY" |
|
70 |
+ assert.Contains(t, key.String(), expected) |
|
71 |
+} |