forked from hashicorp/vault
-
Notifications
You must be signed in to change notification settings - Fork 0
/
path_role_create.go
132 lines (116 loc) · 3.03 KB
/
path_role_create.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
package postgresql
import (
"fmt"
"time"
"github.com/hashicorp/go-uuid"
"github.com/hashicorp/vault/logical"
"github.com/hashicorp/vault/logical/framework"
_ "github.com/lib/pq"
)
func pathRoleCreate(b *backend) *framework.Path {
return &framework.Path{
Pattern: "creds/" + framework.GenericNameRegex("name"),
Fields: map[string]*framework.FieldSchema{
"name": &framework.FieldSchema{
Type: framework.TypeString,
Description: "Name of the role.",
},
},
Callbacks: map[logical.Operation]framework.OperationFunc{
logical.ReadOperation: b.pathRoleCreateRead,
},
HelpSynopsis: pathRoleCreateReadHelpSyn,
HelpDescription: pathRoleCreateReadHelpDesc,
}
}
func (b *backend) pathRoleCreateRead(
req *logical.Request, data *framework.FieldData) (*logical.Response, error) {
name := data.Get("name").(string)
// Get the role
role, err := b.Role(req.Storage, name)
if err != nil {
return nil, err
}
if role == nil {
return logical.ErrorResponse(fmt.Sprintf("unknown role: %s", name)), nil
}
// Determine if we have a lease
lease, err := b.Lease(req.Storage)
if err != nil {
return nil, err
}
// Unlike some other backends we need a lease here (can't leave as 0 and
// let core fill it in) because Postgres also expires users as a safety
// measure, so cannot be zero
if lease == nil {
lease = &configLease{
Lease: b.System().DefaultLeaseTTL(),
}
}
// Generate the username, password and expiration. PG limits user to 63 characters
displayName := req.DisplayName
if len(displayName) > 26 {
displayName = displayName[:26]
}
userUUID, err := uuid.GenerateUUID()
if err != nil {
return nil, err
}
username := fmt.Sprintf("%s-%s", displayName, userUUID)
if len(username) > 63 {
username = username[:63]
}
password, err := uuid.GenerateUUID()
if err != nil {
return nil, err
}
expiration := time.Now().UTC().
Add(lease.Lease).
Format("2006-01-02 15:04:05-0700")
// Get our connection
db, err := b.DB(req.Storage)
if err != nil {
return nil, err
}
// Start a transaction
tx, err := db.Begin()
if err != nil {
return nil, err
}
defer tx.Rollback()
// Execute each query
for _, query := range SplitSQL(role.SQL) {
stmt, err := db.Prepare(Query(query, map[string]string{
"name": username,
"password": password,
"expiration": expiration,
}))
if err != nil {
return nil, err
}
if _, err := stmt.Exec(); err != nil {
return nil, err
}
}
// Commit the transaction
if err := tx.Commit(); err != nil {
return nil, err
}
// Return the secret
resp := b.Secret(SecretCredsType).Response(map[string]interface{}{
"username": username,
"password": password,
}, map[string]interface{}{
"username": username,
})
resp.Secret.TTL = lease.Lease
return resp, nil
}
const pathRoleCreateReadHelpSyn = `
Request database credentials for a certain role.
`
const pathRoleCreateReadHelpDesc = `
This path reads database credentials for a certain role. The
database credentials will be generated on demand and will be automatically
revoked when the lease is up.
`