secretsync: add concept of manifest variable

This is a file-type variable which contains the original mapping of
VARIABLE_NAME to VARIABLE_DATA.

This can be used to automatically repopulate a repository with
secrets that were originally taken from it and transmitted via
GitLab variables (i.e. out-of-band).
This commit is contained in:
Luke Granger-Brown 2020-05-09 14:26:54 +01:00
parent 0949accaea
commit a9cb53fa16
2 changed files with 40 additions and 20 deletions

View file

@ -23,6 +23,8 @@ in secretsync // {
gitlabEndpoint = "https://hg.lukegb.com"; gitlabEndpoint = "https://hg.lukegb.com";
gitlabProject = "lukegb/depot"; gitlabProject = "lukegb/depot";
variablesToFile = {}; variablesToFile = {};
manifestVariable = "";
workingDir = "";
logToStderr = true; logToStderr = true;
} // baseConfig; } // baseConfig;
args = { args = {
@ -31,9 +33,10 @@ in secretsync // {
gitlab_project = config.gitlabProject; gitlab_project = config.gitlabProject;
variable_to_file = lib.mapAttrsToList (name: value: "${name}=${value}") config.variablesToFile; variable_to_file = lib.mapAttrsToList (name: value: "${name}=${value}") config.variablesToFile;
logtostderr = config.logToStderr; logtostderr = config.logToStderr;
}; } // (if config.manifestVariable == "" then {} else { manifest_variable = config.manifestVariable; });
in in
pkgs.writeShellScriptBin config.name '' pkgs.writeShellScriptBin config.name ''
cd "${config.workingDir}"
exec "${config.pkg}/bin/secretsync" ${lib.cli.toGNUCommandLineShell {} args} exec "${config.pkg}/bin/secretsync" ${lib.cli.toGNUCommandLineShell {} args}
''; '';
} }

View file

@ -10,6 +10,7 @@ import (
"net/url" "net/url"
"os" "os"
"path" "path"
"sort"
"strings" "strings"
log "github.com/golang/glog" log "github.com/golang/glog"
@ -20,6 +21,7 @@ var (
gitlabAccessToken = flag.String("gitlab_access_token", os.Getenv("GITLAB_ACCESS_TOKEN"), "GitLab API Access Token") gitlabAccessToken = flag.String("gitlab_access_token", os.Getenv("GITLAB_ACCESS_TOKEN"), "GitLab API Access Token")
gitlabEndpoint = flag.String("gitlab_endpoint", "https://hg.lukegb.com", "GitLab API endpoint") gitlabEndpoint = flag.String("gitlab_endpoint", "https://hg.lukegb.com", "GitLab API endpoint")
gitlabProject = flag.String("gitlab_project", "lukegb/depot", "Project to sync secrets into") gitlabProject = flag.String("gitlab_project", "lukegb/depot", "Project to sync secrets into")
manifestVariable = flag.String("manifest_variable", "", "If non-empty, a variable to populate with the path to a [VARIABLE]=[FILENAME] manifest, separated by newlines.")
varToFileMap map[string]string varToFileMap map[string]string
) )
@ -206,33 +208,48 @@ func main() {
log.Exitf("gitlab.Variables: %v", err) log.Exitf("gitlab.Variables: %v", err)
} }
createOrReplaceVariable := func(varFuture ProjectVariable) error {
varCurrent, ok := vars[varFuture.Key]
switch {
case !ok:
log.Infof("%q needs to be created", varFuture.Key)
return gitlab.CreateVariable(ctx, *gitlabProject, varFuture)
case varCurrent.Value == varFuture.Value:
log.Infof("%q up-to-date", varFuture.Key)
return nil
default:
log.Infof("%q needs to be updated", varFuture.Key)
return gitlab.UpdateVariable(ctx, *gitlabProject, varFuture)
}
}
for varKey, varSource := range varToFileMap { for varKey, varSource := range varToFileMap {
varFutureDataBytes, err := ioutil.ReadFile(varSource) varFutureData, err := ioutil.ReadFile(varSource)
if err != nil { if err != nil {
log.Exitf("reading secret source file %q: %v", varSource, err) log.Exitf("reading secret source file %q: %v", varSource, err)
} }
varFutureData := string(varFutureDataBytes) if err := createOrReplaceVariable(ProjectVariable{
varCurrent, ok := vars[varKey]
if ok && varCurrent.Value == varFutureData {
log.Infof("%q up-to-date", varKey)
continue
}
varFuture := ProjectVariable{
Key: varKey, Key: varKey,
VariableType: "file", VariableType: "file",
Value: varFutureData, Value: string(varFutureData),
Protected: true, Protected: true,
}); err != nil {
log.Errorf("createOrReplaceVariable(%q, %q): %v", *gitlabProject, varKey, err)
} }
if !ok {
log.Infof("%q needs to be created", varKey)
if err := gitlab.CreateVariable(ctx, *gitlabProject, varFuture); err != nil {
log.Errorf("CreateVariable(%q, %q): %v", *gitlabProject, varKey, err)
}
} else {
log.Infof("%q needs to be updated", varKey)
if err := gitlab.UpdateVariable(ctx, *gitlabProject, varFuture); err != nil {
log.Errorf("UpdateVariable(%q, %q): %v", *gitlabProject, varKey, err)
} }
if *manifestVariable != "" {
var manifestData []string
for k, v := range varToFileMap {
manifestData = append(manifestData, fmt.Sprintf("%s=%s", k, v))
}
sort.Strings(manifestData)
if err := createOrReplaceVariable(ProjectVariable{
Key: *manifestVariable,
VariableType: "file",
Value: strings.Join(manifestData, "\n") + "\n",
Protected: true,
}); err != nil {
log.Errorf("createOrReplaceVariable(%q, %q): %v", *gitlabProject, *manifestVariable, err)
} }
} }
} }