Fix secrets patch

The secrets code was just tarring and copying the contents of the secrets directory on host as is.
This meant it was not accounting for any symlinks inside the directory, leading up to the contents
not being copied over.

Signed-off-by: umohnani8 <umohnani@redhat.com>

Closes: #611
Approved by: mheon
This commit is contained in:
umohnani8
2018-04-12 14:41:17 -04:00
committed by Atomic Bot
parent ac910c7aa8
commit 9aafc25a3d
2 changed files with 101 additions and 3 deletions

View File

@ -3,11 +3,11 @@ package secrets
import ( import (
"bufio" "bufio"
"fmt" "fmt"
"io/ioutil"
"os" "os"
"path/filepath" "path/filepath"
"strings" "strings"
"github.com/containers/storage/pkg/chrootarchive"
rspec "github.com/opencontainers/runtime-spec/specs-go" rspec "github.com/opencontainers/runtime-spec/specs-go"
"github.com/opencontainers/selinux/go-selinux/label" "github.com/opencontainers/selinux/go-selinux/label"
"github.com/pkg/errors" "github.com/pkg/errors"
@ -23,6 +23,82 @@ var (
OverrideMountsFile = "/etc/containers/mounts.conf" OverrideMountsFile = "/etc/containers/mounts.conf"
) )
// secretData stores the name of the file and the content read from it
type secretData struct {
name string
data []byte
}
// saveTo saves secret data to given directory
func (s secretData) saveTo(dir string) error {
path := filepath.Join(dir, s.name)
if err := os.MkdirAll(filepath.Dir(path), 0700); err != nil && !os.IsExist(err) {
return err
}
return ioutil.WriteFile(path, s.data, 0700)
}
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
}
bytes, err := ioutil.ReadFile(path)
if err != nil {
return nil, err
}
return []secretData{{name: name, data: bytes}}, nil
}
func getHostSecretData(hostDir string) ([]secretData, error) {
var allSecrets []secretData
hostSecrets, err := readAll(hostDir, "")
if err != nil {
return nil, errors.Wrapf(err, "failed to read secrets from %q", hostDir)
}
return append(allSecrets, hostSecrets...), nil
}
func getMounts(filePath string) []string { func getMounts(filePath string) []string {
file, err := os.Open(filePath) file, err := os.Open(filePath)
if err != nil { if err != nil {
@ -84,8 +160,14 @@ func SecretMounts(filePath, mountLabel, containerWorkingDir string) ([]rspec.Mou
return nil, err return nil, err
} }
if err = chrootarchive.NewArchiver(nil).CopyWithTar(hostDir, ctrDirOnHost); err != nil && !os.IsNotExist(err) { data, err := getHostSecretData(hostDir)
return nil, errors.Wrapf(err, "error getting host secret data") if err != nil {
return nil, errors.Wrapf(err, "getting host secret data failed")
}
for _, s := range data {
if err := s.saveTo(ctrDirOnHost); err != nil {
return nil, errors.Wrapf(err, "error saving data to container filesystem on host %q", ctrDirOnHost)
}
} }
err = label.Relabel(ctrDirOnHost, mountLabel, false) err = label.Relabel(ctrDirOnHost, mountLabel, false)

View File

@ -278,10 +278,26 @@ var _ = Describe("Podman run", func() {
err = ioutil.WriteFile(secretsFile, []byte(secretsString), 0755) err = ioutil.WriteFile(secretsFile, []byte(secretsString), 0755)
Expect(err).To(BeNil()) Expect(err).To(BeNil())
targetDir := "/tmp/symlink/target"
err = os.MkdirAll(targetDir, 0755)
Expect(err).To(BeNil())
keyFile := filepath.Join(targetDir, "key.pem")
err = ioutil.WriteFile(keyFile, []byte(mountString), 0755)
Expect(err).To(BeNil())
execSession := podmanTest.SystemExec("ln", []string{"-s", targetDir, filepath.Join(secretsDir, "mysymlink")})
execSession.WaitWithDefaultTimeout()
Expect(execSession.ExitCode()).To(Equal(0))
session := podmanTest.Podman([]string{"run", "--rm", ALPINE, "cat", "/run/secrets/test.txt"}) session := podmanTest.Podman([]string{"run", "--rm", ALPINE, "cat", "/run/secrets/test.txt"})
session.WaitWithDefaultTimeout() session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
Expect(session.OutputToString()).To(Equal(secretsString)) Expect(session.OutputToString()).To(Equal(secretsString))
session = podmanTest.Podman([]string{"run", "--rm", ALPINE, "ls", "/run/secrets/mysymlink"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
Expect(session.OutputToString()).To(ContainSubstring("key.pem"))
err = os.RemoveAll(containersDir) err = os.RemoveAll(containersDir)
Expect(err).To(BeNil()) Expect(err).To(BeNil())
}) })