Skip to content

Commit 2fc6df3

Browse files
authored
Adding headers to Vault for metadata logging (#15)
1 parent 8926956 commit 2fc6df3

File tree

5 files changed

+137
-60
lines changed

5 files changed

+137
-60
lines changed

CHANGELOG.md

+4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
# Changelog
22

3+
## v0.1.2 (2021-06-14)
4+
### Changed
5+
* Adding HTTP headers to Vault client for logging (e.g. transaction ID)
6+
37
## v0.1.1 (2021-06-09)
48
### Fixed
59
* Add additional valid status codes for Vault health check

service/handlers.go

+71-12
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import (
1414
"github.com/argoproj-labs/argo-cloudops/internal/env"
1515
"github.com/argoproj-labs/argo-cloudops/service/internal/credentials"
1616
"github.com/argoproj-labs/argo-cloudops/service/internal/workflow"
17+
vault "github.com/hashicorp/vault/api"
1718

1819
"github.com/aws/aws-sdk-go/aws/arn"
1920
"github.com/distribution/distribution/reference"
@@ -72,12 +73,14 @@ var isStringAlphaNumericUnderscore = regexp.MustCompile(`^([a-zA-Z])[a-zA-Z0-9_]
7273
// HTTP handler
7374
type handler struct {
7475
logger log.Logger
75-
newCredentialsProvider func(a credentials.Authorization) (credentials.Provider, error)
76+
newCredentialsProvider func(a credentials.Authorization, svc *vault.Client) (credentials.Provider, error)
7677
argo workflow.Workflow
7778
argoCtx context.Context
7879
config *Config
7980
gitClient gitClient
8081
env env.EnvVars
82+
newCredsProviderSvc func(c credentials.VaultConfig, h http.Header) (*vault.Client, error)
83+
vaultConfig credentials.VaultConfig
8184
}
8285

8386
// Validates workflow parameters
@@ -210,7 +213,7 @@ func (h handler) createWorkflowFromGit(w http.ResponseWriter, r *http.Request) {
210213

211214
level.Debug(l).Log("message", "creating workflow")
212215
cwr.Type = cgwr.Type
213-
h.createWorkflowFromRequest(ctx, w, a, cwr, l)
216+
h.createWorkflowFromRequest(ctx, w, r, a, cwr, l)
214217
}
215218

216219
// Creates a workflow
@@ -245,11 +248,11 @@ func (h handler) createWorkflow(w http.ResponseWriter, r *http.Request) {
245248
}
246249

247250
level.Debug(l).Log("message", "creating workflow")
248-
h.createWorkflowFromRequest(ctx, w, a, cwr, l)
251+
h.createWorkflowFromRequest(ctx, w, r, a, cwr, l)
249252
}
250253

251254
// Creates a workflow
252-
func (h handler) createWorkflowFromRequest(ctx context.Context, w http.ResponseWriter, a *credentials.Authorization, cwr createWorkflowRequest, l log.Logger) {
255+
func (h handler) createWorkflowFromRequest(ctx context.Context, w http.ResponseWriter, r *http.Request, a *credentials.Authorization, cwr createWorkflowRequest, l log.Logger) {
253256
level.Debug(l).Log("message", "validating workflow parameters")
254257
if err := h.validateWorkflowParameters(cwr.Parameters); err != nil {
255258
level.Error(l).Log("message", "error in parameters", "error", err)
@@ -329,8 +332,15 @@ func (h handler) createWorkflowFromRequest(ctx context.Context, w http.ResponseW
329332
return
330333
}
331334

335+
cpSvc, err := h.newCredsProviderSvc(h.vaultConfig, r.Header)
336+
if err != nil {
337+
level.Error(l).Log("message", "error creating credentials provider service", "error", err)
338+
h.errorResponse(w, "error creating credentials provider service", http.StatusBadRequest, err)
339+
return
340+
}
341+
332342
level.Debug(l).Log("message", "creating new credentials provider")
333-
cp, err := h.newCredentialsProvider(*a)
343+
cp, err := h.newCredentialsProvider(*a, cpSvc)
334344
if err != nil {
335345
level.Error(l).Log("message", "bad or unknown credentials provider", "error", err)
336346
h.errorResponse(w, "bad or unknown credentials provider", http.StatusInternalServerError, err)
@@ -445,8 +455,15 @@ func (h handler) getTarget(w http.ResponseWriter, r *http.Request) {
445455
return
446456
}
447457

458+
cpSvc, err := h.newCredsProviderSvc(h.vaultConfig, r.Header)
459+
if err != nil {
460+
level.Error(l).Log("message", "error creating credentials provider service", "error", err)
461+
h.errorResponse(w, "error creating credentials provider service", http.StatusBadRequest, err)
462+
return
463+
}
464+
448465
level.Debug(l).Log("message", "creating credential provider")
449-
cp, err := h.newCredentialsProvider(*a)
466+
cp, err := h.newCredentialsProvider(*a, cpSvc)
450467
if err != nil {
451468
level.Error(l).Log("message", "error creating credentials provider", "error", err)
452469
h.errorResponse(w, "error creating credentials provider", http.StatusBadRequest, err)
@@ -564,8 +581,15 @@ func (h handler) createProject(w http.ResponseWriter, r *http.Request) {
564581
return
565582
}
566583

584+
cpSvc, err := h.newCredsProviderSvc(h.vaultConfig, r.Header)
585+
if err != nil {
586+
level.Error(l).Log("message", "error creating credentials provider service", "error", err)
587+
h.errorResponse(w, "error creating credentials provider service", http.StatusBadRequest, err)
588+
return
589+
}
590+
567591
level.Debug(l).Log("message", "creating credential provider")
568-
cp, err := h.newCredentialsProvider(*a)
592+
cp, err := h.newCredentialsProvider(*a, cpSvc)
569593
if err != nil {
570594
level.Error(l).Log("message", "error creating credentials provider", "error", err)
571595
h.errorResponse(w, "error creating credentials provider", http.StatusBadRequest, err)
@@ -633,8 +657,15 @@ func (h handler) getProject(w http.ResponseWriter, r *http.Request) {
633657
return
634658
}
635659

660+
cpSvc, err := h.newCredsProviderSvc(h.vaultConfig, r.Header)
661+
if err != nil {
662+
level.Error(l).Log("message", "error creating credentials provider service", "error", err)
663+
h.errorResponse(w, "error creating credentials provider service", http.StatusBadRequest, err)
664+
return
665+
}
666+
636667
level.Debug(l).Log("message", "creating credential provider")
637-
cp, err := h.newCredentialsProvider(*a)
668+
cp, err := h.newCredentialsProvider(*a, cpSvc)
638669
if err != nil {
639670
level.Error(l).Log("message", "error creating credentials provider", "error", err)
640671
h.errorResponse(w, "error creating credentials provider", http.StatusBadRequest, err)
@@ -674,8 +705,15 @@ func (h handler) deleteProject(w http.ResponseWriter, r *http.Request) {
674705
return
675706
}
676707

708+
cpSvc, err := h.newCredsProviderSvc(h.vaultConfig, r.Header)
709+
if err != nil {
710+
level.Error(l).Log("message", "error creating credentials provider service", "error", err)
711+
h.errorResponse(w, "error creating credentials provider service", http.StatusBadRequest, err)
712+
return
713+
}
714+
677715
level.Debug(l).Log("message", "creating credential provider")
678-
cp, err := h.newCredentialsProvider(*a)
716+
cp, err := h.newCredentialsProvider(*a, cpSvc)
679717
if err != nil {
680718
level.Error(l).Log("message", "error creating credentials provider", "error", err)
681719
h.errorResponse(w, "error creating credentials provider", http.StatusBadRequest, err)
@@ -760,8 +798,15 @@ func (h handler) createTarget(w http.ResponseWriter, r *http.Request) {
760798
return
761799
}
762800

801+
cpSvc, err := h.newCredsProviderSvc(h.vaultConfig, r.Header)
802+
if err != nil {
803+
level.Error(l).Log("message", "error creating credentials provider service", "error", err)
804+
h.errorResponse(w, "error creating credentials provider service", http.StatusBadRequest, err)
805+
return
806+
}
807+
763808
level.Debug(l).Log("message", "creating credential provider")
764-
cp, err := h.newCredentialsProvider(*a)
809+
cp, err := h.newCredentialsProvider(*a, cpSvc)
765810
if err != nil {
766811
level.Error(l).Log("message", "error creating credentials provider", "error", err)
767812
h.errorResponse(w, "error creating credentials provider", http.StatusInternalServerError, err)
@@ -845,8 +890,15 @@ func (h handler) deleteTarget(w http.ResponseWriter, r *http.Request) {
845890
return
846891
}
847892

893+
cpSvc, err := h.newCredsProviderSvc(h.vaultConfig, r.Header)
894+
if err != nil {
895+
level.Error(l).Log("message", "error creating credentials provider service", "error", err)
896+
h.errorResponse(w, "error creating credentials provider service", http.StatusBadRequest, err)
897+
return
898+
}
899+
848900
level.Debug(l).Log("message", "creating credential provider")
849-
cp, err := h.newCredentialsProvider(*a)
901+
cp, err := h.newCredentialsProvider(*a, cpSvc)
850902
if err != nil {
851903
level.Error(l).Log("message", "error creating credentials provider", "error", err)
852904
h.errorResponse(w, "error creating credentials provider", http.StatusBadRequest, err)
@@ -886,8 +938,15 @@ func (h handler) listTargets(w http.ResponseWriter, r *http.Request) {
886938
return
887939
}
888940

941+
cpSvc, err := h.newCredsProviderSvc(h.vaultConfig, r.Header)
942+
if err != nil {
943+
level.Error(l).Log("message", "error creating credentials provider service", "error", err)
944+
h.errorResponse(w, "error creating credentials provider service", http.StatusBadRequest, err)
945+
return
946+
}
947+
889948
level.Debug(l).Log("message", "creating credential provider")
890-
cp, err := h.newCredentialsProvider(*a)
949+
cp, err := h.newCredentialsProvider(*a, cpSvc)
891950
if err != nil {
892951
level.Error(l).Log("message", "error creating credentials provider", "error", err)
893952
h.errorResponse(w, "error creating credentials provider", http.StatusInternalServerError, err)

service/handlers_test.go

+10-7
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@ import (
1212
"path/filepath"
1313
"testing"
1414

15-
"github.com/argoproj-labs/argo-cloudops/service/internal/credentials"
1615
"github.com/argoproj-labs/argo-cloudops/internal/env"
16+
"github.com/argoproj-labs/argo-cloudops/service/internal/credentials"
1717
"github.com/argoproj-labs/argo-cloudops/service/internal/workflow"
1818

1919
"github.com/go-kit/kit/log"
@@ -62,15 +62,12 @@ func (m mockWorkflowSvc) Submit(ctx context.Context, from string, parameters map
6262
return "success", nil
6363
}
6464

65-
func newMockProvider(svc *vault.Client) func(a credentials.Authorization) (credentials.Provider, error) {
66-
return func(a credentials.Authorization) (credentials.Provider, error) {
67-
return &mockCredentialsProvider{}, nil
68-
}
65+
func newMockProvider(a credentials.Authorization, svc *vault.Client) (credentials.Provider, error) {
66+
return &mockCredentialsProvider{}, nil
6967
}
7068

7169
type mockCredentialsProvider struct{}
7270

73-
7471
func (m mockCredentialsProvider) GetToken() (string, error) {
7572
return testPassword, nil
7673
}
@@ -133,6 +130,10 @@ func (m mockCredentialsProvider) TargetExists(name string) (bool, error) {
133130
return false, nil
134131
}
135132

133+
func mockCredsProvSvc(c credentials.VaultConfig, h http.Header) (*vault.Client, error) {
134+
return &vault.Client{}, nil
135+
}
136+
136137
type test struct {
137138
name string
138139
req interface{}
@@ -580,13 +581,15 @@ func executeRequest(method string, url string, body *bytes.Buffer, asAdmin bool)
580581

581582
h := handler{
582583
logger: log.NewNopLogger(),
583-
newCredentialsProvider: newMockProvider(nil),
584+
newCredentialsProvider: newMockProvider,
584585
argo: mockWorkflowSvc{},
585586
config: config,
586587
gitClient: newMockGitClient(),
588+
newCredsProviderSvc: mockCredsProvSvc,
587589
env: env.EnvVars{
588590
AdminSecret: testPassword},
589591
}
592+
590593
var router = setupRouter(h)
591594
req, _ := http.NewRequest(method, url, body)
592595
authorizationHeader := "vault:user:" + testPassword

service/internal/credentials/vault.go

+45-8
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package credentials
33
import (
44
"errors"
55
"fmt"
6+
"net/http"
67
"strings"
78

89
vault "github.com/hashicorp/vault/api"
@@ -51,15 +52,51 @@ type VaultProvider struct {
5152
}
5253

5354
// Returns a new vaultCredentialsProvider
54-
func NewVaultProvider(svc *vault.Client) func(a Authorization) (Provider, error) {
55-
return func(a Authorization) (Provider, error) {
56-
return &VaultProvider{
57-
vaultLogicalSvc: vaultLogical(svc.Logical()),
58-
vaultSysSvc: vaultSys(svc.Sys()),
59-
roleID: a.Key,
60-
secretID: a.Secret,
61-
}, nil
55+
func NewVaultProvider(a Authorization, svc *vault.Client) (Provider, error) {
56+
return &VaultProvider{
57+
vaultLogicalSvc: vaultLogical(svc.Logical()),
58+
vaultSysSvc: vaultSys(svc.Sys()),
59+
roleID: a.Key,
60+
secretID: a.Secret,
61+
}, nil
62+
}
63+
64+
type VaultConfig struct {
65+
config *vault.Config
66+
role string
67+
secret string
68+
}
69+
70+
// NewVaultConfig returns a new VaultConfig.
71+
func NewVaultConfig(config *vault.Config, role, secret string) *VaultConfig {
72+
return &VaultConfig{
73+
config: config,
74+
role: role,
75+
secret: secret,
76+
}
77+
}
78+
79+
// TODO before open sourcing we should provide the token instead of generating it
80+
func NewVaultSvc(c VaultConfig, h http.Header) (*vault.Client, error) {
81+
vaultSvc, err := vault.NewClient(c.config)
82+
if err != nil {
83+
return nil, err
6284
}
85+
86+
vaultSvc.SetHeaders(h)
87+
88+
options := map[string]interface{}{
89+
"role_id": c.role,
90+
"secret_id": c.secret,
91+
}
92+
93+
sec, err := vaultSvc.Logical().Write("auth/approle/login", options)
94+
if err != nil {
95+
return nil, err
96+
}
97+
98+
vaultSvc.SetToken(sec.Auth.ClientToken)
99+
return vaultSvc, nil
63100
}
64101

65102
// Authorization represents a user's authorization token.

service/main.go

+7-33
Original file line numberDiff line numberDiff line change
@@ -36,12 +36,6 @@ func main() {
3636
}
3737
level.Info(logger).Log("message", fmt.Sprintf("loading config '%s' completed", env.ConfigFilePath))
3838

39-
vaultSvc, err := newVaultSvc(env.VaultAddress, env.VaultRole, env.VaultSecret)
40-
if err != nil {
41-
level.Error(logger).Log("message", "error creating vault service client", "error", err)
42-
panic("error creating vault service client")
43-
}
44-
4539
gitClient, err := newBasicGitClient(env.SSHPEMFile)
4640
if err != nil {
4741
level.Error(logger).Log("message", "error creating git client", "error", err)
@@ -56,12 +50,18 @@ func main() {
5650
// setupRouter and applying it to the request will wipe out Mux vars (or any other data Mux sets in its context).
5751
h := handler{
5852
logger: logger,
59-
newCredentialsProvider: credentials.NewVaultProvider(vaultSvc),
53+
newCredentialsProvider: credentials.NewVaultProvider,
6054
argo: workflow.NewArgoWorkflow(argoClient.NewWorkflowServiceClient(), env.ArgoNamespace),
6155
argoCtx: argoCtx,
6256
config: config,
6357
gitClient: gitClient,
6458
env: env,
59+
// Function that the handler will use to create a Vault svc using the vaultConfig below.
60+
// Vault svc needs to be created within the handler methods because Vault uses headers
61+
// to add metadata (e.g. transaction ID) to its logs.
62+
newCredsProviderSvc: credentials.NewVaultSvc,
63+
// A Vault config is needed to be able to create a Vault service from within the handlers.
64+
vaultConfig: *credentials.NewVaultConfig(&vault.Config{Address: env.VaultAddress}, env.VaultRole, env.VaultSecret),
6565
}
6666

6767
level.Info(logger).Log("message", "starting web service", "vault addr", env.VaultAddress, "argoAddr", env.ArgoAddress)
@@ -82,29 +82,3 @@ func setLogLevel(logger *log.Logger, logLevel string) {
8282
*logger = level.NewFilter(*logger, level.AllowInfo())
8383
}
8484
}
85-
86-
// TODO before open sourcing we should provide the token instead of generating it
87-
func newVaultSvc(vaultAddr, role, secret string) (*vault.Client, error) {
88-
config := &vault.Config{
89-
Address: vaultAddr,
90-
}
91-
92-
vaultSvc, err := vault.NewClient(config)
93-
if err != nil {
94-
return nil, err
95-
96-
}
97-
98-
options := map[string]interface{}{
99-
"role_id": role,
100-
"secret_id": secret,
101-
}
102-
103-
sec, err := vaultSvc.Logical().Write("auth/approle/login", options)
104-
if err != nil {
105-
return nil, err
106-
}
107-
108-
vaultSvc.SetToken(sec.Auth.ClientToken)
109-
return vaultSvc, nil
110-
}

0 commit comments

Comments
 (0)