summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorumohnani8 <umohnani@redhat.com>2018-03-23 16:38:55 -0400
committerAtomic Bot <atomic-devel@projectatomic.io>2018-03-29 14:15:27 +0000
commit8a96b4acbc97d5c34ff0160ab1a1b585fdd5d156 (patch)
tree822c9d92ee38b8a85f7f41cc85edc6c388be00f2
parentd0c983563129c804d2c974b05cc7d3604957f51a (diff)
downloadpodman-8a96b4acbc97d5c34ff0160ab1a1b585fdd5d156.tar.gz
podman-8a96b4acbc97d5c34ff0160ab1a1b585fdd5d156.tar.bz2
podman-8a96b4acbc97d5c34ff0160ab1a1b585fdd5d156.zip
Add secrets patch to podman
Adds support for mounting secrets especially on RHEL where the container can use the host subsription to run yum Signed-off-by: umohnani8 <umohnani@redhat.com> Closes: #544 Approved by: rhatdan
-rw-r--r--cmd/podman/create.go11
-rw-r--r--libpod/container_internal.go19
-rw-r--r--pkg/secrets/secrets.go122
-rw-r--r--test/e2e/run_test.go28
4 files changed, 175 insertions, 5 deletions
diff --git a/cmd/podman/create.go b/cmd/podman/create.go
index c1fb15bcf..520664c8e 100644
--- a/cmd/podman/create.go
+++ b/cmd/podman/create.go
@@ -3,6 +3,12 @@ package main
import (
"encoding/json"
"fmt"
+ "net"
+ "os"
+ "strconv"
+ "strings"
+ "syscall"
+
"github.com/docker/docker/api/types/container"
"github.com/docker/docker/pkg/signal"
"github.com/docker/go-connections/nat"
@@ -15,11 +21,6 @@ import (
"github.com/projectatomic/libpod/pkg/util"
"github.com/sirupsen/logrus"
"github.com/urfave/cli"
- "net"
- "os"
- "strconv"
- "strings"
- "syscall"
)
type mountType string
diff --git a/libpod/container_internal.go b/libpod/container_internal.go
index a338a1776..4bfdfae9d 100644
--- a/libpod/container_internal.go
+++ b/libpod/container_internal.go
@@ -22,6 +22,7 @@ import (
"github.com/pkg/errors"
crioAnnotations "github.com/projectatomic/libpod/pkg/annotations"
"github.com/projectatomic/libpod/pkg/chrootuser"
+ "github.com/projectatomic/libpod/pkg/secrets"
"github.com/projectatomic/libpod/pkg/util"
"github.com/sirupsen/logrus"
"github.com/ulule/deepcopier"
@@ -681,9 +682,27 @@ func (c *Container) makeBindMounts() error {
c.state.BindMounts["/run/.containerenv"] = containerenvPath
}
+ // Add Secret Mounts
+ secretMounts := c.getSecretMounts(secrets.OverrideMountsFile)
+ secretMounts = append(secretMounts, c.getSecretMounts(secrets.DefaultMountsFile)...)
+ for _, mount := range secretMounts {
+ if _, ok := c.state.BindMounts[mount.Destination]; !ok {
+ c.state.BindMounts[mount.Destination] = mount.Source
+ }
+ }
+
return nil
}
+// addSecrets mounts the secrets from the override and/or default mounts file
+func (c *Container) getSecretMounts(mountFile string) (secretMounts []spec.Mount) {
+ secretMounts, err := secrets.SecretMounts(mountFile, c.config.MountLabel, c.state.RunDir)
+ if err != nil {
+ logrus.Warn("error mounting secrets, skipping...")
+ }
+ return secretMounts
+}
+
// writeStringToRundir copies the provided file to the runtimedir
func (c *Container) writeStringToRundir(destFile, output string) (string, error) {
destFileName := filepath.Join(c.state.RunDir, destFile)
diff --git a/pkg/secrets/secrets.go b/pkg/secrets/secrets.go
new file mode 100644
index 000000000..8227499e5
--- /dev/null
+++ b/pkg/secrets/secrets.go
@@ -0,0 +1,122 @@
+package secrets
+
+import (
+ "bufio"
+ "fmt"
+ "os"
+ "path/filepath"
+ "strings"
+
+ "github.com/containers/storage/pkg/chrootarchive"
+ rspec "github.com/opencontainers/runtime-spec/specs-go"
+ "github.com/opencontainers/selinux/go-selinux/label"
+ "github.com/pkg/errors"
+ "github.com/sirupsen/logrus"
+)
+
+var (
+ // DefaultMountsFile holds the default mount paths in the form
+ // "host_path:container_path"
+ DefaultMountsFile = "/usr/share/containers/mounts.conf"
+ // OverrideMountsFile holds the default mount paths in the form
+ // "host_path:container_path" overridden by the user
+ OverrideMountsFile = "/etc/containers/mounts.conf"
+)
+
+func getMounts(filePath string) []string {
+ file, err := os.Open(filePath)
+ if err != nil {
+ logrus.Warnf("file %q not found, skipping...", filePath)
+ return nil
+ }
+ defer file.Close()
+ scanner := bufio.NewScanner(file)
+ if err = scanner.Err(); err != nil {
+ logrus.Warnf("error reading file %q, skipping...", filePath)
+ return nil
+ }
+ var mounts []string
+ for scanner.Scan() {
+ mounts = append(mounts, scanner.Text())
+ }
+ return mounts
+}
+
+// getHostAndCtrDir separates the host:container paths
+func getMountsMap(path string) (string, string, error) {
+ arr := strings.SplitN(path, ":", 2)
+ if len(arr) == 2 {
+ return arr[0], arr[1], nil
+ }
+ return "", "", errors.Errorf("unable to get host and container dir")
+}
+
+// SecretMounts copies the contents of host directory to container directory
+// and returns a list of mounts
+func SecretMounts(filePath, mountLabel, containerWorkingDir string) ([]rspec.Mount, error) {
+ var mounts []rspec.Mount
+ defaultMountsPaths := getMounts(filePath)
+ for _, path := range defaultMountsPaths {
+ hostDir, ctrDir, err := getMountsMap(path)
+ if err != nil {
+ return nil, err
+ }
+ // skip if the hostDir path doesn't exist
+ if _, err = os.Stat(hostDir); os.IsNotExist(err) {
+ logrus.Warnf("%q doesn't exist, skipping", hostDir)
+ continue
+ }
+
+ ctrDirOnHost := filepath.Join(containerWorkingDir, ctrDir)
+ if err = os.RemoveAll(ctrDirOnHost); err != nil {
+ return nil, fmt.Errorf("remove container directory failed: %v", err)
+ }
+
+ // In the event of a restart, don't want to copy secrets over again as they already would exist in ctrDirOnHost
+ _, err = os.Stat(ctrDirOnHost)
+ if os.IsNotExist(err) {
+ if err = os.MkdirAll(ctrDirOnHost, 0755); err != nil {
+ return nil, fmt.Errorf("making container directory failed: %v", err)
+ }
+
+ hostDir, err = resolveSymbolicLink(hostDir)
+ if err != nil {
+ return nil, err
+ }
+
+ if err = chrootarchive.NewArchiver(nil).CopyWithTar(hostDir, ctrDirOnHost); err != nil && !os.IsNotExist(err) {
+ return nil, errors.Wrapf(err, "error getting host secret data")
+ }
+
+ err = label.Relabel(ctrDirOnHost, mountLabel, false)
+ if err != nil {
+ return nil, errors.Wrap(err, "error applying correct labels")
+ }
+ } else if err != nil {
+ return nil, errors.Wrapf(err, "error getting status of %q", ctrDirOnHost)
+ }
+
+ m := rspec.Mount{
+ Source: ctrDirOnHost,
+ Destination: ctrDir,
+ Type: "bind",
+ Options: []string{"bind"},
+ }
+
+ mounts = append(mounts, m)
+ }
+ return mounts, nil
+}
+
+// resolveSymbolicLink resolves a possbile symlink path. If the path is a symlink, returns resolved
+// path; if not, returns the original path.
+func resolveSymbolicLink(path string) (string, error) {
+ info, err := os.Lstat(path)
+ if err != nil {
+ return "", err
+ }
+ if info.Mode()&os.ModeSymlink != os.ModeSymlink {
+ return path, nil
+ }
+ return filepath.EvalSymlinks(path)
+}
diff --git a/test/e2e/run_test.go b/test/e2e/run_test.go
index 3abaab783..16fae5898 100644
--- a/test/e2e/run_test.go
+++ b/test/e2e/run_test.go
@@ -2,6 +2,7 @@ package integration
import (
"fmt"
+ "io/ioutil"
"os"
"path/filepath"
@@ -216,4 +217,31 @@ var _ = Describe("Podman run", func() {
Expect(session.ExitCode()).To(Equal(0))
})
+ It("podman run with secrets", func() {
+ containersDir := "/usr/share/containers"
+ err := os.MkdirAll(containersDir, 0755)
+ Expect(err).To(BeNil())
+
+ secretsDir := filepath.Join(podmanTest.TempDir, "rhel", "secrets")
+ err = os.MkdirAll(secretsDir, 0755)
+ Expect(err).To(BeNil())
+
+ mountsFile := filepath.Join(containersDir, "mounts.conf")
+ mountString := secretsDir + ":/run/secrets"
+ err = ioutil.WriteFile(mountsFile, []byte(mountString), 0755)
+ Expect(err).To(BeNil())
+
+ secretsFile := filepath.Join(secretsDir, "test.txt")
+ secretsString := "Testing secrets mount. I am mounted!"
+ err = ioutil.WriteFile(secretsFile, []byte(secretsString), 0755)
+ Expect(err).To(BeNil())
+
+ session := podmanTest.Podman([]string{"run", "--rm", ALPINE, "cat", "/run/secrets/test.txt"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.OutputToString()).To(Equal(secretsString))
+
+ err = os.RemoveAll(containersDir)
+ Expect(err).To(BeNil())
+ })
+
})