From e915d71bfeac9b0fcaa9719bcea4eb40703d0b0e Mon Sep 17 00:00:00 2001 From: Luan Date: Mon, 20 Sep 2021 15:00:01 +0700 Subject: [PATCH 1/3] add vault's k8s authentication support --- Dockerfile | 26 +++++++++++++++++++++++ README.md | 21 ++++++++++++++++++ config/config.go | 23 +++++++++++--------- snapshot.json | 18 ++++++++++++++++ snapshot_agent/agent.go | 47 ++++++++++++++++++++++++++++++++++++----- 5 files changed, 120 insertions(+), 15 deletions(-) create mode 100644 Dockerfile create mode 100644 snapshot.json diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..d847702 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,26 @@ +FROM golang:1.16 AS builder + +ENV GO111MODULE=on \ + CGO_ENABLED=0 \ + GOOS=linux \ + GOARCH=amd64 + +RUN mkdir /build +WORKDIR /build + +COPY . . + +RUN go mod download +RUN go build \ + -a \ + -trimpath \ + -ldflags "-s -w -extldflags '-static'" \ + -tags 'osusergo netgo static_build' \ + -o ../vault_raft_snapshot_agent \ + ./main.go + +FROM alpine +WORKDIR / +COPY --from=builder /vault_raft_snapshot_agent . +COPY snapshot.json /etc/vault.d/snapshot.json +ENTRYPOINT ["/vault_raft_snapshot_agent"] diff --git a/README.md b/README.md index c9df76f..4475429 100644 --- a/README.md +++ b/README.md @@ -61,12 +61,25 @@ If your configuration is right and Vault is running on the same host as the agen `frequency` How often to run the snapshot agent. Examples: `30s`, `1h`. See https://golang.org/pkg/time/#ParseDuration for a full list of valid time units. + +### Default authentication mode `role_id` Specifies the role_id used to call the Vault API. See the authentication steps below. `secret_id` Specifies the secret_id used to call the Vault API. `approle` Specifies the approle name used to login. Defaults to "approle". + +### Kubernetes authentication mode +Incase we're running the application under kubernetes, we can use Vault's Kubernetes Auth +as below. Read more on [kubernetes auth mode](https://www.vaultproject.io/docs/auth/kubernetes) + +`vault_auth_method` Set it to "k8s", otherwise, approle will be chosen + +`vault_auth_role` Specifies vault k8s auth role + +`vault_auth_path` Specifies vault k8s auth path + ### 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,6 +131,9 @@ Note that if you specify more than one storage option, *all* options will be wri ## Authentication + +### Default authentication mode + 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. @@ -143,3 +159,8 @@ and copy your secret and role ids, and place them into the snapshot file. The s The AppRole allows the snapshot agent to automatically rotate tokens to avoid long-lived credentials. To learn more about AppRole's and why this project chose to use them, see [the Vault docs](https://www.vaultproject.io/docs/auth/approle) + + +### Kubernetes authentication mode + +To Enable Kubernetes authentication mode, we should follow these steps from [the Vault docs](https://www.vaultproject.io/docs/auth/kubernetes#configuration) diff --git a/config/config.go b/config/config.go index e478d9a..293ec7a 100644 --- a/config/config.go +++ b/config/config.go @@ -11,16 +11,19 @@ import ( // Configuration is the overall config object type Configuration struct { - Address string `json:"addr"` - Retain int64 `json:"retain"` - Frequency string `json:"frequency"` - AWS S3Config `json:"aws_storage"` - Local LocalConfig `json:"local_storage"` - GCP GCPConfig `json:"google_storage"` - Azure AzureConfig `json:"azure_storage"` - RoleID string `json:"role_id"` - SecretID string `json:"secret_id"` - Approle string `json:"approle"` + Address string `json:"addr"` + Retain int64 `json:"retain"` + Frequency string `json:"frequency"` + AWS S3Config `json:"aws_storage"` + Local LocalConfig `json:"local_storage"` + GCP GCPConfig `json:"google_storage"` + Azure AzureConfig `json:"azure_storage"` + RoleID string `json:"role_id"` + SecretID string `json:"secret_id"` + Approle string `json:"approle"` + K8sAuthRole string `json:"k8s_auth_role,omitempty"` + K8sAuthPath string `json:"k8s_auth_path,omitempty"` + VaultAuthMethod string `json:"vault_auth_method,omitempty"` } // AzureConfig is the configuration for Azure blob snapshots diff --git a/snapshot.json b/snapshot.json new file mode 100644 index 0000000..6a3b0a6 --- /dev/null +++ b/snapshot.json @@ -0,0 +1,18 @@ +{ + "addr":"http://vaul-addr:8200", + "retain":72, + "frequency":"3600s", + "role_id": "", + "secret_id":"", + "secret_access_key":"", + "s3_region":"", + "s3_bucket":"", + "s3_force_path_style":true + } +} diff --git a/snapshot_agent/agent.go b/snapshot_agent/agent.go index 06a44eb..8d6da2b 100644 --- a/snapshot_agent/agent.go +++ b/snapshot_agent/agent.go @@ -7,6 +7,7 @@ import ( "log" "net/url" "os" + "path" "time" "cloud.google.com/go/storage" @@ -70,11 +71,10 @@ func (s *Snapshotter) ConfigureVaultClient(config *config.Configuration) error { return err } s.API = api - err = s.SetClientTokenFromAppRole(config) - if err != nil { - return err + if config.VaultAuthMethod == "k8s" { + return s.SetClientTokenFromK8sAuth(config) } - return nil + return s.SetClientTokenFromAppRole(config) } func (s *Snapshotter) SetClientTokenFromAppRole(config *config.Configuration) error { @@ -86,7 +86,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) } @@ -95,6 +95,43 @@ func (s *Snapshotter) SetClientTokenFromAppRole(config *config.Configuration) er return nil } +func (s *Snapshotter) SetClientTokenFromK8sAuth(config *config.Configuration) error { + + if config.K8sAuthPath == "" || config.K8sAuthRole == "" { + return errors.New("missing k8s auth definitions") + } + + jwt, err := os.ReadFile("/var/run/secrets/kubernetes.io/serviceaccount/token") + if err != nil { + return err + } + data := map[string]string{ + "role": config.K8sAuthRole, + "jwt": string(jwt), + } + + login := path.Clean("/v1/auth/" + config.K8sAuthPath + "/login") + req := s.API.NewRequest("POST", login) + req.SetJSONBody(data) + + resp, err := s.API.RawRequest(req) + if err != nil { + return err + } + if respErr := resp.Error(); respErr != nil { + return respErr + } + + var result vaultApi.Secret + if err := resp.DecodeJSON(&result); err != nil { + return err + } + + s.API.SetToken(result.Auth.ClientToken) + s.TokenExpiration = time.Now().Add(time.Duration((time.Second * time.Duration(result.Auth.LeaseDuration)) / 2)) + return nil +} + func (s *Snapshotter) ConfigureS3(config *config.Configuration) error { awsConfig := &aws.Config{Region: aws.String(config.AWS.Region)} From a50e05a65015090e98c1ca7ff6161b2c43f9f72b Mon Sep 17 00:00:00 2001 From: Luan Date: Mon, 20 Sep 2021 15:43:47 +0700 Subject: [PATCH 2/3] add renew token k8s at main.go --- main.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/main.go b/main.go index 4af6bd8..15e011a 100644 --- a/main.go +++ b/main.go @@ -46,6 +46,9 @@ func main() { for { if snapshotter.TokenExpiration.Before(time.Now()) { + if c.VaultAuthMethod == "k8s" { + snapshotter.SetClientTokenFromK8sAuth(c) + } snapshotter.SetClientTokenFromAppRole(c) } leader, err := snapshotter.API.Sys().Leader() @@ -54,7 +57,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 From 74d7799de50263e0bd9d104bcac9915fe638f848 Mon Sep 17 00:00:00 2001 From: Luan Date: Tue, 21 Sep 2021 10:08:01 +0700 Subject: [PATCH 3/3] vaultAuth by switching --- main.go | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/main.go b/main.go index 15e011a..e9b38b8 100644 --- a/main.go +++ b/main.go @@ -46,10 +46,12 @@ func main() { for { if snapshotter.TokenExpiration.Before(time.Now()) { - if c.VaultAuthMethod == "k8s" { + switch c.VaultAuthMethod { + case "k8s": snapshotter.SetClientTokenFromK8sAuth(c) + default: + snapshotter.SetClientTokenFromAppRole(c) } - snapshotter.SetClientTokenFromAppRole(c) } leader, err := snapshotter.API.Sys().Leader() if err != nil {