1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
|
// Package flagfolder parses a folder on the disk as if each file in it had the contents of a command line flag.
//
// This is mainly intended to be used with environments like Kubernetes where you have your secrets mounted as a filesystem.
package flagfolder
import (
"flag"
"fmt"
"log/slog"
"os"
"path/filepath"
"github.com/stoewer/go-strcase"
)
// ParseSet parses secrets in a single folder into the given *flag.FlagSet.
//
// By default this will attempt to correct for several styles of naming for files:
//
// * kebab-case (the default)
// * SHOUTING-KEBAB-CASE
// * snake_case
// * SHOUTING_SNAKE_CASE
// * camelCase
// * HammerCase
func ParseSet(secretLocation string, set *flag.FlagSet) error {
var (
data []byte
err error
)
set.VisitAll(func(f *flag.Flag) {
if err != nil {
return
}
for _, fname := range []string{
filepath.Join(secretLocation, f.Name),
filepath.Join(secretLocation, strcase.UpperKebabCase(f.Name)),
filepath.Join(secretLocation, strcase.LowerCamelCase(f.Name)),
filepath.Join(secretLocation, strcase.UpperCamelCase(f.Name)),
filepath.Join(secretLocation, strcase.SnakeCase(f.Name)),
filepath.Join(secretLocation, strcase.UpperSnakeCase(f.Name)),
} {
var ferr error
data, ferr = os.ReadFile(fname)
if ferr != nil {
slog.Debug("can't read", "fname", fname, "err", err)
if os.IsNotExist(ferr) {
continue
}
continue
}
if ferr := f.Value.Set(string(data)); ferr != nil {
err = fmt.Errorf("flagfolder: failed to set flag %q in %s with value %q", f.Name, fname, string(data))
}
}
})
return err
}
// Parse parses all files in every folder under /run/secrets as if they were command-line flags.
//
// This is most useful when you are using environments like Kubernetes where the path of least resistance
// is to mount your secrets as a filesystem. Mount all your secrets into the pod and then let it figure
// itself out!
//
// To use this effectively, ensure that your Pods and Deployments mount secrets as volumes like this:
//
// volumes:
// - name: secret-volume
// secret:
// secretName: shell
// containers:
// - name: shell
// image: ubuntu:latest
// volumeMounts:
// - name: secret-volume
// readOnly: true
// mountPath: "/run/secrets/shell"
//
// By default this will attempt to correct for several styles of naming for files:
//
// * kebab-case (the default)
// * SHOUTING-KEBAB-CASE
// * snake_case
// * SHOUTING_SNAKE_CASE
// * camelCase
// * HammerCase
func Parse() {
stats, err := os.ReadDir("/run/secrets")
if err != nil {
slog.Debug("can't read from /run/secrets", "err", err)
return
}
for _, stat := range stats {
if !stat.IsDir() {
continue
}
loc := filepath.Join("/run/secrets", stat.Name())
if err := ParseSet(loc, flag.CommandLine); err != nil {
slog.Error("can't parse folder", "folder", loc, "err", err)
}
}
}
|