From 57afb7514d5c123779601cae77d016bf6de8a5f1 Mon Sep 17 00:00:00 2001 From: umohnani8 Date: Thu, 19 Apr 2018 10:25:01 -0400 Subject: Add FIPS mode secret If the host is in FIPS mode and /etc/system-fips exists /run/secrets/system-fips is created in the container so that the container can run in FIPS mode as well. Signed-off-by: umohnani8 --- libpod/container_internal.go | 14 ++------ pkg/secrets/secrets.go | 81 ++++++++++++++++++++++++++++++++++++++++---- test/e2e/run_test.go | 14 ++++++++ 3 files changed, 91 insertions(+), 18 deletions(-) diff --git a/libpod/container_internal.go b/libpod/container_internal.go index 32f8d2aec..62960fa0f 100644 --- a/libpod/container_internal.go +++ b/libpod/container_internal.go @@ -754,8 +754,7 @@ func (c *Container) makeBindMounts() error { } // Add Secret Mounts - secretMounts := c.getSecretMounts(secrets.OverrideMountsFile) - secretMounts = append(secretMounts, c.getSecretMounts(secrets.DefaultMountsFile)...) + secretMounts := secrets.SecretMounts(c.config.MountLabel, c.state.RunDir) for _, mount := range secretMounts { if _, ok := c.state.BindMounts[mount.Destination]; !ok { c.state.BindMounts[mount.Destination] = mount.Source @@ -765,15 +764,6 @@ func (c *Container) makeBindMounts() error { 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) @@ -932,6 +922,8 @@ func (c *Container) generateSpec(ctx context.Context) (*spec.Spec, error) { } if !MountExists(g.Mounts(), dstPath) { g.AddMount(newMount) + } else { + logrus.Warnf("User mount overriding libpod mount at %q", dstPath) } } diff --git a/pkg/secrets/secrets.go b/pkg/secrets/secrets.go index be825d906..9b328575b 100644 --- a/pkg/secrets/secrets.go +++ b/pkg/secrets/secrets.go @@ -2,7 +2,6 @@ package secrets import ( "bufio" - "fmt" "io/ioutil" "os" "path/filepath" @@ -127,9 +126,35 @@ func getMountsMap(path string) (string, string, error) { return "", "", errors.Errorf("unable to get host and container dir") } -// SecretMounts copies the contents of host directory to container directory +// SecretMounts copies, adds, and mounts the secrets to the container root filesystem +func SecretMounts(mountLabel, containerWorkingDir string) []rspec.Mount { + var secretMounts []rspec.Mount + // Add secrets from paths given in the mounts.conf files + for _, file := range []string{OverrideMountsFile, DefaultMountsFile} { + mounts, err := addSecretsFromMountsFile(file, mountLabel, containerWorkingDir) + if err != nil { + logrus.Warnf("error mounting secrets, skipping: %v", err) + } + secretMounts = append(secretMounts, mounts...) + } + + // Add FIPS mode secret if /etc/system-fips exists on the host + _, err := os.Stat("/etc/system-fips") + if err == nil { + if err := addFIPSsModeSecret(&secretMounts, containerWorkingDir); err != nil { + logrus.Warnf("error adding FIPS mode secret to container: %v", err) + } + } else if os.IsNotExist(err) { + logrus.Debug("/etc/system-fips does not exist on host, not mounting FIPS mode secret") + } else { + logrus.Errorf("error stating /etc/system-fips for FIPS mode secret: %v", err) + } + return secretMounts +} + +// addSecretsFromMountsFile copies the contents of host directory to container directory // and returns a list of mounts -func SecretMounts(filePath, mountLabel, containerWorkingDir string) ([]rspec.Mount, error) { +func addSecretsFromMountsFile(filePath, mountLabel, containerWorkingDir string) ([]rspec.Mount, error) { var mounts []rspec.Mount defaultMountsPaths := getMounts(filePath) for _, path := range defaultMountsPaths { @@ -144,15 +169,12 @@ func SecretMounts(filePath, mountLabel, containerWorkingDir string) ([]rspec.Mou } 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) + return nil, errors.Wrapf(err, "making container directory failed") } hostDir, err = resolveSymbolicLink(hostDir) @@ -190,6 +212,51 @@ func SecretMounts(filePath, mountLabel, containerWorkingDir string) ([]rspec.Mou return mounts, nil } +// addFIPSModeSecret creates /run/secrets/system-fips in the container +// root filesystem if /etc/system-fips exists on hosts. +// This enables the container to be FIPS compliant and run openssl in +// FIPS mode as the host is also in FIPS mode. +func addFIPSsModeSecret(mounts *[]rspec.Mount, containerWorkingDir string) error { + secretsDir := "/run/secrets" + ctrDirOnHost := filepath.Join(containerWorkingDir, secretsDir) + if _, err := os.Stat(ctrDirOnHost); os.IsNotExist(err) { + if err = os.MkdirAll(ctrDirOnHost, 0755); err != nil { + return errors.Wrapf(err, "making container directory on host failed") + } + } + fipsFile := filepath.Join(ctrDirOnHost, "system-fips") + // In the event of restart, it is possible for the FIPS mode file to already exist + if _, err := os.Stat(fipsFile); os.IsNotExist(err) { + file, err := os.Create(fipsFile) + if err != nil { + return errors.Wrapf(err, "error creating system-fips file in container for FIPS mode") + } + defer file.Close() + } + + if !mountExists(*mounts, secretsDir) { + m := rspec.Mount{ + Source: ctrDirOnHost, + Destination: secretsDir, + Type: "bind", + Options: []string{"bind"}, + } + *mounts = append(*mounts, m) + } + + return nil +} + +// mountExists checks if a mount already exists in the spec +func mountExists(mounts []rspec.Mount, dest string) bool { + for _, mount := range mounts { + if mount.Destination == dest { + return true + } + } + return false +} + // 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) { diff --git a/test/e2e/run_test.go b/test/e2e/run_test.go index 66e5791a7..501434852 100644 --- a/test/e2e/run_test.go +++ b/test/e2e/run_test.go @@ -302,6 +302,20 @@ var _ = Describe("Podman run", func() { Expect(err).To(BeNil()) }) + It("podman run with FIPS mode secrets", func() { + fipsFile := "/etc/system-fips" + err = ioutil.WriteFile(fipsFile, []byte{}, 0755) + Expect(err).To(BeNil()) + + session := podmanTest.Podman([]string{"run", "--rm", ALPINE, "ls", "/run/secrets"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + Expect(session.OutputToString()).To(ContainSubstring("system-fips")) + + err = os.Remove(fipsFile) + Expect(err).To(BeNil()) + }) + It("podman run without group-add", func() { session := podmanTest.Podman([]string{"run", "--rm", ALPINE, "id"}) session.WaitWithDefaultTimeout() -- cgit v1.2.3-54-g00ecf