mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
bfed4b7cc3
This patch creates a new `tlsconfig` package to handle creation of secure-enough TLS configurations for clients and servers. The package was created by refactoring TLS code in the client and the daemon. After this patch, it is expected that all code creating TLS configurations use this `tlsconfig` package for greater security, consistency and readability. On the server side, this fixes a bug where --tlsverify was not taken into account. Now, if specified, it will require the client to authenticate. Signed-off-by: Tibor Vass <tibor@docker.com>
225 lines
5.5 KiB
Go
225 lines
5.5 KiB
Go
// +build daemon
|
|
|
|
package main
|
|
|
|
import (
|
|
"crypto/tls"
|
|
"fmt"
|
|
"io"
|
|
"os"
|
|
"path/filepath"
|
|
"time"
|
|
|
|
"github.com/Sirupsen/logrus"
|
|
apiserver "github.com/docker/docker/api/server"
|
|
"github.com/docker/docker/autogen/dockerversion"
|
|
"github.com/docker/docker/daemon"
|
|
_ "github.com/docker/docker/daemon/execdriver/lxc"
|
|
_ "github.com/docker/docker/daemon/execdriver/native"
|
|
"github.com/docker/docker/pkg/homedir"
|
|
flag "github.com/docker/docker/pkg/mflag"
|
|
"github.com/docker/docker/pkg/pidfile"
|
|
"github.com/docker/docker/pkg/signal"
|
|
"github.com/docker/docker/pkg/system"
|
|
"github.com/docker/docker/pkg/timeutils"
|
|
"github.com/docker/docker/pkg/tlsconfig"
|
|
"github.com/docker/docker/registry"
|
|
"github.com/docker/docker/utils"
|
|
)
|
|
|
|
const CanDaemon = true
|
|
|
|
var (
|
|
daemonCfg = &daemon.Config{}
|
|
registryCfg = ®istry.Options{}
|
|
)
|
|
|
|
func init() {
|
|
if daemonCfg.LogConfig.Config == nil {
|
|
daemonCfg.LogConfig.Config = make(map[string]string)
|
|
}
|
|
daemonCfg.InstallFlags()
|
|
registryCfg.InstallFlags()
|
|
}
|
|
|
|
func migrateKey() (err error) {
|
|
// Migrate trust key if exists at ~/.docker/key.json and owned by current user
|
|
oldPath := filepath.Join(homedir.Get(), ".docker", defaultTrustKeyFile)
|
|
newPath := filepath.Join(getDaemonConfDir(), defaultTrustKeyFile)
|
|
if _, statErr := os.Stat(newPath); os.IsNotExist(statErr) && currentUserIsOwner(oldPath) {
|
|
defer func() {
|
|
// Ensure old path is removed if no error occurred
|
|
if err == nil {
|
|
err = os.Remove(oldPath)
|
|
} else {
|
|
logrus.Warnf("Key migration failed, key file not removed at %s", oldPath)
|
|
}
|
|
}()
|
|
|
|
if err := os.MkdirAll(getDaemonConfDir(), os.FileMode(0644)); err != nil {
|
|
return fmt.Errorf("Unable to create daemon configuration directory: %s", err)
|
|
}
|
|
|
|
newFile, err := os.OpenFile(newPath, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0600)
|
|
if err != nil {
|
|
return fmt.Errorf("error creating key file %q: %s", newPath, err)
|
|
}
|
|
defer newFile.Close()
|
|
|
|
oldFile, err := os.Open(oldPath)
|
|
if err != nil {
|
|
return fmt.Errorf("error opening key file %q: %s", oldPath, err)
|
|
}
|
|
defer oldFile.Close()
|
|
|
|
if _, err := io.Copy(newFile, oldFile); err != nil {
|
|
return fmt.Errorf("error copying key: %s", err)
|
|
}
|
|
|
|
logrus.Infof("Migrated key from %s to %s", oldPath, newPath)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func mainDaemon() {
|
|
if utils.ExperimentalBuild() {
|
|
logrus.Warn("Running experimental build")
|
|
}
|
|
|
|
if flag.NArg() != 0 {
|
|
flag.Usage()
|
|
return
|
|
}
|
|
|
|
logrus.SetFormatter(&logrus.TextFormatter{TimestampFormat: timeutils.RFC3339NanoFixed})
|
|
|
|
var pfile *pidfile.PidFile
|
|
if daemonCfg.Pidfile != "" {
|
|
pf, err := pidfile.New(daemonCfg.Pidfile)
|
|
if err != nil {
|
|
logrus.Fatalf("Error starting daemon: %v", err)
|
|
}
|
|
pfile = pf
|
|
defer func() {
|
|
if err := pfile.Remove(); err != nil {
|
|
logrus.Error(err)
|
|
}
|
|
}()
|
|
}
|
|
|
|
serverConfig := &apiserver.ServerConfig{
|
|
Logging: true,
|
|
EnableCors: daemonCfg.EnableCors,
|
|
CorsHeaders: daemonCfg.CorsHeaders,
|
|
Version: dockerversion.VERSION,
|
|
SocketGroup: daemonCfg.SocketGroup,
|
|
}
|
|
|
|
if *flTls {
|
|
if *flTlsVerify {
|
|
tlsOptions.ClientAuth = tls.RequireAndVerifyClientCert
|
|
}
|
|
tlsConfig, err := tlsconfig.Server(tlsOptions)
|
|
if err != nil {
|
|
logrus.Fatal(err)
|
|
}
|
|
serverConfig.TLSConfig = tlsConfig
|
|
}
|
|
|
|
api := apiserver.New(serverConfig)
|
|
|
|
// The serve API routine never exits unless an error occurs
|
|
// We need to start it as a goroutine and wait on it so
|
|
// daemon doesn't exit
|
|
serveAPIWait := make(chan error)
|
|
go func() {
|
|
if err := api.ServeApi(flHosts); err != nil {
|
|
logrus.Errorf("ServeAPI error: %v", err)
|
|
serveAPIWait <- err
|
|
return
|
|
}
|
|
serveAPIWait <- nil
|
|
}()
|
|
|
|
if err := migrateKey(); err != nil {
|
|
logrus.Fatal(err)
|
|
}
|
|
daemonCfg.TrustKeyPath = *flTrustKey
|
|
|
|
registryService := registry.NewService(registryCfg)
|
|
d, err := daemon.NewDaemon(daemonCfg, registryService)
|
|
if err != nil {
|
|
if pfile != nil {
|
|
if err := pfile.Remove(); err != nil {
|
|
logrus.Error(err)
|
|
}
|
|
}
|
|
logrus.Fatalf("Error starting daemon: %v", err)
|
|
}
|
|
|
|
logrus.Info("Daemon has completed initialization")
|
|
|
|
logrus.WithFields(logrus.Fields{
|
|
"version": dockerversion.VERSION,
|
|
"commit": dockerversion.GITCOMMIT,
|
|
"execdriver": d.ExecutionDriver().Name(),
|
|
"graphdriver": d.GraphDriver().String(),
|
|
}).Info("Docker daemon")
|
|
|
|
signal.Trap(func() {
|
|
api.Close()
|
|
<-serveAPIWait
|
|
shutdownDaemon(d, 15)
|
|
if pfile != nil {
|
|
if err := pfile.Remove(); err != nil {
|
|
logrus.Error(err)
|
|
}
|
|
}
|
|
})
|
|
|
|
// after the daemon is done setting up we can tell the api to start
|
|
// accepting connections with specified daemon
|
|
api.AcceptConnections(d)
|
|
|
|
// Daemon is fully initialized and handling API traffic
|
|
// Wait for serve API to complete
|
|
errAPI := <-serveAPIWait
|
|
shutdownDaemon(d, 15)
|
|
if errAPI != nil {
|
|
if pfile != nil {
|
|
if err := pfile.Remove(); err != nil {
|
|
logrus.Error(err)
|
|
}
|
|
}
|
|
logrus.Fatalf("Shutting down due to ServeAPI error: %v", errAPI)
|
|
}
|
|
}
|
|
|
|
// shutdownDaemon just wraps daemon.Shutdown() to handle a timeout in case
|
|
// d.Shutdown() is waiting too long to kill container or worst it's
|
|
// blocked there
|
|
func shutdownDaemon(d *daemon.Daemon, timeout time.Duration) {
|
|
ch := make(chan struct{})
|
|
go func() {
|
|
d.Shutdown()
|
|
close(ch)
|
|
}()
|
|
select {
|
|
case <-ch:
|
|
logrus.Debug("Clean shutdown succeded")
|
|
case <-time.After(timeout * time.Second):
|
|
logrus.Error("Force shutdown daemon")
|
|
}
|
|
}
|
|
|
|
// currentUserIsOwner checks whether the current user is the owner of the given
|
|
// file.
|
|
func currentUserIsOwner(f string) bool {
|
|
if fileInfo, err := system.Stat(f); err == nil && fileInfo != nil {
|
|
if int(fileInfo.Uid()) == os.Getuid() {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|