diff --git a/cmd/podman/cliconfig/config.go b/cmd/podman/cliconfig/config.go index e81756808e27..282d90d0be66 100644 --- a/cmd/podman/cliconfig/config.go +++ b/cmd/podman/cliconfig/config.go @@ -308,12 +308,13 @@ type HealthCheckValues struct { type KubePlayValues struct { PodmanCommand - Authfile string - CertDir string - Creds string - Quiet bool - SignaturePolicy string - TlsVerify bool + Authfile string + CertDir string + Creds string + Quiet bool + SignaturePolicy string + TlsVerify bool + SeccompProfileRoot string } type PodCreateValues struct { diff --git a/cmd/podman/play_kube.go b/cmd/podman/play_kube.go index fc9f2d5b66a4..2028d2ef4545 100644 --- a/cmd/podman/play_kube.go +++ b/cmd/podman/play_kube.go @@ -28,6 +28,8 @@ var ( }, Example: `podman play kube demo.yml`, } + // https://kubernetes.io/docs/reference/command-line-tools-reference/kubelet/ + defaultSeccompRoot = "/var/lib/kubelet/seccomp" ) func init() { @@ -46,6 +48,7 @@ func init() { flags.StringVar(&playKubeCommand.CertDir, "cert-dir", "", "`Pathname` of a directory containing TLS certificates and keys") flags.StringVar(&playKubeCommand.SignaturePolicy, "signature-policy", "", "`Pathname` of signature policy file (not usually used)") flags.BoolVar(&playKubeCommand.TlsVerify, "tls-verify", true, "Require HTTPS and verify certificates when contacting registries") + flags.StringVar(&playKubeCommand.SeccompProfileRoot, "seccomp-profile-root", defaultSeccompRoot, "Directory path for seccomp profiles") markFlagHidden(flags, "signature-policy") } } diff --git a/completions/bash/podman b/completions/bash/podman index 40be0018b28d..c23d156bcbca 100644 --- a/completions/bash/podman +++ b/completions/bash/podman @@ -2672,6 +2672,7 @@ _podman_play_kube() { --quiet -q --tls-verify + --seccomp-profile-root " case "$cur" in diff --git a/docs/source/markdown/podman-play-kube.1.md b/docs/source/markdown/podman-play-kube.1.md index 2ac860a325a6..2367ff7fe33c 100644 --- a/docs/source/markdown/podman-play-kube.1.md +++ b/docs/source/markdown/podman-play-kube.1.md @@ -40,6 +40,10 @@ value can be entered. The password is entered without echo. Suppress output information when pulling images +**--seccomp-profile-root**=*path* + +Directory path for seccomp profiles (default: "/var/lib/kubelet/seccomp"). (Not available for remote commands) + **--tls-verify**=*true|false* Require HTTPS and verify certificates when contacting registries (default: true). If explicitly set to true, diff --git a/pkg/adapter/pods.go b/pkg/adapter/pods.go index a726153c01f8..5891c361f634 100644 --- a/pkg/adapter/pods.go +++ b/pkg/adapter/pods.go @@ -8,6 +8,7 @@ import ( "io" "io/ioutil" "os" + "path/filepath" "strings" "github.com/containers/buildah/pkg/parse" @@ -597,7 +598,7 @@ func (r *LocalRuntime) PlayKubeYAML(ctx context.Context, c *cliconfig.KubePlayVa volumes[volume.Name] = hostPath.Path } - seccompPaths, err := initializeSeccompPaths(podYAML.ObjectMeta.Annotations) + seccompPaths, err := initializeSeccompPaths(podYAML.ObjectMeta.Annotations, c.SeccompProfileRoot) if err != nil { return nil, err } @@ -847,7 +848,8 @@ func (k *kubeSeccompPaths) findForContainer(ctrName string) string { // initializeSeccompPaths takes annotations from the pod object metadata and finds annotations pertaining to seccomp // it parses both pod and container level -func initializeSeccompPaths(annotations map[string]string) (*kubeSeccompPaths, error) { +// if the annotation is of the form "localhost/%s", the seccomp profile will be set to profileRoot/%s +func initializeSeccompPaths(annotations map[string]string, profileRoot string) (*kubeSeccompPaths, error) { seccompPaths := &kubeSeccompPaths{containerPaths: make(map[string]string)} var err error if annotations != nil { @@ -863,7 +865,7 @@ func initializeSeccompPaths(annotations map[string]string) (*kubeSeccompPaths, e return nil, errors.Errorf("Invalid seccomp path: %s", prefixAndCtr[0]) } - path, err := verifySeccompPath(seccomp) + path, err := verifySeccompPath(seccomp, profileRoot) if err != nil { return nil, err } @@ -872,7 +874,7 @@ func initializeSeccompPaths(annotations map[string]string) (*kubeSeccompPaths, e podSeccomp, ok := annotations[v1.SeccompPodAnnotationKey] if ok { - seccompPaths.podPath, err = verifySeccompPath(podSeccomp) + seccompPaths.podPath, err = verifySeccompPath(podSeccomp, profileRoot) } else { seccompPaths.podPath, err = libpod.DefaultSeccompPath() } @@ -885,7 +887,7 @@ func initializeSeccompPaths(annotations map[string]string) (*kubeSeccompPaths, e // verifySeccompPath takes a path and checks whether it is a default, unconfined, or a path // the available options are parsed as defined in https://kubernetes.io/docs/concepts/policy/pod-security-policy/#seccomp -func verifySeccompPath(path string) (string, error) { +func verifySeccompPath(path string, profileRoot string) (string, error) { switch path { case v1.DeprecatedSeccompProfileDockerDefault: fallthrough @@ -894,13 +896,9 @@ func verifySeccompPath(path string) (string, error) { case "unconfined": return path, nil default: - // TODO we have an inconsistency here - // k8s parses `localhost/` which is found at `` - // we currently parse `localhost:/ - // to fully conform, we need to find a good location for the seccomp root - parts := strings.Split(path, ":") + parts := strings.Split(path, "/") if parts[0] == "localhost" { - return parts[1], nil + return filepath.Join(profileRoot, parts[1]), nil } return "", errors.Errorf("invalid seccomp path: %s", path) } diff --git a/test/e2e/play_kube_test.go b/test/e2e/play_kube_test.go index 29c60d7acd45..89a5eddf432a 100644 --- a/test/e2e/play_kube_test.go +++ b/test/e2e/play_kube_test.go @@ -358,10 +358,11 @@ var _ = Describe("Podman generate kube", func() { ctrAnnotation := "container.seccomp.security.alpha.kubernetes.io/" + defaultCtrName ctr := getCtr(withCmd([]string{"pwd"})) - err = generateKubeYaml(getPod(withCtr(ctr), withAnnotation(ctrAnnotation, "localhost:"+jsonFile)), kubeYaml) + err = generateKubeYaml(getPod(withCtr(ctr), withAnnotation(ctrAnnotation, "localhost/"+filepath.Base(jsonFile))), kubeYaml) Expect(err).To(BeNil()) - kube := podmanTest.Podman([]string{"play", "kube", kubeYaml}) + // CreateSeccompJson will put the profile into podmanTest.TempDir. Use --seccomp-profile-root to tell play kube where to look + kube := podmanTest.Podman([]string{"play", "kube", "--seccomp-profile-root", podmanTest.TempDir, kubeYaml}) kube.WaitWithDefaultTimeout() Expect(kube.ExitCode()).To(Equal(0)) @@ -378,13 +379,15 @@ var _ = Describe("Podman generate kube", func() { fmt.Println(err) Skip("Failed to prepare seccomp.json for test.") } + defer os.Remove(jsonFile) ctr := getCtr(withCmd([]string{"pwd"})) - err = generateKubeYaml(getPod(withCtr(ctr), withAnnotation("seccomp.security.alpha.kubernetes.io/pod", "localhost:"+jsonFile)), kubeYaml) + err = generateKubeYaml(getPod(withCtr(ctr), withAnnotation("seccomp.security.alpha.kubernetes.io/pod", "localhost/"+filepath.Base(jsonFile))), kubeYaml) Expect(err).To(BeNil()) - kube := podmanTest.Podman([]string{"play", "kube", kubeYaml}) + // CreateSeccompJson will put the profile into podmanTest.TempDir. Use --seccomp-profile-root to tell play kube where to look + kube := podmanTest.Podman([]string{"play", "kube", "--seccomp-profile-root", podmanTest.TempDir, kubeYaml}) kube.WaitWithDefaultTimeout() Expect(kube.ExitCode()).To(Equal(0))