Skip to content

Commit 43c4961

Browse files
authored
Support _FILE based configuration values (#264)
* Replace envconfig with env * Adjust config options and processing * Added _FILE variant for all password vars. * Try pathenvconfig * Revert everything so far * Use our fork of envconfig with custom lookup * Use our fork of envconfig with custom lookup * Test compose timeout option * Remove secret resolving and specific _FILE config * Fix timing issue in swarm tests * Revert "Test compose timeout option" This reverts commit ab50b21, reversing changes made to 0282514. Revert "Test compose timeout option" This reverts commit 0282514. * Use offen/envconfig v1.5.0 * Add info about _FILE in README * Value > File. Panic on file error. Panic on duplicate presence. * Test panic on duplicate vars and panic on file error.
1 parent 24a6ec9 commit 43c4961

File tree

7 files changed

+42
-35
lines changed

7 files changed

+42
-35
lines changed

README.md

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,9 @@ Documentation references Docker Hub, but all examples will work using ghcr.io ju
139139
## Configuration reference
140140

141141
Backup targets, schedule and retention are configured in environment variables.
142+
143+
Note: You can use any environment variable from below also with a `_FILE` suffix to be able to load the value from a file. This is usually useful when using [Docker Secrets](https://docs.docker.com/engine/swarm/secrets/) or similar.
144+
142145
You can populate below template according to your requirements and use it as your `env_file`:
143146

144147
```ini
@@ -233,14 +236,6 @@ You can populate below template according to your requirements and use it as you
233236
# AWS_ACCESS_KEY_ID="<xxx>"
234237
# AWS_SECRET_ACCESS_KEY="<xxx>"
235238

236-
# It is possible to provide the keys in files, allowing to hide the sensitive data.
237-
# These values have a higher priority than the ones above, meaning if both are set
238-
# the values from the files will be used.
239-
# This option is most useful with Docker [secrets](https://docs.docker.com/engine/swarm/secrets/).
240-
241-
# AWS_ACCESS_KEY_ID_FILE="/path/to/file"
242-
# AWS_SECRET_ACCESS_KEY_FILE="/path/to/file"
243-
244239
# Instead of providing static credentials, you can also use IAM instance profiles
245240
# or similar to provide authentication. Some possible configuration options on AWS:
246241
# - EC2: http://169.254.169.254

cmd/backup/config.go

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,7 @@ type Config struct {
2424
AwsEndpointCACert CertDecoder `envconfig:"AWS_ENDPOINT_CA_CERT"`
2525
AwsStorageClass string `split_words:"true"`
2626
AwsAccessKeyID string `envconfig:"AWS_ACCESS_KEY_ID"`
27-
AwsAccessKeyIDFile string `envconfig:"AWS_ACCESS_KEY_ID_FILE"`
2827
AwsSecretAccessKey string `split_words:"true"`
29-
AwsSecretAccessKeyFile string `split_words:"true"`
3028
AwsIamRoleEndpoint string `split_words:"true"`
3129
AwsPartSize int64 `split_words:"true"`
3230
BackupCompression CompressionType `split_words:"true" default:"gz"`
@@ -80,17 +78,6 @@ type Config struct {
8078
DropboxConcurrencyLevel NaturalNumber `split_words:"true" default:"6"`
8179
}
8280

83-
func (c *Config) resolveSecret(envVar string, secretPath string) (string, error) {
84-
if secretPath == "" {
85-
return envVar, nil
86-
}
87-
data, err := os.ReadFile(secretPath)
88-
if err != nil {
89-
return "", fmt.Errorf("resolveSecret: error reading secret path: %w", err)
90-
}
91-
return string(data), nil
92-
}
93-
9481
type CompressionType string
9582

9683
func (c *CompressionType) Decode(v string) error {

cmd/backup/script.go

Lines changed: 25 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,8 @@ import (
3535
"github.com/docker/docker/api/types/filters"
3636
"github.com/docker/docker/api/types/swarm"
3737
"github.com/docker/docker/client"
38-
"github.com/kelseyhightower/envconfig"
3938
"github.com/leekchan/timeutil"
39+
"github.com/offen/envconfig"
4040
"github.com/otiai10/copy"
4141
"golang.org/x/sync/errgroup"
4242
)
@@ -89,6 +89,28 @@ func newScript() (*script, error) {
8989
return nil
9090
})
9191

92+
envconfig.Lookup = func(key string) (string, bool) {
93+
value, okValue := os.LookupEnv(key)
94+
location, okFile := os.LookupEnv(key + "_FILE")
95+
96+
switch {
97+
case okValue && !okFile: // only value
98+
return value, true
99+
case !okValue && okFile: // only file
100+
contents, err := os.ReadFile(location)
101+
if err != nil {
102+
s.must(fmt.Errorf("newScript: failed to read %s! Error: %s", location, err))
103+
return "", false
104+
}
105+
return string(contents), true
106+
case okValue && okFile: // both
107+
s.must(fmt.Errorf("newScript: both %s and %s are set!", key, key+"_FILE"))
108+
return "", false
109+
default: // neither, ignore
110+
return "", false
111+
}
112+
}
113+
92114
if err := envconfig.Process("", s.c); err != nil {
93115
return nil, fmt.Errorf("newScript: failed to process configuration values: %w", err)
94116
}
@@ -137,18 +159,10 @@ func newScript() (*script, error) {
137159
}
138160

139161
if s.c.AwsS3BucketName != "" {
140-
accessKeyID, err := s.c.resolveSecret(s.c.AwsAccessKeyID, s.c.AwsAccessKeyIDFile)
141-
if err != nil {
142-
return nil, fmt.Errorf("newScript: error resolving AwsAccessKeyID: %w", err)
143-
}
144-
secretAccessKey, err := s.c.resolveSecret(s.c.AwsSecretAccessKey, s.c.AwsSecretAccessKeyFile)
145-
if err != nil {
146-
return nil, fmt.Errorf("newScript: error resolving AwsSecretAccessKey: %w", err)
147-
}
148162
s3Config := s3.Config{
149163
Endpoint: s.c.AwsEndpoint,
150-
AccessKeyID: accessKeyID,
151-
SecretAccessKey: secretAccessKey,
164+
AccessKeyID: s.c.AwsAccessKeyID,
165+
SecretAccessKey: s.c.AwsSecretAccessKey,
152166
IamRoleEndpoint: s.c.AwsIamRoleEndpoint,
153167
EndpointProto: s.c.AwsEndpointProto,
154168
EndpointInsecure: s.c.AwsEndpointInsecure,

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,10 @@ require (
99
github.com/cosiner/argv v0.1.0
1010
github.com/docker/docker v24.0.5+incompatible
1111
github.com/gofrs/flock v0.8.1
12-
github.com/kelseyhightower/envconfig v1.4.0
1312
github.com/klauspost/compress v1.16.7
1413
github.com/leekchan/timeutil v0.0.0-20150802142658-28917288c48d
1514
github.com/minio/minio-go/v7 v7.0.62
15+
github.com/offen/envconfig v1.5.0
1616
github.com/otiai10/copy v1.11.0
1717
github.com/pkg/sftp v1.13.6
1818
github.com/studio-b12/gowebdav v0.9.0

go.sum

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -451,8 +451,6 @@ github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1
451451
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
452452
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
453453
github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
454-
github.com/kelseyhightower/envconfig v1.4.0 h1:Im6hONhd3pLkfDFsbRgu68RDNkGF1r3dvMUtDTo2cv8=
455-
github.com/kelseyhightower/envconfig v1.4.0/go.mod h1:cccZRl6mQpaq41TPp5QxidR+Sa3axMbJDNb//FQX6Gg=
456454
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
457455
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
458456
github.com/klauspost/compress v1.16.7 h1:2mk3MPGNzKyxErAw8YaohYh69+pa4sIQSC0fPGCFR9I=
@@ -527,6 +525,8 @@ github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWb
527525
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
528526
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
529527
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
528+
github.com/offen/envconfig v1.5.0 h1:LHL4wYIDVeoGxSDI40MShmWfss3gYUlCdstfSiSq4Fk=
529+
github.com/offen/envconfig v1.5.0/go.mod h1:L7ny7R+4JWH3VVnZ+ARHvZysWUiZ2eQcm3L0imU9ACY=
530530
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
531531
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
532532
github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc=

test/secrets/run.sh

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,16 @@ pass "Found relevant files in untared backup."
3131
sleep 5
3232
expect_running_containers "5"
3333

34+
docker exec -e AWS_ACCESS_KEY_ID=test $(docker ps -q -f name=backup) backup \
35+
&& fail "Backup should have failed due to duplicate env variables."
36+
37+
pass "Backup failed due to duplicate env variables."
38+
39+
docker exec -e AWS_ACCESS_KEY_ID_FILE=/tmp/nonexistant $(docker ps -q -f name=backup) backup \
40+
&& fail "Backup should have failed due to non existing file env variable."
41+
42+
pass "Backup failed due to non existing file env variable."
43+
3444
docker stack rm test_stack
3545

3646
docker secret rm minio_root_password

test/swarm/run.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ sleep 5
2929
expect_running_containers "5"
3030

3131
docker stack rm test_stack
32+
sleep 1
3233
docker swarm leave --force
3334

3435
sleep 10

0 commit comments

Comments
 (0)