compose/ecs/secrets/main.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
}