forked from toolshed/abra
WIP: still hacking on the app new command
Finally had to fork godotenv because it strips comments and we need
those to parse length values (e.g. "FOO=v1 # length=10") (or in other
words, motivation to move to the YAML format).
There is a new secret module now, with functionality for dealing with
generation and parsing of secrets.
The final output needs some work and there is also the final step of
implementing the sending of secrets to the docker daemon. Coming Soon
™️.
This commit is contained in:
101
secret/secret.go
101
secret/secret.go
@ -1,9 +1,23 @@
|
||||
package secret
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os/exec"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"coopcloud.tech/abra/client"
|
||||
"coopcloud.tech/abra/config"
|
||||
"github.com/schultz-is/passgen"
|
||||
)
|
||||
|
||||
type SecretValue struct {
|
||||
Version string
|
||||
Length int
|
||||
}
|
||||
|
||||
func GeneratePasswords(count, length uint) ([]string, error) {
|
||||
passwords, err := passgen.GeneratePasswords(
|
||||
count,
|
||||
@ -33,3 +47,90 @@ func GeneratePassphrases(count uint) ([]string, error) {
|
||||
|
||||
return passphrases, nil
|
||||
}
|
||||
|
||||
func ReadSecretEnvVars(appEnv config.AppEnv) map[string]string {
|
||||
secretEnvVars := make(map[string]string)
|
||||
for envVar := range appEnv {
|
||||
regex := regexp.MustCompile(`^SECRET.*VERSION.*`)
|
||||
if string(regex.Find([]byte(envVar))) != "" {
|
||||
secretEnvVars[envVar] = appEnv[envVar]
|
||||
}
|
||||
}
|
||||
return secretEnvVars
|
||||
}
|
||||
|
||||
func ParseSecretEnvVarName(secretEnvVar string) string {
|
||||
withoutPrefix := strings.TrimPrefix(secretEnvVar, "SECRET_")
|
||||
withoutSuffix := strings.TrimSuffix(withoutPrefix, "_VERSION")
|
||||
return strings.ToLower(withoutSuffix)
|
||||
}
|
||||
|
||||
func ParseSecretEnvVarValue(secretValue string) (SecretValue, error) {
|
||||
values := strings.Split(secretValue, "#")
|
||||
if len(values) == 0 {
|
||||
return SecretValue{}, fmt.Errorf("Unable to parse '%s'", secretValue)
|
||||
}
|
||||
if len(values) == 1 {
|
||||
return SecretValue{Version: values[0], Length: 0}, nil
|
||||
} else {
|
||||
split := strings.Split(values[1], "=")
|
||||
parsed := split[len(split)-1]
|
||||
stripped := strings.ReplaceAll(parsed, " ", "")
|
||||
length, err := strconv.Atoi(stripped)
|
||||
if err != nil {
|
||||
return SecretValue{}, err
|
||||
}
|
||||
return SecretValue{Version: values[0], Length: length}, nil
|
||||
}
|
||||
}
|
||||
|
||||
func GenerateSecrets(secretEnvVars map[string]string, server string) (map[string]string, error) {
|
||||
secrets := make(map[string]string)
|
||||
|
||||
for secretEnvVar := range secretEnvVars {
|
||||
secretName := ParseSecretEnvVarName(secretEnvVar)
|
||||
secretValue, err := ParseSecretEnvVarValue(secretEnvVars[secretEnvVar])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if secretValue.Length > 0 {
|
||||
passwords, err := GeneratePasswords(1, uint(secretValue.Length))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
secrets[secretName] = passwords[0]
|
||||
if err := client.StoreSecret(secretName, passwords[0], server); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
passphrases, err := GeneratePassphrases(1)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
secrets[secretName] = passphrases[0]
|
||||
if err := client.StoreSecret(secretName, passphrases[0], server); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return secrets, nil
|
||||
}
|
||||
|
||||
func PassInsertSecret(secretValue, secretName, appName, server string) error {
|
||||
_, err := exec.LookPath("pass")
|
||||
if err != nil {
|
||||
return errors.New("Pass cannot be found on your $PATH, is it installed?")
|
||||
}
|
||||
|
||||
cmd := fmt.Sprintf(
|
||||
"echo %s | pass insert hosts/%s/%s/%s -m",
|
||||
secretValue, server, appName, secretName,
|
||||
)
|
||||
if err := exec.Command("bash", "-c", cmd).Run(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
Reference in New Issue
Block a user