From a9cb53fa1683cbd47f23a47fe36e841edec5e467 Mon Sep 17 00:00:00 2001 From: Luke Granger-Brown Date: Sat, 9 May 2020 14:26:54 +0100 Subject: [PATCH] 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). --- nix/pkgs/secretsync/default.nix | 5 ++- nix/pkgs/secretsync/secretsync.go | 55 ++++++++++++++++++++----------- 2 files changed, 40 insertions(+), 20 deletions(-) diff --git a/nix/pkgs/secretsync/default.nix b/nix/pkgs/secretsync/default.nix index 40df758461..cbbb63a0fc 100644 --- a/nix/pkgs/secretsync/default.nix +++ b/nix/pkgs/secretsync/default.nix @@ -23,6 +23,8 @@ in secretsync // { gitlabEndpoint = "https://hg.lukegb.com"; gitlabProject = "lukegb/depot"; variablesToFile = {}; + manifestVariable = ""; + workingDir = ""; logToStderr = true; } // baseConfig; args = { @@ -31,9 +33,10 @@ in secretsync // { gitlab_project = config.gitlabProject; variable_to_file = lib.mapAttrsToList (name: value: "${name}=${value}") config.variablesToFile; logtostderr = config.logToStderr; - }; + } // (if config.manifestVariable == "" then {} else { manifest_variable = config.manifestVariable; }); in pkgs.writeShellScriptBin config.name '' + cd "${config.workingDir}" exec "${config.pkg}/bin/secretsync" ${lib.cli.toGNUCommandLineShell {} args} ''; } diff --git a/nix/pkgs/secretsync/secretsync.go b/nix/pkgs/secretsync/secretsync.go index a0e4eae6cc..bb9a328fb3 100644 --- a/nix/pkgs/secretsync/secretsync.go +++ b/nix/pkgs/secretsync/secretsync.go @@ -10,6 +10,7 @@ import ( "net/url" "os" "path" + "sort" "strings" 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") gitlabEndpoint = flag.String("gitlab_endpoint", "https://hg.lukegb.com", "GitLab API endpoint") 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 ) @@ -206,33 +208,48 @@ func main() { 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 { - varFutureDataBytes, err := ioutil.ReadFile(varSource) + varFutureData, err := ioutil.ReadFile(varSource) if err != nil { log.Exitf("reading secret source file %q: %v", varSource, err) } - varFutureData := string(varFutureDataBytes) - varCurrent, ok := vars[varKey] - if ok && varCurrent.Value == varFutureData { - log.Infof("%q up-to-date", varKey) - continue - } - varFuture := ProjectVariable{ + if err := createOrReplaceVariable(ProjectVariable{ Key: varKey, VariableType: "file", - Value: varFutureData, + Value: string(varFutureData), 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) } } }