Explorar o código

Atomically save libtrust key file

The libtrust keyfile which is used to set the "ID" property of a daemon must be generated or loaded on every startup.
If the process crashes during startup this could cause the file to be incomplete causing future startup errors.
Ensure that the file is written atomically to ensure the file is never in an incomplete state.

Fixes #23985

Signed-off-by: Derek McGowan <derek@mcgstyle.net> (github: dmcgowan)
Derek McGowan %!s(int64=9) %!d(string=hai) anos
pai
achega
9836162446
Modificáronse 1 ficheiros con 25 adicións e 1 borrados
  1. 25 1
      api/common.go

+ 25 - 1
api/common.go

@@ -1,14 +1,18 @@
 package api
 package api
 
 
 import (
 import (
+	"encoding/json"
+	"encoding/pem"
 	"fmt"
 	"fmt"
 	"mime"
 	"mime"
+	"os"
 	"path/filepath"
 	"path/filepath"
 	"sort"
 	"sort"
 	"strconv"
 	"strconv"
 	"strings"
 	"strings"
 
 
 	"github.com/Sirupsen/logrus"
 	"github.com/Sirupsen/logrus"
+	"github.com/docker/docker/pkg/ioutils"
 	"github.com/docker/docker/pkg/system"
 	"github.com/docker/docker/pkg/system"
 	"github.com/docker/engine-api/types"
 	"github.com/docker/engine-api/types"
 	"github.com/docker/libtrust"
 	"github.com/docker/libtrust"
@@ -135,7 +139,11 @@ func LoadOrCreateTrustKey(trustKeyPath string) (libtrust.PrivateKey, error) {
 		if err != nil {
 		if err != nil {
 			return nil, fmt.Errorf("Error generating key: %s", err)
 			return nil, fmt.Errorf("Error generating key: %s", err)
 		}
 		}
-		if err := libtrust.SaveKey(trustKeyPath, trustKey); err != nil {
+		encodedKey, err := serializePrivateKey(trustKey, filepath.Ext(trustKeyPath))
+		if err != nil {
+			return nil, fmt.Errorf("Error serializing key: %s", err)
+		}
+		if err := ioutils.AtomicWriteFile(trustKeyPath, encodedKey, os.FileMode(0600)); err != nil {
 			return nil, fmt.Errorf("Error saving key file: %s", err)
 			return nil, fmt.Errorf("Error saving key file: %s", err)
 		}
 		}
 	} else if err != nil {
 	} else if err != nil {
@@ -143,3 +151,19 @@ func LoadOrCreateTrustKey(trustKeyPath string) (libtrust.PrivateKey, error) {
 	}
 	}
 	return trustKey, nil
 	return trustKey, nil
 }
 }
+
+func serializePrivateKey(key libtrust.PrivateKey, ext string) (encoded []byte, err error) {
+	if ext == ".json" || ext == ".jwk" {
+		encoded, err = json.Marshal(key)
+		if err != nil {
+			return nil, fmt.Errorf("unable to encode private key JWK: %s", err)
+		}
+	} else {
+		pemBlock, err := key.PEMBlock()
+		if err != nil {
+			return nil, fmt.Errorf("unable to encode private key PEM: %s", err)
+		}
+		encoded = pem.EncodeToMemory(pemBlock)
+	}
+	return
+}