From ed97ccf535888a5e1fa2cadf42d01089e1192e06 Mon Sep 17 00:00:00 2001 From: Dan Walsh Date: Thu, 13 Nov 2014 15:28:39 -0500 Subject: [PATCH] Super Secrets Patch Docker-DCO-1.1-Signed-off-by: Dan Walsh (github: rhatdan) --- daemon/container.go | 48 +++++++++++++++++++++++++++++- daemon/secrets.go | 86 +++++++++++++++++++++++++++++++++++++++++++++++++++++ daemon/volumes.go | 11 +++++++ graph/graph.go | 1 + 4 files changed, 145 insertions(+), 1 deletion(-) create mode 100644 daemon/secrets.go diff --git a/daemon/container.go b/daemon/container.go index 2ac8316..b754105 100644 --- a/daemon/container.go +++ b/daemon/container.go @@ -338,11 +338,28 @@ func (container *Container) Start() (err error) { if err := populateCommand(container, env); err != nil { return err } + if err := container.setupSecretFiles(); err != nil { + return err + } if err := container.setupMounts(); err != nil { return err } - return container.waitForStart() + if err := container.waitForStart(); err != nil { + return err + } + + // Now the container is running, unmount the secrets on the host + secretsPath, err := container.secretsPath() + if err != nil { + return err + } + + if err := syscall.Unmount(secretsPath, syscall.MNT_DETACH); err != nil { + return err + } + + return nil } func (container *Container) Run() error { @@ -793,6 +810,10 @@ func (container *Container) jsonPath() (string, error) { return container.getRootResourcePath("config.json") } +func (container *Container) secretsPath() (string, error) { + return container.getRootResourcePath("secrets") +} + // This method must be exported to be used from the lxc template // This directory is only usable when the container is running func (container *Container) RootfsPath() string { @@ -1064,6 +1085,31 @@ func (container *Container) verifyDaemonSettings() { } } +func (container *Container) setupSecretFiles() error { + secretsPath, err := container.secretsPath() + if err != nil { + return err + } + + if err := os.MkdirAll(secretsPath, 0700); err != nil { + return err + } + + if err := syscall.Mount("tmpfs", secretsPath, "tmpfs", uintptr(syscall.MS_NOEXEC|syscall.MS_NOSUID|syscall.MS_NODEV), label.FormatMountLabel("", container.GetMountLabel())); err != nil { + return fmt.Errorf("mounting secret tmpfs: %s", err) + } + + data, err := getHostSecretData() + if err != nil { + return err + } + for _, s := range data { + s.SaveTo(secretsPath) + } + + return nil +} + func (container *Container) setupLinkedContainers() ([]string, error) { var ( env []string diff --git a/daemon/secrets.go b/daemon/secrets.go new file mode 100644 index 0000000..8bd97a5 --- /dev/null +++ b/daemon/secrets.go @@ -0,0 +1,86 @@ +package daemon + +import ( + "io/ioutil" + "os" + "path/filepath" +) + +type Secret struct { + Name string + IsDir bool + HostBased bool +} + +type SecretData struct { + Name string + Data []byte +} + +func (s SecretData) SaveTo(dir string) error { + path := filepath.Join(dir, s.Name) + if err := os.MkdirAll(filepath.Dir(path), 0755); err != nil && !os.IsExist(err) { + return err + } + if err := ioutil.WriteFile(path, s.Data, 0755); err != nil { + return err + } + return nil +} + +func readAll(root, prefix string) ([]SecretData, error) { + path := filepath.Join(root, prefix) + + data := []SecretData{} + + files, err := ioutil.ReadDir(path) + if err != nil { + if os.IsNotExist(err) { + return data, nil + } + + return nil, err + } + + for _, f := range files { + fileData, err := readFile(root, filepath.Join(prefix, f.Name())) + if err != nil { + // If the file did not exist, might be a dangling symlink + // Ignore the error + if os.IsNotExist(err) { + continue + } + return nil, err + } + data = append(data, fileData...) + } + + return data, nil +} + +func readFile(root, name string) ([]SecretData, error) { + path := filepath.Join(root, name) + + s, err := os.Stat(path) + if err != nil { + return nil, err + } + + if s.IsDir() { + dirData, err := readAll(root, name) + if err != nil { + return nil, err + } + return dirData, nil + } else { + bytes, err := ioutil.ReadFile(path) + if err != nil { + return nil, err + } + return []SecretData{{Name: name, Data: bytes}}, nil + } +} + +func getHostSecretData() ([]SecretData, error) { + return readAll("/usr/share/rhel/secrets", "") +} diff --git a/daemon/volumes.go b/daemon/volumes.go index 6523dae..322d3f4 100644 --- a/daemon/volumes.go +++ b/daemon/volumes.go @@ -260,6 +260,17 @@ func (container *Container) setupMounts() error { }) } + secretsPath, err := container.secretsPath() + if err != nil { + return err + } + + mounts = append(mounts, execdriver.Mount{ + Source: secretsPath, + Destination: "/run/secrets", + Writable: true, + }) + container.command.Mounts = mounts return nil } diff --git a/graph/graph.go b/graph/graph.go index 720f6e6..647b64d 100644 --- a/graph/graph.go +++ b/graph/graph.go @@ -242,6 +242,7 @@ func SetupInitLayer(initLayer string) error { "/etc/hostname": "file", "/dev/console": "file", "/etc/mtab": "/proc/mounts", + "/run/secrets": "dir", } { parts := strings.Split(pth, "/") prev := "/"