-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathpath_credentials.go
More file actions
184 lines (150 loc) · 5.19 KB
/
Copy pathpath_credentials.go
File metadata and controls
184 lines (150 loc) · 5.19 KB
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
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
package boundarysecrets
import (
"context"
"errors"
"fmt"
"github.com/hashicorp/vault/sdk/framework"
"github.com/hashicorp/vault/sdk/logical"
)
// pathCredentials extends the Vault API with a `/creds`
// endpoint for a role. You can choose whether
// or not certain attributes should be displayed,
// required, and named.
func pathCredentials(b *boundaryBackend) *framework.Path {
return &framework.Path{
Pattern: "creds/" + framework.GenericNameRegex("name"),
Fields: map[string]*framework.FieldSchema{
"name": {
Type: framework.TypeLowerCaseString,
Description: "Name of the role",
Required: true,
},
"worker_name": {
Type: framework.TypeString,
Description: "Name of Boundary Worker",
Required: false,
},
"description": {
Type: framework.TypeString,
Description: "Short description of the worker",
Required: false,
},
},
Callbacks: map[logical.Operation]framework.OperationFunc{
logical.ReadOperation: b.pathCredentialsRead,
logical.UpdateOperation: b.pathCredentialsRead,
},
HelpSynopsis: pathCredentialsHelpSyn,
HelpDescription: pathCredentialsHelpDesc,
}
}
// pathCredentialsRead creates a new HashiCups token each time it is called if a
// role exists.
func (b *boundaryBackend) pathCredentialsRead(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) {
roleName := d.Get("name").(string)
workerName := d.Get("worker_name").(string)
workerDescription := d.Get("description").(string)
if workerDescription == "" {
workerDescription = "Generated by Vault"
}
roleEntry, err := b.getRole(ctx, req.Storage, roleName)
if err != nil {
return nil, fmt.Errorf("error retrieving role: %w", err)
}
if roleEntry == nil {
return nil, errors.New("error retrieving role: role is nil")
}
return b.createUserCreds(ctx, req, roleEntry, workerName, workerDescription)
}
// createUserCreds creates a new HashiCups token to store into the Vault backend, generates
// a response with the secrets information, and checks the TTL and MaxTTL attributes.
func (b *boundaryBackend) createUserCreds(ctx context.Context, req *logical.Request, role *boundaryRoleEntry, workerName string, workerDescription string) (*logical.Response, error) {
var resp *logical.Response
roleTtl := role.TTL
roleMaxTtl := role.MaxTTL
roleType := role.RoleType
switch roleType {
case "user":
account, err := b.createAccount(ctx, req.Storage, role)
if err != nil {
return nil, err
}
// The response is divided into two objects (1) internal data and (2) data.
// If you want to reference any information in your code, you need to
// store it in internal data!
resp = b.Secret(Account).Response(map[string]interface{}{
"account_id": account.AccountId,
"boundary_roles": account.BoundaryRoles,
"user_id": account.UserId,
"auth_method_id": account.AuthMethodId,
"password": account.Password,
"login_name": account.LoginName,
}, map[string]interface{}{
"account_id": account.AccountId,
"user_id": account.UserId,
"ttl": roleTtl,
"max_ttl": roleMaxTtl,
})
case "worker":
worker, err := b.createWorker(ctx, req.Storage, role, workerName, workerDescription)
if err != nil {
return logical.ErrorResponse("unable to create worker, error:", err), nil
//return nil, err
}
resp = b.Secret(Worker).Response(map[string]interface{}{
"worker_id": worker.WorkerId,
"worker_name": worker.WorkerName,
"activation_token": worker.ActivationToken,
}, map[string]interface{}{
"worker_id": worker.WorkerId,
"worker_name": worker.WorkerName,
"ttl": roleTtl,
"max_ttl": roleMaxTtl,
})
}
if role.TTL > 0 {
resp.Secret.TTL = role.TTL
}
if role.MaxTTL > 0 {
resp.Secret.MaxTTL = role.MaxTTL
}
return resp, nil
}
// createAccount uses the Boundary client to create a new account
func (b *boundaryBackend) createAccount(ctx context.Context, s logical.Storage, roleEntry *boundaryRoleEntry) (*boundaryAccount, error) {
client, err := b.getClient(ctx, s)
if err != nil {
return nil, err
}
var token *boundaryAccount
token, err = createAccount(ctx, client, roleEntry.Name, roleEntry.AuthMethodID, roleEntry.BoundaryRoles, roleEntry.ScopeId)
if err != nil {
return nil, fmt.Errorf("error creating Boundary Account: %w", err)
}
if token == nil {
return nil, errors.New("error creating Boundary Account")
}
return token, nil
}
func (b *boundaryBackend) createWorker(ctx context.Context, s logical.Storage, roleEntry *boundaryRoleEntry, workerName string, description string) (*boundaryWorker, error) {
client, err := b.getClient(ctx, s)
if err != nil {
return nil, err
}
var worker *boundaryWorker
worker, err = createWorker(ctx, client, roleEntry.ScopeId, workerName, description)
if err != nil {
return nil, fmt.Errorf("error creating Boundary worker auth token: %w", err)
}
if worker == nil {
return nil, errors.New("error creating Boundary worker auth token")
}
return worker, nil
}
const pathCredentialsHelpSyn = `
Generate a Boundary account or worker from a specific Vault role.
`
const pathCredentialsHelpDesc = `
This path generates a Boundary account
based on a particular role.
`