From fbf9465374c65ee2936ac73bfcee5cecf0bc2009 Mon Sep 17 00:00:00 2001 From: Richard McDonald Date: Thu, 20 May 2021 11:15:16 -0400 Subject: [PATCH] Allow another process (eg Vault Agent) to supply a Vault Token --- README.md | 4 +++- config/config.go | 1 + main.go | 4 ++-- snapshot_agent/agent.go | 30 +++++++++++++++++++++++++++--- 4 files changed, 33 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index c9df76f..98fc12d 100644 --- a/README.md +++ b/README.md @@ -67,6 +67,8 @@ If your configuration is right and Vault is running on the same host as the agen `approle` Specifies the approle name used to login. Defaults to "approle". +`token_path` Specifies the path to a file containing a Vault token, if one exists (e.g. a Vault Agent might already be running along the Vault Server, and it writes a token to the Sink file path). If this is specified, approle authentication is skipped. This token must have a policy with at least the permissions described in the authentication section. + ### Storage options Note that if you specify more than one storage option, *all* options will be written to. For example, specifying `local_storage` and `aws_storage` will write to both locations. @@ -118,7 +120,7 @@ Note that if you specify more than one storage option, *all* options will be wri ## Authentication -You must do some quick initial setup prior to being able to use the Snapshot Agent. This involves the following: +Unless another process like a Vault Agent is providing the Snapshot Agent with a token (specified via the `token_path` configuration), you must do some quick initial setup prior to being able to use the Snapshot Agent. This involves the following: `vault login` with an admin user. Create the following policy `vault policy write snapshot ./my_policies/snapshot_policy.hcl` diff --git a/config/config.go b/config/config.go index e478d9a..3f34361 100644 --- a/config/config.go +++ b/config/config.go @@ -21,6 +21,7 @@ type Configuration struct { RoleID string `json:"role_id"` SecretID string `json:"secret_id"` Approle string `json:"approle"` + TokenPath string `json:"token_path"` } // AzureConfig is the configuration for Azure blob snapshots diff --git a/main.go b/main.go index 4af6bd8..9ddf2cd 100644 --- a/main.go +++ b/main.go @@ -46,7 +46,7 @@ func main() { for { if snapshotter.TokenExpiration.Before(time.Now()) { - snapshotter.SetClientTokenFromAppRole(c) + snapshotter.SetClientToken(c) } leader, err := snapshotter.API.Sys().Leader() if err != nil { @@ -54,7 +54,7 @@ func main() { log.Fatalln("Unable to determine leader instance. The snapshot agent will only run on the leader node. Are you running this daemon on a Vault instance?") } leaderIsSelf := leader.IsSelf - if ! leaderIsSelf { + if !leaderIsSelf { log.Println("Not running on leader node, skipping.") } else { var snapshot bytes.Buffer diff --git a/snapshot_agent/agent.go b/snapshot_agent/agent.go index 06a44eb..6bb61fe 100644 --- a/snapshot_agent/agent.go +++ b/snapshot_agent/agent.go @@ -2,8 +2,10 @@ package snapshot_agent import ( "context" + "encoding/json" "errors" "fmt" + "io/ioutil" "log" "net/url" "os" @@ -70,14 +72,36 @@ func (s *Snapshotter) ConfigureVaultClient(config *config.Configuration) error { return err } s.API = api - err = s.SetClientTokenFromAppRole(config) + err = s.SetClientToken(config) if err != nil { return err } return nil } -func (s *Snapshotter) SetClientTokenFromAppRole(config *config.Configuration) error { +func (s *Snapshotter) SetClientToken(config *config.Configuration) error { + if config.TokenPath != "" { + // The process generating this token file (e.g. a Vault Agent) should be + // renewing or replacing the underlying token appropriately. + cBytes, err := ioutil.ReadFile(config.TokenPath) + if err != nil { + return fmt.Errorf("error reading the given TokenPath: %s", err) + } + token := string(cBytes) + s.API.SetToken(token) + childInfo, err := s.API.Auth().Token().LookupSelf() + if err != nil { + s.API.ClearToken() + return fmt.Errorf("error looking up provided token: %s", err) + } + ttl, err := childInfo.Data["ttl"].(json.Number).Int64() + if err != nil { + s.API.ClearToken() + return fmt.Errorf("error converting ttl to int: %s", err) + } + s.TokenExpiration = time.Now().Add(time.Duration((time.Second * time.Duration(ttl)) / 2)) + return nil + } data := map[string]interface{}{ "role_id": config.RoleID, "secret_id": config.SecretID, @@ -86,7 +110,7 @@ func (s *Snapshotter) SetClientTokenFromAppRole(config *config.Configuration) er if config.Approle != "" { approle = config.Approle } - resp, err := s.API.Logical().Write("auth/" + approle + "/login", data) + resp, err := s.API.Logical().Write("auth/"+approle+"/login", data) if err != nil { return fmt.Errorf("error logging into AppRole auth backend: %s", err) }