Do not bind mount configs and secrets when source is a file but copy it into the container

Signed-off-by: schaubl <schaubl@users.noreply.github.com>
This commit is contained in:
schaubl 2024-07-15 17:38:51 +02:00
parent d3d378b92a
commit f54922f13f
3 changed files with 67 additions and 89 deletions

View File

@ -288,6 +288,12 @@ func (s *composeService) getCreateConfigs(ctx context.Context,
return createConfigs{}, err
}
// CONFIGS and SECRETS
err = checkContainerConfigsSecrets(*p, service)
if err != nil {
return createConfigs{}, err
}
// NETWORKING
links, err := s.getLinks(ctx, p.Name, service, number)
if err != nil {
@ -915,128 +921,79 @@ func fillBindMounts(p types.Project, s types.ServiceConfig, m map[string]mount.M
m[bindMount.Target] = bindMount
}
secrets, err := buildContainerSecretMounts(p, s)
if err != nil {
return nil, err
}
for _, s := range secrets {
if _, found := m[s.Target]; found {
continue
}
m[s.Target] = s
}
configs, err := buildContainerConfigMounts(p, s)
if err != nil {
return nil, err
}
for _, c := range configs {
if _, found := m[c.Target]; found {
continue
}
m[c.Target] = c
}
return m, nil
}
func buildContainerConfigMounts(p types.Project, s types.ServiceConfig) ([]mount.Mount, error) {
var mounts = map[string]mount.Mount{}
func checkContainerConfigsSecrets(p types.Project, s types.ServiceConfig) error {
err := checkContainerConfigs(p, s)
if err != nil {
return err
}
configsBaseDir := "/"
err = checkContainerSecrets(p, s)
if err != nil {
return err
}
return nil
}
func checkContainerConfigs(p types.Project, s types.ServiceConfig) error {
for _, config := range s.Configs {
target := config.Target
if config.Target == "" {
target = configsBaseDir + config.Source
} else if !isAbsTarget(config.Target) {
target = configsBaseDir + config.Target
}
if config.UID != "" || config.GID != "" || config.Mode != nil {
logrus.Warn("config `uid`, `gid` and `mode` are not supported, they will be ignored")
}
definedConfig := p.Configs[config.Source]
if definedConfig.External {
return nil, fmt.Errorf("unsupported external config %s", definedConfig.Name)
return fmt.Errorf("unsupported external config %s", definedConfig.Name)
}
if definedConfig.Driver != "" {
return nil, errors.New("Docker Compose does not support configs.*.driver")
return errors.New("Docker Compose does not support configs.*.driver")
}
if definedConfig.TemplateDriver != "" {
return nil, errors.New("Docker Compose does not support configs.*.template_driver")
return errors.New("Docker Compose does not support configs.*.template_driver")
}
if definedConfig.Environment != "" || definedConfig.Content != "" {
if definedConfig.File != "" {
_, err := os.Stat(definedConfig.File)
if err != nil {
return fmt.Errorf("error with source file of config %s: %s", definedConfig.Name, err.Error())
}
continue
}
bindMount, err := buildMount(p, types.ServiceVolumeConfig{
Type: types.VolumeTypeBind,
Source: definedConfig.File,
Target: target,
ReadOnly: true,
})
if err != nil {
return nil, err
}
mounts[target] = bindMount
}
values := make([]mount.Mount, 0, len(mounts))
for _, v := range mounts {
values = append(values, v)
}
return values, nil
return nil
}
func buildContainerSecretMounts(p types.Project, s types.ServiceConfig) ([]mount.Mount, error) {
var mounts = map[string]mount.Mount{}
secretsDir := "/run/secrets/"
func checkContainerSecrets(p types.Project, s types.ServiceConfig) error {
for _, secret := range s.Secrets {
target := secret.Target
if secret.Target == "" {
target = secretsDir + secret.Source
} else if !isAbsTarget(secret.Target) {
target = secretsDir + secret.Target
}
if secret.UID != "" || secret.GID != "" || secret.Mode != nil {
logrus.Warn("secrets `uid`, `gid` and `mode` are not supported, they will be ignored")
}
definedSecret := p.Secrets[secret.Source]
if definedSecret.External {
return nil, fmt.Errorf("unsupported external secret %s", definedSecret.Name)
return fmt.Errorf("unsupported external secret %s", definedSecret.Name)
}
if definedSecret.Driver != "" {
return nil, errors.New("Docker Compose does not support secrets.*.driver")
return errors.New("Docker Compose does not support secrets.*.driver")
}
if definedSecret.TemplateDriver != "" {
return nil, errors.New("Docker Compose does not support secrets.*.template_driver")
return errors.New("Docker Compose does not support secrets.*.template_driver")
}
if definedSecret.Environment != "" {
if definedSecret.File != "" {
_, err := os.Stat(definedSecret.File)
if err != nil {
return fmt.Errorf("error with source file of secret %s: %s", definedSecret.Name, err.Error())
}
continue
}
mnt, err := buildMount(p, types.ServiceVolumeConfig{
Type: types.VolumeTypeBind,
Source: definedSecret.File,
Target: target,
ReadOnly: true,
})
if err != nil {
return nil, err
}
mounts[target] = mnt
}
values := make([]mount.Mount, 0, len(mounts))
for _, v := range mounts {
values = append(values, v)
}
return values, nil
return nil
}
func isAbsTarget(p string) bool {

View File

@ -21,6 +21,7 @@ import (
"bytes"
"context"
"fmt"
"os"
"strconv"
"time"
@ -31,7 +32,23 @@ import (
func (s *composeService) injectSecrets(ctx context.Context, project *types.Project, service types.ServiceConfig, id string) error {
for _, config := range service.Secrets {
file := project.Secrets[config.Source]
if file.Environment == "" {
content := file.Content
if file.Environment != "" {
env, ok := project.Environment[file.Environment]
if !ok {
return fmt.Errorf("environment variable %q required by file %q is not set", file.Environment, file.Name)
}
content = env
} else if file.File != "" {
data, err := os.ReadFile(file.File)
if err != nil {
return err
}
content = string(data)
}
if content == "" {
continue
}
@ -41,11 +58,7 @@ func (s *composeService) injectSecrets(ctx context.Context, project *types.Proje
config.Target = "/run/secrets/" + config.Target
}
env, ok := project.Environment[file.Environment]
if !ok {
return fmt.Errorf("environment variable %q required by file %q is not set", file.Environment, file.Name)
}
b, err := createTar(env, types.FileReferenceConfig(config))
b, err := createTar(content, types.FileReferenceConfig(config))
if err != nil {
return err
}
@ -64,13 +77,21 @@ func (s *composeService) injectConfigs(ctx context.Context, project *types.Proje
for _, config := range service.Configs {
file := project.Configs[config.Source]
content := file.Content
if file.Environment != "" {
env, ok := project.Environment[file.Environment]
if !ok {
return fmt.Errorf("environment variable %q required by file %q is not set", file.Environment, file.Name)
}
content = env
} else if file.File != "" {
data, err := os.ReadFile(file.File)
if err != nil {
return err
}
content = string(data)
}
if content == "" {
continue
}

View File

@ -52,7 +52,7 @@ func TestLocalComposeVolume(t *testing.T) {
res := c.RunDockerCmd(t, "inspect", "compose-e2e-volume-nginx2-1", "--format", "{{ json .Mounts }}")
output := res.Stdout()
assert.Assert(t, strings.Contains(output, `"Destination":"/usr/src/app/node_modules","Driver":"local","Mode":"z","RW":true,"Propagation":""`), output)
assert.Assert(t, strings.Contains(output, `"Destination":"/myconfig","Mode":"","RW":false,"Propagation":"rprivate"`), output)
assert.Assert(t, !strings.Contains(output, `"Destination":"/myconfig","Mode":"","RW":false,"Propagation":"rprivate"`), output)
})
t.Run("check config content", func(t *testing.T) {