123 lines
2.3 KiB
Go
123 lines
2.3 KiB
Go
package main
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"io/ioutil"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
|
|
"github.com/pkg/errors"
|
|
)
|
|
|
|
type secret struct {
|
|
name string
|
|
keys []string
|
|
}
|
|
|
|
const secretsFolder = "/run/secrets"
|
|
|
|
func main() {
|
|
secrets := parseInput(os.Args[1:])
|
|
|
|
for _, secret := range secrets {
|
|
err := createSecretFiles(secret, secretsFolder)
|
|
if err != nil {
|
|
fmt.Fprintf(os.Stderr, err.Error())
|
|
os.Exit(1)
|
|
}
|
|
}
|
|
}
|
|
|
|
func createSecretFiles(secret secret, path string) error {
|
|
value, ok := os.LookupEnv(secret.name)
|
|
if !ok {
|
|
return fmt.Errorf("%q variable not set", secret.name)
|
|
}
|
|
|
|
secrets := filepath.Join(path, secret.name)
|
|
|
|
if len(secret.keys) == 0 {
|
|
// raw secret
|
|
fmt.Printf("inject secret %q info %s\n", secret.name, secrets)
|
|
return ioutil.WriteFile(secrets, []byte(value), 0444)
|
|
}
|
|
|
|
var unmarshalled interface{}
|
|
err := json.Unmarshal([]byte(value), &unmarshalled)
|
|
if err != nil {
|
|
return errors.Wrapf(err, "%q secret is not a valid JSON document", secret.name)
|
|
}
|
|
|
|
dict, ok := unmarshalled.(map[string]interface{})
|
|
if !ok {
|
|
return errors.Wrapf(err, "%q secret is not a JSON dictionary", secret.name)
|
|
}
|
|
err = os.MkdirAll(secrets, 0755)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if contains(secret.keys, "*") {
|
|
var keys []string
|
|
for k := range dict {
|
|
keys = append(keys, k)
|
|
}
|
|
secret.keys = keys
|
|
}
|
|
|
|
for _, k := range secret.keys {
|
|
path := filepath.Join(secrets, k)
|
|
fmt.Printf("inject secret %q info %s\n", k, path)
|
|
|
|
v, ok := dict[k]
|
|
if !ok {
|
|
return fmt.Errorf("%q secret has no %q key", secret.name, k)
|
|
}
|
|
|
|
var raw []byte
|
|
if s, ok := v.(string); ok {
|
|
raw = []byte(s)
|
|
} else {
|
|
raw, err = json.Marshal(v)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
err = ioutil.WriteFile(path, raw, 0444)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// parseInput parse secret to be dumped into secret files with syntax `VARIABLE_NAME[:COMA_SEPARATED_KEYS]`
|
|
func parseInput(input []string) []secret {
|
|
var secrets []secret
|
|
for _, name := range input {
|
|
i := strings.Index(name, ":")
|
|
var keys []string
|
|
if i > 0 {
|
|
keys = strings.Split(name[i+1:], ",")
|
|
name = name[:i]
|
|
}
|
|
secrets = append(secrets, secret{
|
|
name: name,
|
|
keys: keys,
|
|
})
|
|
}
|
|
return secrets
|
|
}
|
|
|
|
func contains(keys []string, s string) bool {
|
|
for _, k := range keys {
|
|
if k == s {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|