summaryrefslogtreecommitdiff
path: root/cmd/podman
diff options
context:
space:
mode:
Diffstat (limited to 'cmd/podman')
-rw-r--r--cmd/podman/common.go9
-rw-r--r--cmd/podman/create.go82
-rw-r--r--cmd/podman/exec.go3
-rw-r--r--cmd/podman/image.go1
-rw-r--r--cmd/podman/sign.go197
5 files changed, 206 insertions, 86 deletions
diff --git a/cmd/podman/common.go b/cmd/podman/common.go
index 0fc9a6acc..d934c8699 100644
--- a/cmd/podman/common.go
+++ b/cmd/podman/common.go
@@ -28,6 +28,10 @@ var (
Name: "latest, l",
Usage: "act on the latest pod podman is aware of",
}
+ WorkDirFlag = cli.StringFlag{
+ Name: "workdir, w",
+ Usage: "Working directory inside the container",
+ }
)
const (
@@ -522,10 +526,7 @@ var createFlags = []cli.Flag{
Name: "volumes-from",
Usage: "Mount volumes from the specified container(s) (default [])",
},
- cli.StringFlag{
- Name: "workdir, w",
- Usage: "Working `directory inside the container",
- },
+ WorkDirFlag,
}
func getFormat(c *cli.Context) (string, error) {
diff --git a/cmd/podman/create.go b/cmd/podman/create.go
index 395a64b3b..d98b78bd4 100644
--- a/cmd/podman/create.go
+++ b/cmd/podman/create.go
@@ -15,13 +15,11 @@ import (
"github.com/containers/libpod/libpod"
"github.com/containers/libpod/libpod/image"
ann "github.com/containers/libpod/pkg/annotations"
- "github.com/containers/libpod/pkg/apparmor"
"github.com/containers/libpod/pkg/inspect"
ns "github.com/containers/libpod/pkg/namespaces"
"github.com/containers/libpod/pkg/rootless"
cc "github.com/containers/libpod/pkg/spec"
"github.com/containers/libpod/pkg/util"
- libpodVersion "github.com/containers/libpod/version"
"github.com/docker/docker/pkg/signal"
"github.com/docker/go-connections/nat"
"github.com/docker/go-units"
@@ -162,83 +160,9 @@ func createContainer(c *cli.Context, runtime *libpod.Runtime) (*libpod.Container
return ctr, createConfig, nil
}
-// Checks if a user-specified AppArmor profile is loaded, or loads the default profile if
-// AppArmor is enabled.
-// Any interaction with AppArmor requires root permissions.
-func loadAppArmor(config *cc.CreateConfig) error {
- if rootless.IsRootless() {
- noAAMsg := "AppArmor security is not available in rootless mode"
- switch config.ApparmorProfile {
- case "":
- logrus.Warn(noAAMsg)
- case "unconfined":
- default:
- return fmt.Errorf(noAAMsg)
- }
- return nil
- }
-
- if config.ApparmorProfile == "" && apparmor.IsEnabled() {
- // Unless specified otherwise, make sure that the default AppArmor
- // profile is installed. To avoid redundantly loading the profile
- // on each invocation, check if it's loaded before installing it.
- // Suffix the profile with the current libpod version to allow
- // loading the new, potentially updated profile after an update.
- profile := fmt.Sprintf("%s-%s", apparmor.DefaultLibpodProfile, libpodVersion.Version)
-
- loadProfile := func() error {
- isLoaded, err := apparmor.IsLoaded(profile)
- if err != nil {
- return err
- }
- if !isLoaded {
- err = apparmor.InstallDefault(profile)
- if err != nil {
- return err
- }
-
- }
- return nil
- }
-
- if err := loadProfile(); err != nil {
- switch err {
- case apparmor.ErrApparmorUnsupported:
- // do not set the profile when AppArmor isn't supported
- logrus.Debugf("AppArmor is not supported: setting empty profile")
- default:
- return err
- }
- } else {
- logrus.Infof("Sucessfully loaded AppAmor profile '%s'", profile)
- config.ApparmorProfile = profile
- }
- } else if config.ApparmorProfile != "" && config.ApparmorProfile != "unconfined" {
- if !apparmor.IsEnabled() {
- return fmt.Errorf("Profile specified but AppArmor is disabled on the host")
- }
-
- isLoaded, err := apparmor.IsLoaded(config.ApparmorProfile)
- if err != nil {
- switch err {
- case apparmor.ErrApparmorUnsupported:
- return fmt.Errorf("Profile specified but AppArmor is not supported")
- default:
- return fmt.Errorf("Error checking if AppArmor profile is loaded: %v", err)
- }
- }
- if !isLoaded {
- return fmt.Errorf("The specified AppArmor profile '%s' is not loaded", config.ApparmorProfile)
- }
- }
-
- return nil
-}
-
func parseSecurityOpt(config *cc.CreateConfig, securityOpts []string) error {
var (
labelOpts []string
- err error
)
if config.PidMode.IsHost() {
@@ -283,10 +207,6 @@ func parseSecurityOpt(config *cc.CreateConfig, securityOpts []string) error {
}
}
- if err := loadAppArmor(config); err != nil {
- return err
- }
-
if config.SeccompProfilePath == "" {
if _, err := os.Stat(libpod.SeccompOverridePath); err == nil {
config.SeccompProfilePath = libpod.SeccompOverridePath
@@ -304,7 +224,7 @@ func parseSecurityOpt(config *cc.CreateConfig, securityOpts []string) error {
}
}
config.LabelOpts = labelOpts
- return err
+ return nil
}
// isPortInPortBindings determines if an exposed host port is in user
diff --git a/cmd/podman/exec.go b/cmd/podman/exec.go
index c03834dea..073e72e64 100644
--- a/cmd/podman/exec.go
+++ b/cmd/podman/exec.go
@@ -34,6 +34,7 @@ var (
Usage: "Sets the username or UID used and optionally the groupname or GID for the specified command",
},
LatestFlag,
+ WorkDirFlag,
}
execDescription = `
podman exec
@@ -108,5 +109,5 @@ func execCmd(c *cli.Context) error {
envs = append(envs, fmt.Sprintf("%s=%s", k, v))
}
- return ctr.Exec(c.Bool("tty"), c.Bool("privileged"), envs, cmd, c.String("user"))
+ return ctr.Exec(c.Bool("tty"), c.Bool("privileged"), envs, cmd, c.String("user"), c.String("workdir"))
}
diff --git a/cmd/podman/image.go b/cmd/podman/image.go
index e978b9cf5..557fc1056 100644
--- a/cmd/podman/image.go
+++ b/cmd/podman/image.go
@@ -20,6 +20,7 @@ var (
saveCommand,
tagCommand,
trustCommand,
+ signCommand,
}
imageDescription = "Manage images"
diff --git a/cmd/podman/sign.go b/cmd/podman/sign.go
new file mode 100644
index 000000000..8a31ddb98
--- /dev/null
+++ b/cmd/podman/sign.go
@@ -0,0 +1,197 @@
+package main
+
+import (
+ "fmt"
+ "io/ioutil"
+ "net/url"
+ "os"
+ "strconv"
+ "strings"
+
+ "github.com/containers/image/signature"
+ "github.com/containers/image/transports"
+ "github.com/containers/image/transports/alltransports"
+ "github.com/containers/libpod/cmd/podman/libpodruntime"
+ "github.com/containers/libpod/libpod/image"
+ "github.com/containers/libpod/pkg/trust"
+ "github.com/pkg/errors"
+ "github.com/sirupsen/logrus"
+ "github.com/urfave/cli"
+)
+
+var (
+ signFlags = []cli.Flag{
+ cli.StringFlag{
+ Name: "sign-by",
+ Usage: "Name of the signing key",
+ },
+ cli.StringFlag{
+ Name: "directory, d",
+ Usage: "Define an alternate directory to store signatures",
+ },
+ }
+
+ signDescription = "Create a signature file that can be used later to verify the image"
+ signCommand = cli.Command{
+ Name: "sign",
+ Usage: "Sign an image",
+ Description: signDescription,
+ Flags: sortFlags(signFlags),
+ Action: signCmd,
+ ArgsUsage: "IMAGE-NAME [IMAGE-NAME ...]",
+ OnUsageError: usageErrorHandler,
+ }
+)
+
+// SignatureStoreDir defines default directory to store signatures
+const SignatureStoreDir = "/var/lib/containers/sigstore"
+
+func signCmd(c *cli.Context) error {
+ args := c.Args()
+ if len(args) < 1 {
+ return errors.Errorf("at least one image name must be specified")
+ }
+ runtime, err := libpodruntime.GetRuntime(c)
+ if err != nil {
+ return errors.Wrapf(err, "could not create runtime")
+ }
+ defer runtime.Shutdown(false)
+
+ signby := c.String("sign-by")
+ if signby == "" {
+ return errors.Errorf("You must provide an identity")
+ }
+
+ var sigStoreDir string
+ if c.IsSet("directory") {
+ sigStoreDir = c.String("directory")
+ if _, err := os.Stat(sigStoreDir); err != nil {
+ return errors.Wrapf(err, "invalid directory %s", sigStoreDir)
+ }
+ }
+
+ mech, err := signature.NewGPGSigningMechanism()
+ if err != nil {
+ return errors.Wrap(err, "Error initializing GPG")
+ }
+ defer mech.Close()
+ if err := mech.SupportsSigning(); err != nil {
+ return errors.Wrap(err, "Signing is not supported")
+ }
+
+ systemRegistriesDirPath := trust.RegistriesDirPath(runtime.SystemContext())
+ registryConfigs, err := trust.LoadAndMergeConfig(systemRegistriesDirPath)
+ if err != nil {
+ return errors.Wrapf(err, "error reading registry configuration")
+ }
+
+ for _, signimage := range args {
+ srcRef, err := alltransports.ParseImageName(signimage)
+ if err != nil {
+ return errors.Wrapf(err, "error parsing image name")
+ }
+ rawSource, err := srcRef.NewImageSource(getContext(), runtime.SystemContext())
+ if err != nil {
+ return errors.Wrapf(err, "error getting image source")
+ }
+ manifest, _, err := rawSource.GetManifest(getContext(), nil)
+ if err != nil {
+ return errors.Wrapf(err, "error getting manifest")
+ }
+ dockerReference := rawSource.Reference().DockerReference()
+ if dockerReference == nil {
+ return errors.Errorf("Cannot determine canonical Docker reference for destination %s", transports.ImageName(rawSource.Reference()))
+ }
+
+ // create the signstore file
+ newImage, err := runtime.ImageRuntime().New(getContext(), signimage, runtime.GetConfig().SignaturePolicyPath, "", os.Stderr, nil, image.SigningOptions{SignBy: signby}, false)
+ if err != nil {
+ return errors.Wrapf(err, "error pulling image %s", signimage)
+ }
+
+ registryInfo := trust.HaveMatchRegistry(rawSource.Reference().DockerReference().String(), registryConfigs)
+ if registryInfo != nil {
+ if sigStoreDir == "" {
+ sigStoreDir = registryInfo.SigStoreStaging
+ if sigStoreDir == "" {
+ sigStoreDir = registryInfo.SigStore
+ }
+ }
+ sigStoreDir, err = isValidSigStoreDir(sigStoreDir)
+ if err != nil {
+ return errors.Wrapf(err, "invalid signature storage %s", sigStoreDir)
+ }
+ }
+ if sigStoreDir == "" {
+ sigStoreDir = SignatureStoreDir
+ }
+
+ repos, err := newImage.RepoDigests()
+ if err != nil {
+ return errors.Wrapf(err, "error calculating repo digests for %s", signimage)
+ }
+ if len(repos) == 0 {
+ logrus.Errorf("no repodigests associated with the image %s", signimage)
+ continue
+ }
+
+ // create signature
+ newSig, err := signature.SignDockerManifest(manifest, dockerReference.String(), mech, signby)
+ if err != nil {
+ return errors.Wrapf(err, "error creating new signature")
+ }
+
+ sigStoreDir = fmt.Sprintf("%s/%s", sigStoreDir, strings.Replace(repos[0][strings.Index(repos[0], "/")+1:len(repos[0])], ":", "=", 1))
+ if err := os.MkdirAll(sigStoreDir, 0751); err != nil {
+ // The directory is allowed to exist
+ if !os.IsExist(err) {
+ logrus.Errorf("error creating directory %s: %s", sigStoreDir, err)
+ continue
+ }
+ }
+ sigFilename, err := getSigFilename(sigStoreDir)
+ if err != nil {
+ logrus.Errorf("error creating sigstore file: %v", err)
+ continue
+ }
+ err = ioutil.WriteFile(sigStoreDir+"/"+sigFilename, newSig, 0644)
+ if err != nil {
+ logrus.Errorf("error storing signature for %s", rawSource.Reference().DockerReference().String())
+ continue
+ }
+ }
+ return nil
+}
+
+func getSigFilename(sigStoreDirPath string) (string, error) {
+ sigFileSuffix := 1
+ sigFiles, err := ioutil.ReadDir(sigStoreDirPath)
+ if err != nil {
+ return "", err
+ }
+ sigFilenames := make(map[string]bool)
+ for _, file := range sigFiles {
+ sigFilenames[file.Name()] = true
+ }
+ for {
+ sigFilename := "signature-" + strconv.Itoa(sigFileSuffix)
+ if _, exists := sigFilenames[sigFilename]; !exists {
+ return sigFilename, nil
+ }
+ sigFileSuffix++
+ }
+}
+
+func isValidSigStoreDir(sigStoreDir string) (string, error) {
+ writeURIs := map[string]bool{"file": true}
+ url, err := url.Parse(sigStoreDir)
+ if err != nil {
+ return sigStoreDir, errors.Wrapf(err, "invalid directory %s", sigStoreDir)
+ }
+ _, exists := writeURIs[url.Scheme]
+ if !exists {
+ return sigStoreDir, errors.Errorf("Writing to %s is not supported. Use a supported scheme", sigStoreDir)
+ }
+ sigStoreDir = url.Path
+ return sigStoreDir, nil
+}