diff options
-rw-r--r-- | secrets/client.go | 16 | ||||
-rw-r--r-- | secrets/noop_client.go | 17 | ||||
-rw-r--r-- | secrets/vault_client.go | 67 |
3 files changed, 96 insertions, 4 deletions
diff --git a/secrets/client.go b/secrets/client.go index 92c46ef..779f28c 100644 --- a/secrets/client.go +++ b/secrets/client.go | |||
@@ -33,6 +33,12 @@ type ApiKey struct { | |||
33 | Key string `json:"key" mapstructure:"key"` | 33 | Key string `json:"key" mapstructure:"key"` |
34 | } | 34 | } |
35 | 35 | ||
36 | type AWSCredential struct { | ||
37 | AccessKeyId string `json:"access_key" mapstructure:"access_key"` | ||
38 | SecretAccessKey string `json:"secret_key" mapstructure:"secret_key"` | ||
39 | SessionToken string `json:"security_token" mapstructure:"security_token"` | ||
40 | } | ||
41 | |||
36 | type RSAKey struct { | 42 | type RSAKey struct { |
37 | Key string `json:"key" mapstructure:"key"` | 43 | Key string `json:"key" mapstructure:"key"` |
38 | } | 44 | } |
@@ -63,9 +69,13 @@ func (k *RSAKey) RSAPrivateKey() (*rsa.PrivateKey, error) { | |||
63 | // to inject stubs to code that doesn't care about the fact that a | 69 | // to inject stubs to code that doesn't care about the fact that a |
64 | // manager may exist. | 70 | // manager may exist. |
65 | type Client interface { | 71 | type Client interface { |
66 | DatabaseCredential(context.Context, string) (*Credential, Handle, error) | 72 | DatabaseCredential(ctx context.Context, suffix string) (*Credential, Handle, error) |
67 | Secret(context.Context, string, any) (Handle, error) | 73 | Secret(ctx context.Context, suffix string, out any) (Handle, error) |
68 | WriteSecret(context.Context, string, any) error | 74 | RawSecret(ctx context.Context, path string, out any) (Handle, error) |
75 | AWSIAMUser(ctx context.Context, name string) (*AWSCredential, Handle, error) | ||
76 | AWSAssumeRoleSimple(ctx context.Context, name string) (*AWSCredential, Handle, error) | ||
77 | AWSAssumeRole(ctx context.Context, name string, sessionName string, ttl time.Duration) (*AWSCredential, Handle, error) | ||
78 | WriteSecret(ctx context.Context, suffix string, out any) error | ||
69 | Destroy(Handle) error | 79 | Destroy(Handle) error |
70 | MakeNonCritical(Handle) error | 80 | MakeNonCritical(Handle) error |
71 | } | 81 | } |
diff --git a/secrets/noop_client.go b/secrets/noop_client.go index 85bd736..e727e51 100644 --- a/secrets/noop_client.go +++ b/secrets/noop_client.go | |||
@@ -3,6 +3,7 @@ package secrets | |||
3 | import ( | 3 | import ( |
4 | "context" | 4 | "context" |
5 | "sync" | 5 | "sync" |
6 | "time" | ||
6 | ) | 7 | ) |
7 | 8 | ||
8 | type NoopHandle struct{} | 9 | type NoopHandle struct{} |
@@ -33,6 +34,22 @@ func (c *NoopClient) Secret(ctx context.Context, path string, out any) (Handle, | |||
33 | return &NoopHandle{}, nil | 34 | return &NoopHandle{}, nil |
34 | } | 35 | } |
35 | 36 | ||
37 | func (c *NoopClient) RawSecret(ctx context.Context, path string, out any) (Handle, error) { | ||
38 | return &NoopHandle{}, nil | ||
39 | } | ||
40 | |||
41 | func (c *NoopClient) AWSIAMUser(ctx context.Context, name string) (*AWSCredential, Handle, error) { | ||
42 | return &AWSCredential{}, &NoopHandle{}, nil | ||
43 | } | ||
44 | |||
45 | func (c *NoopClient) AWSAssumeRoleSimple(ctx context.Context, name string) (*AWSCredential, Handle, error) { | ||
46 | return &AWSCredential{}, &NoopHandle{}, nil | ||
47 | } | ||
48 | |||
49 | func (c *NoopClient) AWSAssumeRole(ctx context.Context, name string, sessionName string, ttl time.Duration) (*AWSCredential, Handle, error) { | ||
50 | return &AWSCredential{}, &NoopHandle{}, nil | ||
51 | } | ||
52 | |||
36 | func (c *NoopClient) WriteSecret(ctx context.Context, path string, in any) error { | 53 | func (c *NoopClient) WriteSecret(ctx context.Context, path string, in any) error { |
37 | return nil | 54 | return nil |
38 | } | 55 | } |
diff --git a/secrets/vault_client.go b/secrets/vault_client.go index ce26dbe..b84b344 100644 --- a/secrets/vault_client.go +++ b/secrets/vault_client.go | |||
@@ -289,8 +289,25 @@ func (c *VaultClient) makeHandle(name string, s *api.Secret) Handle { | |||
289 | return h | 289 | return h |
290 | } | 290 | } |
291 | 291 | ||
292 | func (c *VaultClient) writeHandle(ctx context.Context, prefix, suffix string, data map[string]any) (Handle, error) { | ||
293 | key := suffix | ||
294 | if prefix != "" { | ||
295 | key = path.Join(prefix, suffix) | ||
296 | } | ||
297 | |||
298 | s, err := c.logical.WriteWithContext(ctx, key, data) | ||
299 | if err != nil { | ||
300 | return nil, fmt.Errorf("writeHandle: error writing to Vault: %w", err) | ||
301 | } | ||
302 | |||
303 | return c.makeHandle(key, s), nil | ||
304 | } | ||
305 | |||
292 | func (c *VaultClient) read(ctx context.Context, prefix, suffix string) (Handle, error) { | 306 | func (c *VaultClient) read(ctx context.Context, prefix, suffix string) (Handle, error) { |
293 | key := path.Join(prefix, suffix) | 307 | key := suffix |
308 | if prefix != "" { | ||
309 | key = path.Join(prefix, suffix) | ||
310 | } | ||
294 | 311 | ||
295 | s, err := c.logical.ReadWithContext(ctx, key) | 312 | s, err := c.logical.ReadWithContext(ctx, key) |
296 | if err != nil { | 313 | if err != nil { |
@@ -358,6 +375,54 @@ func (c *VaultClient) Secret(ctx context.Context, suffix string, out any) (Handl | |||
358 | return h, nil | 375 | return h, nil |
359 | } | 376 | } |
360 | 377 | ||
378 | func (c *VaultClient) RawSecret(ctx context.Context, path string, out any) (Handle, error) { | ||
379 | h, err := c.read(ctx, "", path) | ||
380 | if err != nil { | ||
381 | return nil, err | ||
382 | } | ||
383 | |||
384 | if err = mapstructure.Decode(h.(*VaultHandle).secret.Data["data"], out); err != nil { | ||
385 | return nil, err | ||
386 | } | ||
387 | |||
388 | return h, nil | ||
389 | } | ||
390 | |||
391 | func (c *VaultClient) AWSAssumeRoleSimple(ctx context.Context, name string) (*AWSCredential, Handle, error) { | ||
392 | return c.AWSAssumeRole(ctx, name, fmt.Sprintf("%s-%d", name, time.Now().UnixNano()), time.Hour) | ||
393 | } | ||
394 | |||
395 | func (c *VaultClient) AWSAssumeRole(ctx context.Context, name string, sessionName string, ttl time.Duration) (*AWSCredential, Handle, error) { | ||
396 | h, err := c.writeHandle(ctx, "aws/sts", name, map[string]any{ | ||
397 | "role_session_name": sessionName, | ||
398 | "ttl": ttl.String(), | ||
399 | }) | ||
400 | if err != nil { | ||
401 | return nil, nil, err | ||
402 | } | ||
403 | |||
404 | var d AWSCredential | ||
405 | if err = mapstructure.Decode(h.(*VaultHandle).secret.Data, &d); err != nil { | ||
406 | return nil, nil, fmt.Errorf("AWSIAMUser: error decoding secret: %w", err) | ||
407 | } | ||
408 | |||
409 | return nil, nil, nil | ||
410 | } | ||
411 | |||
412 | func (c *VaultClient) AWSIAMUser(ctx context.Context, name string) (*AWSCredential, Handle, error) { | ||
413 | h, err := c.read(ctx, "aws/creds", name) | ||
414 | if err != nil { | ||
415 | return nil, nil, err | ||
416 | } | ||
417 | |||
418 | var d AWSCredential | ||
419 | if err = mapstructure.Decode(h.(*VaultHandle).secret.Data, &d); err != nil { | ||
420 | return nil, nil, fmt.Errorf("AWSIAMUser: error decoding secret: %w", err) | ||
421 | } | ||
422 | |||
423 | return &d, h, nil | ||
424 | } | ||
425 | |||
361 | func (c *VaultClient) WriteSecret(ctx context.Context, suffix string, in any) error { | 426 | func (c *VaultClient) WriteSecret(ctx context.Context, suffix string, in any) error { |
362 | inb, err := json.Marshal(in) | 427 | inb, err := json.Marshal(in) |
363 | if err != nil { | 428 | if err != nil { |