Implement Secrets

Implement podman secret create, inspect, ls, rm
Implement podman run/create --secret
Secrets are blobs of data that are sensitive.
Currently, the only secret driver supported is filedriver, which means creating a secret stores it in base64 unencrypted in a file.
After creating a secret, a user can use the --secret flag to expose the secret inside the container at /run/secrets/[secretname]
This secret will not be commited to an image on a podman commit

Signed-off-by: Ashley Cui <acui@redhat.com>
This commit is contained in:
Ashley Cui
2021-01-15 01:27:23 -05:00
parent 2aaf631586
commit 832a69b0be
58 changed files with 2962 additions and 7 deletions

36
test/apiv2/50-secrets.at Normal file
View File

@ -0,0 +1,36 @@
# -*- sh -*-
#
# secret-related tests
#
# secret create
t POST secrets/create '"Name":"mysecret","Data":"c2VjcmV0"' 200\
.ID~.* \
# secret create unsupported labels
t POST secrets/create '"Name":"mysecret","Data":"c2VjcmV0","Labels":{"fail":"fail"}' 400
# secret create name already in use
t POST secrets/create '"Name":"mysecret","Data":"c2VjcmV0"' 409
# secret inspect
t GET secrets/mysecret 200\
.Spec.Name=mysecret
# secret inspect non-existent secret
t GET secrets/bogus 404
# secret list
t GET secrets 200\
length=1
# secret list unsupported filters
t GET secrets?filters=%7B%22name%22%3A%5B%22foo1%22%5D%7D 400
# secret rm
t DELETE secrets/mysecret 204
# secret rm non-existent secret
t DELETE secrets/bogus 404
# secret update not implemented
t POST secrets/mysecret/update "" 501

View File

@ -279,4 +279,29 @@ var _ = Describe("Podman commit", func() {
data := check.InspectImageJSON()
Expect(data[0].ID).To(Equal(string(id)))
})
It("podman commit should not commit secret", func() {
secretsString := "somesecretdata"
secretFilePath := filepath.Join(podmanTest.TempDir, "secret")
err := ioutil.WriteFile(secretFilePath, []byte(secretsString), 0755)
Expect(err).To(BeNil())
session := podmanTest.Podman([]string{"secret", "create", "mysecret", secretFilePath})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
session = podmanTest.Podman([]string{"run", "--secret", "mysecret", "--name", "secr", ALPINE, "cat", "/run/secrets/mysecret"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
Expect(session.OutputToString()).To(Equal(secretsString))
session = podmanTest.Podman([]string{"commit", "secr", "foobar.com/test1-image:latest"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
session = podmanTest.Podman([]string{"run", "foobar.com/test1-image:latest", "cat", "/run/secrets/mysecret"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Not(Equal(0)))
})
})

View File

@ -491,6 +491,21 @@ func (p *PodmanTestIntegration) CleanupVolume() {
p.Cleanup()
}
// CleanupSecret cleans up the temporary store
func (p *PodmanTestIntegration) CleanupSecrets() {
// Remove all containers
session := p.Podman([]string{"secret", "rm", "-a"})
session.Wait(90)
// Stop remove service on secret cleanup
p.StopRemoteService()
// Nuke tempdir
if err := os.RemoveAll(p.TempDir); err != nil {
fmt.Printf("%q\n", err)
}
}
// InspectContainerToJSON takes the session output of an inspect
// container and returns json
func (s *PodmanSessionIntegration) InspectContainerToJSON() []define.InspectContainerData {

View File

@ -668,8 +668,8 @@ USER bin`
Expect(session.ExitCode()).To(Equal(0))
})
It("podman run with secrets", func() {
SkipIfRemote("--default-mounts-file option is not supported in podman-remote")
It("podman run with subscription secrets", func() {
SkipIfRemote("--default-mount-file option is not supported in podman-remote")
containersDir := filepath.Join(podmanTest.TempDir, "containers")
err := os.MkdirAll(containersDir, 0755)
Expect(err).To(BeNil())
@ -1448,4 +1448,26 @@ WORKDIR /madethis`
Expect(session.ExitCode()).To(Equal(0))
Expect(session.OutputToString()).To(ContainSubstring(hostnameEnv))
})
It("podman run --secret", func() {
secretsString := "somesecretdata"
secretFilePath := filepath.Join(podmanTest.TempDir, "secret")
err := ioutil.WriteFile(secretFilePath, []byte(secretsString), 0755)
Expect(err).To(BeNil())
session := podmanTest.Podman([]string{"secret", "create", "mysecret", secretFilePath})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
session = podmanTest.Podman([]string{"run", "--secret", "mysecret", "--name", "secr", ALPINE, "cat", "/run/secrets/mysecret"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
Expect(session.OutputToString()).To(Equal(secretsString))
session = podmanTest.Podman([]string{"inspect", "secr", "--format", " {{(index .Config.Secrets 0).Name}}"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
Expect(session.OutputToString()).To(ContainSubstring("mysecret"))
})
})

202
test/e2e/secret_test.go Normal file
View File

@ -0,0 +1,202 @@
package integration
import (
"io/ioutil"
"os"
"path/filepath"
. "github.com/containers/podman/v2/test/utils"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
)
var _ = Describe("Podman secret", func() {
var (
tempdir string
err error
podmanTest *PodmanTestIntegration
)
BeforeEach(func() {
tempdir, err = CreateTempDirInTempDir()
if err != nil {
os.Exit(1)
}
podmanTest = PodmanTestCreate(tempdir)
podmanTest.Setup()
podmanTest.SeedImages()
})
AfterEach(func() {
podmanTest.CleanupSecrets()
f := CurrentGinkgoTestDescription()
processTestResult(f)
})
It("podman secret create", func() {
secretFilePath := filepath.Join(podmanTest.TempDir, "secret")
err := ioutil.WriteFile(secretFilePath, []byte("mysecret"), 0755)
Expect(err).To(BeNil())
session := podmanTest.Podman([]string{"secret", "create", "a", secretFilePath})
session.WaitWithDefaultTimeout()
secrID := session.OutputToString()
Expect(session.ExitCode()).To(Equal(0))
inspect := podmanTest.Podman([]string{"secret", "inspect", "--format", "{{.ID}}", secrID})
inspect.WaitWithDefaultTimeout()
Expect(inspect.ExitCode()).To(Equal(0))
Expect(inspect.OutputToString()).To(Equal(secrID))
})
It("podman secret create bad name should fail", func() {
secretFilePath := filepath.Join(podmanTest.TempDir, "secret")
err := ioutil.WriteFile(secretFilePath, []byte("mysecret"), 0755)
Expect(err).To(BeNil())
session := podmanTest.Podman([]string{"secret", "create", "?!", secretFilePath})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Not(Equal(0)))
})
It("podman secret inspect", func() {
secretFilePath := filepath.Join(podmanTest.TempDir, "secret")
err := ioutil.WriteFile(secretFilePath, []byte("mysecret"), 0755)
Expect(err).To(BeNil())
session := podmanTest.Podman([]string{"secret", "create", "a", secretFilePath})
session.WaitWithDefaultTimeout()
secrID := session.OutputToString()
Expect(session.ExitCode()).To(Equal(0))
inspect := podmanTest.Podman([]string{"secret", "inspect", secrID})
inspect.WaitWithDefaultTimeout()
Expect(inspect.ExitCode()).To(Equal(0))
Expect(inspect.IsJSONOutputValid()).To(BeTrue())
})
It("podman secret inspect with --format", func() {
secretFilePath := filepath.Join(podmanTest.TempDir, "secret")
err := ioutil.WriteFile(secretFilePath, []byte("mysecret"), 0755)
Expect(err).To(BeNil())
session := podmanTest.Podman([]string{"secret", "create", "a", secretFilePath})
session.WaitWithDefaultTimeout()
secrID := session.OutputToString()
Expect(session.ExitCode()).To(Equal(0))
inspect := podmanTest.Podman([]string{"secret", "inspect", "--format", "{{.ID}}", secrID})
inspect.WaitWithDefaultTimeout()
Expect(inspect.ExitCode()).To(Equal(0))
Expect(inspect.OutputToString()).To(Equal(secrID))
})
It("podman secret inspect multiple secrets", func() {
secretFilePath := filepath.Join(podmanTest.TempDir, "secret")
err := ioutil.WriteFile(secretFilePath, []byte("mysecret"), 0755)
Expect(err).To(BeNil())
session := podmanTest.Podman([]string{"secret", "create", "a", secretFilePath})
session.WaitWithDefaultTimeout()
secrID := session.OutputToString()
Expect(session.ExitCode()).To(Equal(0))
session2 := podmanTest.Podman([]string{"secret", "create", "b", secretFilePath})
session2.WaitWithDefaultTimeout()
secrID2 := session2.OutputToString()
Expect(session2.ExitCode()).To(Equal(0))
inspect := podmanTest.Podman([]string{"secret", "inspect", secrID, secrID2})
inspect.WaitWithDefaultTimeout()
Expect(inspect.ExitCode()).To(Equal(0))
Expect(inspect.IsJSONOutputValid()).To(BeTrue())
})
It("podman secret inspect bogus", func() {
secretFilePath := filepath.Join(podmanTest.TempDir, "secret")
err := ioutil.WriteFile(secretFilePath, []byte("mysecret"), 0755)
Expect(err).To(BeNil())
inspect := podmanTest.Podman([]string{"secret", "inspect", "bogus"})
inspect.WaitWithDefaultTimeout()
Expect(inspect.ExitCode()).To(Not(Equal(0)))
})
It("podman secret ls", func() {
secretFilePath := filepath.Join(podmanTest.TempDir, "secret")
err := ioutil.WriteFile(secretFilePath, []byte("mysecret"), 0755)
Expect(err).To(BeNil())
session := podmanTest.Podman([]string{"secret", "create", "a", secretFilePath})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
list := podmanTest.Podman([]string{"secret", "ls"})
list.WaitWithDefaultTimeout()
Expect(list.ExitCode()).To(Equal(0))
Expect(len(list.OutputToStringArray())).To(Equal(2))
})
It("podman secret ls with Go template", func() {
secretFilePath := filepath.Join(podmanTest.TempDir, "secret")
err := ioutil.WriteFile(secretFilePath, []byte("mysecret"), 0755)
Expect(err).To(BeNil())
session := podmanTest.Podman([]string{"secret", "create", "a", secretFilePath})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
list := podmanTest.Podman([]string{"secret", "ls", "--format", "table {{.Name}}"})
list.WaitWithDefaultTimeout()
Expect(list.ExitCode()).To(Equal(0))
Expect(len(list.OutputToStringArray())).To(Equal(2), list.OutputToString())
})
It("podman secret rm", func() {
secretFilePath := filepath.Join(podmanTest.TempDir, "secret")
err := ioutil.WriteFile(secretFilePath, []byte("mysecret"), 0755)
Expect(err).To(BeNil())
session := podmanTest.Podman([]string{"secret", "create", "a", secretFilePath})
session.WaitWithDefaultTimeout()
secrID := session.OutputToString()
Expect(session.ExitCode()).To(Equal(0))
removed := podmanTest.Podman([]string{"secret", "rm", "a"})
removed.WaitWithDefaultTimeout()
Expect(removed.ExitCode()).To(Equal(0))
Expect(removed.OutputToString()).To(Equal(secrID))
session = podmanTest.Podman([]string{"secret", "ls"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
Expect(len(session.OutputToStringArray())).To(Equal(1))
})
It("podman secret rm --all", func() {
secretFilePath := filepath.Join(podmanTest.TempDir, "secret")
err := ioutil.WriteFile(secretFilePath, []byte("mysecret"), 0755)
Expect(err).To(BeNil())
session := podmanTest.Podman([]string{"secret", "create", "a", secretFilePath})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
session = podmanTest.Podman([]string{"secret", "create", "b", secretFilePath})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
removed := podmanTest.Podman([]string{"secret", "rm", "-a"})
removed.WaitWithDefaultTimeout()
Expect(removed.ExitCode()).To(Equal(0))
session = podmanTest.Podman([]string{"secret", "ls"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
Expect(len(session.OutputToStringArray())).To(Equal(1))
})
})