Skip to content

Commit

Permalink
Merge pull request containers#10915 from ashley-cui/backport
Browse files Browse the repository at this point in the history
[3.2] Backport: Support uid,gid,mode options for secrets
  • Loading branch information
openshift-merge-robot authored Jul 13, 2021
2 parents 60d12f7 + 6f9d963 commit 4136f8b
Show file tree
Hide file tree
Showing 17 changed files with 197 additions and 49 deletions.
53 changes: 47 additions & 6 deletions cmd/podman/common/specgen.go
Original file line number Diff line number Diff line change
Expand Up @@ -778,28 +778,38 @@ func parseThrottleIOPsDevices(iopsDevices []string) (map[string]specs.LinuxThrot
return td, nil
}

func parseSecrets(secrets []string) ([]string, map[string]string, error) {
func parseSecrets(secrets []string) ([]specgen.Secret, map[string]string, error) {
secretParseError := errors.New("error parsing secret")
var mount []string
var mount []specgen.Secret
envs := make(map[string]string)
for _, val := range secrets {
// mount only tells if user has set an option that can only be used with mount secret type
mountOnly := false
source := ""
secretType := ""
target := ""
var uid, gid uint32
// default mode 444 octal = 292 decimal
var mode uint32 = 292
split := strings.Split(val, ",")

// --secret mysecret
if len(split) == 1 {
source = val
mount = append(mount, source)
mountSecret := specgen.Secret{
Source: val,
UID: uid,
GID: gid,
Mode: mode,
}
mount = append(mount, mountSecret)
continue
}
// --secret mysecret,opt=opt
if !strings.Contains(split[0], "=") {
source = split[0]
split = split[1:]
}
// TODO: implement other secret options

for _, val := range split {
kv := strings.SplitN(val, "=", 2)
if len(kv) < 2 {
Expand All @@ -818,6 +828,28 @@ func parseSecrets(secrets []string) ([]string, map[string]string, error) {
secretType = kv[1]
case "target":
target = kv[1]
case "mode":
mountOnly = true
mode64, err := strconv.ParseUint(kv[1], 8, 32)
if err != nil {
return nil, nil, errors.Wrapf(secretParseError, "mode %s invalid", kv[1])
}
mode = uint32(mode64)
case "uid", "UID":
mountOnly = true
uid64, err := strconv.ParseUint(kv[1], 10, 32)
if err != nil {
return nil, nil, errors.Wrapf(secretParseError, "UID %s invalid", kv[1])
}
uid = uint32(uid64)
case "gid", "GID":
mountOnly = true
gid64, err := strconv.ParseUint(kv[1], 10, 32)
if err != nil {
return nil, nil, errors.Wrapf(secretParseError, "GID %s invalid", kv[1])
}
gid = uint32(gid64)

default:
return nil, nil, errors.Wrapf(secretParseError, "option %s invalid", val)
}
Expand All @@ -833,9 +865,18 @@ func parseSecrets(secrets []string) ([]string, map[string]string, error) {
if target != "" {
return nil, nil, errors.Wrapf(secretParseError, "target option is invalid for mounted secrets")
}
mount = append(mount, source)
mountSecret := specgen.Secret{
Source: source,
UID: uid,
GID: gid,
Mode: mode,
}
mount = append(mount, mountSecret)
}
if secretType == "env" {
if mountOnly {
return nil, nil, errors.Wrap(secretParseError, "UID, GID, Mode options cannot be set with secret type env")
}
if target == "" {
target = source
}
Expand Down
3 changes: 3 additions & 0 deletions docs/source/markdown/podman-create.1.md
Original file line number Diff line number Diff line change
Expand Up @@ -859,6 +859,9 @@ Secret Options

- `type=mount|env` : How the secret will be exposed to the container. Default mount.
- `target=target` : Target of secret. Defauts to secret name.
- `uid=0` : UID of secret. Defaults to 0. Mount secret type only.
- `gid=0` : GID of secret. Defaults to 0. Mount secret type only.
- `mode=0` : Mode of secret. Defaults to 0444. Mount secret type only.

#### **--security-opt**=*option*

Expand Down
3 changes: 3 additions & 0 deletions docs/source/markdown/podman-run.1.md
Original file line number Diff line number Diff line change
Expand Up @@ -911,6 +911,9 @@ Secret Options

- `type=mount|env` : How the secret will be exposed to the container. Default mount.
- `target=target` : Target of secret. Defauts to secret name.
- `uid=0` : UID of secret. Defaults to 0. Mount secret type only.
- `gid=0` : GID of secret. Defaults to 0. Mount secret type only.
- `mode=0` : Mode of secret. Defaults to 0444. Mount secret type only.

#### **--security-opt**=*option*

Expand Down
14 changes: 13 additions & 1 deletion libpod/container.go
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,18 @@ type ContainerImageVolume struct {
ReadWrite bool `json:"rw"`
}

// ContainerSecret is a secret that is mounted in a container
type ContainerSecret struct {
// Secret is the secret
*secrets.Secret
// UID is tbe UID of the secret file
UID uint32
// GID is the GID of the secret file
GID uint32
// Mode is the mode of the secret file
Mode uint32
}

// ContainerNetworkDescriptions describes the relationship between the CNI
// network and the ethN where N is an integer
type ContainerNetworkDescriptions map[string]int
Expand Down Expand Up @@ -1136,7 +1148,7 @@ func (c *Container) Umask() string {
}

//Secrets return the secrets in the container
func (c *Container) Secrets() []*secrets.Secret {
func (c *Container) Secrets() []*ContainerSecret {
return c.config.Secrets
}

Expand Down
2 changes: 1 addition & 1 deletion libpod/container_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ type ContainerRootFSConfig struct {
// default, but others do not.
CreateWorkingDir bool `json:"createWorkingDir,omitempty"`
// Secrets lists secrets to mount into the container
Secrets []*secrets.Secret `json:"secrets,omitempty"`
Secrets []*ContainerSecret `json:"secrets,omitempty"`
// SecretPath is the secrets location in storage
SecretsPath string `json:"secretsPath"`
// Volatile specifies whether the container storage can be optimized
Expand Down
4 changes: 3 additions & 1 deletion libpod/container_inspect.go
Original file line number Diff line number Diff line change
Expand Up @@ -343,11 +343,13 @@ func (c *Container) generateInspectContainerConfig(spec *spec.Spec) *define.Insp
ctrConfig.CreateCommand = c.config.CreateCommand

ctrConfig.Timezone = c.config.Timezone

for _, secret := range c.config.Secrets {
newSec := define.InspectSecret{}
newSec.Name = secret.Name
newSec.ID = secret.ID
newSec.UID = secret.UID
newSec.GID = secret.GID
newSec.Mode = secret.Mode
ctrConfig.Secrets = append(ctrConfig.Secrets, &newSec)
}

Expand Down
19 changes: 15 additions & 4 deletions libpod/container_internal.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import (

metadata "github.com/checkpoint-restore/checkpointctl/lib"
"github.com/containers/buildah/copier"
"github.com/containers/common/pkg/secrets"
butil "github.com/containers/buildah/util"
"github.com/containers/podman/v3/libpod/define"
"github.com/containers/podman/v3/libpod/events"
"github.com/containers/podman/v3/pkg/cgroups"
Expand All @@ -24,6 +24,7 @@ import (
"github.com/containers/podman/v3/pkg/hooks/exec"
"github.com/containers/podman/v3/pkg/rootless"
"github.com/containers/podman/v3/pkg/selinux"
"github.com/containers/podman/v3/pkg/util"
"github.com/containers/storage"
"github.com/containers/storage/pkg/archive"
"github.com/containers/storage/pkg/idtools"
Expand Down Expand Up @@ -2188,21 +2189,31 @@ func (c *Container) hasNamespace(namespace spec.LinuxNamespaceType) bool {
}

// extractSecretToStorage copies a secret's data from the secrets manager to the container's static dir
func (c *Container) extractSecretToCtrStorage(name string) error {
manager, err := secrets.NewManager(c.runtime.GetSecretsStorageDir())
func (c *Container) extractSecretToCtrStorage(secr *ContainerSecret) error {
manager, err := c.runtime.SecretsManager()
if err != nil {
return err
}
secr, data, err := manager.LookupSecretData(name)
_, data, err := manager.LookupSecretData(secr.Name)
if err != nil {
return err
}
secretFile := filepath.Join(c.config.SecretsPath, secr.Name)

hostUID, hostGID, err := butil.GetHostIDs(util.IDtoolsToRuntimeSpec(c.config.IDMappings.UIDMap), util.IDtoolsToRuntimeSpec(c.config.IDMappings.GIDMap), secr.UID, secr.GID)
if err != nil {
return errors.Wrap(err, "unable to extract secret")
}
err = ioutil.WriteFile(secretFile, data, 0644)
if err != nil {
return errors.Wrapf(err, "unable to create %s", secretFile)
}
if err := os.Lchown(secretFile, int(hostUID), int(hostGID)); err != nil {
return err
}
if err := os.Chmod(secretFile, os.FileMode(secr.Mode)); err != nil {
return err
}
if err := label.Relabel(secretFile, c.config.MountLabel, false); err != nil {
return err
}
Expand Down
8 changes: 5 additions & 3 deletions libpod/container_internal_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ import (
"github.com/containers/common/pkg/apparmor"
"github.com/containers/common/pkg/chown"
"github.com/containers/common/pkg/config"
"github.com/containers/common/pkg/secrets"
"github.com/containers/common/pkg/subscriptions"
"github.com/containers/common/pkg/umask"
"github.com/containers/podman/v3/libpod/define"
Expand Down Expand Up @@ -759,7 +758,10 @@ func (c *Container) generateSpec(ctx context.Context) (*spec.Spec, error) {
return nil, errors.Wrapf(err, "error setting up OCI Hooks")
}
if len(c.config.EnvSecrets) > 0 {
manager, err := secrets.NewManager(c.runtime.GetSecretsStorageDir())
manager, err := c.runtime.SecretsManager()
if err != nil {
return nil, err
}
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -2413,7 +2415,7 @@ func (c *Container) createSecretMountDir() error {
oldUmask := umask.Set(0)
defer umask.Set(oldUmask)

if err := os.MkdirAll(src, 0644); err != nil {
if err := os.MkdirAll(src, 0755); err != nil {
return err
}
if err := label.Relabel(src, c.config.MountLabel, false); err != nil {
Expand Down
15 changes: 9 additions & 6 deletions libpod/define/container_inspect.go
Original file line number Diff line number Diff line change
Expand Up @@ -713,13 +713,16 @@ type DriverData struct {
Data map[string]string `json:"Data"`
}

// InspectHostPort provides information on a port on the host that a container's
// port is bound to.
// InspectSecret contains information on secrets mounted inside the container
type InspectSecret struct {
// IP on the host we are bound to. "" if not specified (binding to all
// IPs).
// Name is the name of the secret
Name string `json:"Name"`
// Port on the host we are bound to. No special formatting - just an
// integer stuffed into a string.
// ID is the ID of the secret
ID string `json:"ID"`
// ID is the UID of the mounted secret file
UID uint32 `json:"UID"`
// ID is the GID of the mounted secret file
GID uint32 `json:"GID"`
// ID is the ID of the mode of the mounted secret file
Mode uint32 `json:"Mode"`
}
17 changes: 3 additions & 14 deletions libpod/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -1712,23 +1712,12 @@ func WithUmask(umask string) CtrCreateOption {
}

// WithSecrets adds secrets to the container
func WithSecrets(secretNames []string) CtrCreateOption {
func WithSecrets(containerSecrets []*ContainerSecret) CtrCreateOption {
return func(ctr *Container) error {
if ctr.valid {
return define.ErrCtrFinalized
}
manager, err := secrets.NewManager(ctr.runtime.GetSecretsStorageDir())
if err != nil {
return err
}
for _, name := range secretNames {
secr, err := manager.Lookup(name)
if err != nil {
return err
}
ctr.config.Secrets = append(ctr.config.Secrets, secr)
}

ctr.config.Secrets = containerSecrets
return nil
}
}
Expand All @@ -1740,7 +1729,7 @@ func WithEnvSecrets(envSecrets map[string]string) CtrCreateOption {
if ctr.valid {
return define.ErrCtrFinalized
}
manager, err := secrets.NewManager(ctr.runtime.GetSecretsStorageDir())
manager, err := ctr.runtime.SecretsManager()
if err != nil {
return err
}
Expand Down
15 changes: 15 additions & 0 deletions libpod/runtime.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import (
"github.com/containers/buildah/pkg/parse"
"github.com/containers/common/libimage"
"github.com/containers/common/pkg/config"
"github.com/containers/common/pkg/secrets"
"github.com/containers/image/v5/pkg/sysregistriesv2"
is "github.com/containers/image/v5/storage"
"github.com/containers/image/v5/types"
Expand Down Expand Up @@ -106,6 +107,8 @@ type Runtime struct {

// noStore indicates whether we need to interact with a store or not
noStore bool
// secretsManager manages secrets
secretsManager *secrets.SecretsManager
}

// SetXdgDirs ensures the XDG_RUNTIME_DIR env and XDG_CONFIG_HOME variables are set.
Expand Down Expand Up @@ -1091,6 +1094,18 @@ func (r *Runtime) GetSecretsStorageDir() string {
return filepath.Join(r.store.GraphRoot(), "secrets")
}

// SecretsManager returns the directory that the secrets manager should take
func (r *Runtime) SecretsManager() (*secrets.SecretsManager, error) {
if r.secretsManager == nil {
manager, err := secrets.NewManager(r.GetSecretsStorageDir())
if err != nil {
return nil, err
}
r.secretsManager = manager
}
return r.secretsManager, nil
}

func graphRootMounted() bool {
f, err := os.OpenFile("/run/.containerenv", os.O_RDONLY, os.ModePerm)
if err != nil {
Expand Down
2 changes: 1 addition & 1 deletion libpod/runtime_ctr.go
Original file line number Diff line number Diff line change
Expand Up @@ -366,7 +366,7 @@ func (r *Runtime) setupContainer(ctx context.Context, ctr *Container) (_ *Contai
return nil, err
}
for _, secr := range ctr.config.Secrets {
err = ctr.extractSecretToCtrStorage(secr.Name)
err = ctr.extractSecretToCtrStorage(secr)
if err != nil {
return nil, err
}
Expand Down
3 changes: 1 addition & 2 deletions pkg/domain/infra/abi/play.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import (

"github.com/containers/common/libimage"
"github.com/containers/common/pkg/config"
"github.com/containers/common/pkg/secrets"
"github.com/containers/image/v5/types"
"github.com/containers/podman/v3/libpod"
"github.com/containers/podman/v3/libpod/define"
Expand Down Expand Up @@ -161,7 +160,7 @@ func (ic *ContainerEngine) playKubePod(ctx context.Context, podName string, podY
)

// Create the secret manager before hand
secretsManager, err := secrets.NewManager(ic.Libpod.GetSecretsStorageDir())
secretsManager, err := ic.Libpod.SecretsManager()
if err != nil {
return nil, err
}
Expand Down
Loading

0 comments on commit 4136f8b

Please sign in to comment.