-
Notifications
You must be signed in to change notification settings - Fork 5
/
secret_creds.go
145 lines (126 loc) · 4.36 KB
/
secret_creds.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
package database
import (
"context"
"fmt"
"time"
"github.com/hashicorp/vault/sdk/database/dbplugin"
"github.com/hashicorp/vault/sdk/framework"
"github.com/hashicorp/vault/sdk/logical"
)
const SecretCredsType = "creds"
func secretCreds(b *databaseBackend) *framework.Secret {
return &framework.Secret{
Type: SecretCredsType,
Fields: map[string]*framework.FieldSchema{},
Renew: b.secretCredsRenew(),
Revoke: b.secretCredsRevoke(),
}
}
func (b *databaseBackend) secretCredsRenew() framework.OperationFunc {
return func(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) {
// Get the username from the internal data
usernameRaw, ok := req.Secret.InternalData["username"]
if !ok {
return nil, fmt.Errorf("secret is missing username internal data")
}
username, ok := usernameRaw.(string)
roleNameRaw, ok := req.Secret.InternalData["role"]
if !ok {
return nil, fmt.Errorf("could not find role with name: %q", req.Secret.InternalData["role"])
}
role, err := b.Role(ctx, req.Storage, roleNameRaw.(string))
if err != nil {
return nil, err
}
if role == nil {
return nil, fmt.Errorf("error during renew: could not find role with name %q", req.Secret.InternalData["role"])
}
// Get the Database object
db, err := b.GetConnection(ctx, req.Storage, role.DBName)
if err != nil {
return nil, err
}
db.RLock()
defer db.RUnlock()
// Make sure we increase the VALID UNTIL endpoint for this user.
ttl, _, err := framework.CalculateTTL(b.System(), req.Secret.Increment, role.DefaultTTL, 0, role.MaxTTL, 0, req.Secret.IssueTime)
if err != nil {
return nil, err
}
if ttl > 0 {
expireTime := time.Now().Add(ttl)
// Adding a small buffer since the TTL will be calculated again after this call
// to ensure the database credential does not expire before the lease
expireTime = expireTime.Add(5 * time.Second)
err := db.RenewUser(ctx, role.Statements, username, expireTime)
if err != nil {
b.CloseIfShutdown(db, err)
return nil, err
}
}
resp := &logical.Response{Secret: req.Secret}
resp.Secret.TTL = role.DefaultTTL
resp.Secret.MaxTTL = role.MaxTTL
return resp, nil
}
}
func (b *databaseBackend) secretCredsRevoke() framework.OperationFunc {
return func(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) {
// Get the username from the internal data
usernameRaw, ok := req.Secret.InternalData["username"]
if !ok {
return nil, fmt.Errorf("secret is missing username internal data")
}
username, ok := usernameRaw.(string)
var resp *logical.Response
roleNameRaw, ok := req.Secret.InternalData["role"]
if !ok {
return nil, fmt.Errorf("no role name was provided")
}
var dbName string
var statements dbplugin.Statements
role, err := b.Role(ctx, req.Storage, roleNameRaw.(string))
if err != nil {
return nil, err
}
if role != nil {
dbName = role.DBName
statements = role.Statements
} else {
if dbNameRaw, ok := req.Secret.InternalData["db_name"]; !ok {
return nil, fmt.Errorf("error during revoke: could not find role with name %q or embedded revocation db name data", req.Secret.InternalData["role"])
} else {
dbName = dbNameRaw.(string)
}
if statementsRaw, ok := req.Secret.InternalData["revocation_statements"]; !ok {
return nil, fmt.Errorf("error during revoke: could not find role with name %q or embedded revocation statement data", req.Secret.InternalData["role"])
} else {
// If we don't actually have any statements, because none were
// set in the role, we'll end up with an empty one and the
// default for the db type will be attempted
if statementsRaw != nil {
statementsSlice, ok := statementsRaw.([]interface{})
if !ok {
return nil, fmt.Errorf("error during revoke: could not find role with name %q and embedded reovcation data could not be read", req.Secret.InternalData["role"])
} else {
for _, v := range statementsSlice {
statements.Revocation = append(statements.Revocation, v.(string))
}
}
}
}
}
// Get our connection
db, err := b.GetConnection(ctx, req.Storage, dbName)
if err != nil {
return nil, err
}
db.RLock()
defer db.RUnlock()
if err := db.RevokeUser(ctx, statements, username); err != nil {
b.CloseIfShutdown(db, err)
return nil, err
}
return resp, nil
}
}