@@ -9,13 +9,18 @@ import (
9
9
"github.com/hashicorp/vault/logical"
10
10
"github.com/hashicorp/vault/logical/framework"
11
11
"github.com/splunk/vault-plugin-splunk/clients/splunk"
12
+ "strings"
12
13
)
13
14
15
+ const (
16
+ SEARCHHEAD = "search_head"
17
+ INDEXER = "indexer"
18
+ )
14
19
func (b * backend ) pathCredsCreate () * framework.Path {
15
20
return & framework.Path {
16
21
Pattern : "creds/" + framework .GenericNameRegex ("name" ),
17
22
Fields : map [string ]* framework.FieldSchema {
18
- "name" : & framework. FieldSchema {
23
+ "name" : {
19
24
Type : framework .TypeString ,
20
25
Description : "Name of the role" ,
21
26
},
@@ -30,7 +35,30 @@ func (b *backend) pathCredsCreate() *framework.Path {
30
35
}
31
36
}
32
37
33
- func (b * backend ) credsReadHandler (ctx context.Context , req * logical.Request , d * framework.FieldData ) (* logical.Response , error ) {
38
+ func (b * backend ) pathCredsCreateMulti () * framework.Path {
39
+ return & framework.Path {
40
+ Pattern : "creds/" + framework .GenericNameRegex ("name" ) + "/" + framework .GenericNameRegex ("node_fqdn" ),
41
+ Fields : map [string ]* framework.FieldSchema {
42
+ "name" : {
43
+ Type : framework .TypeString ,
44
+ Description : "Name of the role" ,
45
+ },
46
+ "node_fqdn" : {
47
+ Type : framework .TypeString ,
48
+ Description : "FQDN for the Splunk Stack node" ,
49
+ },
50
+ },
51
+
52
+ Callbacks : map [logical.Operation ]framework.OperationFunc {
53
+ logical .ReadOperation : b .credsReadHandler ,
54
+ },
55
+
56
+ HelpSynopsis : pathCredsCreateHelpSyn ,
57
+ HelpDescription : pathCredsCreateHelpDesc ,
58
+ }
59
+ }
60
+
61
+ func (b * backend ) credsReadHandlerStandalone (ctx context.Context , req * logical.Request , d * framework.FieldData ) (* logical.Response , error ) {
34
62
name := d .Get ("name" ).(string )
35
63
role , err := roleConfigLoad (ctx , req .Storage , name )
36
64
if err != nil {
@@ -100,6 +128,123 @@ func (b *backend) credsReadHandler(ctx context.Context, req *logical.Request, d
100
128
return resp , nil
101
129
}
102
130
131
+ func findNode (nodeFQDN string , hosts []splunk.ServerInfoEntry ) (bool , error ) {
132
+ for _ , host := range hosts {
133
+ // check if node_fqdn is in either of HostFQDN or Host. User might not always the FQDN on the cli input
134
+ if strings .Contains (host .Content .HostFQDN , nodeFQDN ) || strings .Contains (host .Content .Host , nodeFQDN ) {
135
+ // Only set found to true if the requested node is a search head
136
+ for _ , role := range host .Content .Roles {
137
+ if role == SEARCHHEAD {
138
+ return true , nil
139
+ } else if role == INDEXER {
140
+ return false , fmt .Errorf ("host: %s is an indexer. Creating ephemeral creds for indexer isn't supported" , nodeFQDN )
141
+ }
142
+ }
143
+ }
144
+ }
145
+ return false , fmt .Errorf ("host: %s not found" , nodeFQDN )
146
+ }
147
+
148
+ func (b * backend ) credsReadHandlerMulti (ctx context.Context , req * logical.Request , d * framework.FieldData ) (* logical.Response , error ) {
149
+ name := d .Get ("name" ).(string )
150
+ node , _ := d .GetOk ("node_fqdn" )
151
+ nodeFQDN := node .(string )
152
+ role , err := roleConfigLoad (ctx , req .Storage , name )
153
+ if err != nil {
154
+ return nil , err
155
+ }
156
+ if role == nil {
157
+ return logical .ErrorResponse (fmt .Sprintf ("role not found: %q" , name )), nil
158
+ }
159
+
160
+ config , err := connectionConfigLoad (ctx , req .Storage , role .Connection )
161
+ if err != nil {
162
+ return nil , err
163
+ }
164
+ // Check if isStandalone is set
165
+ if config .IsStandalone {
166
+ return nil , fmt .Errorf ("expected is_standalone to be set for connection: %q" , role .Connection )
167
+ }
168
+
169
+ // If role name isn't in allowed roles, send back a permission denied.
170
+ if ! strutil .StrListContains (config .AllowedRoles , "*" ) && ! strutil .StrListContainsGlob (config .AllowedRoles , name ) {
171
+ return nil , fmt .Errorf ("%q is not an allowed role for connection %q" , name , role .Connection )
172
+ }
173
+
174
+ conn , err := b .ensureConnection (ctx , role .Connection , config )
175
+ if err != nil {
176
+ return nil , err
177
+ }
178
+
179
+ nodes , _ , err := conn .Deployment .GetSearchPeers ()
180
+ if err != nil {
181
+ b .Logger ().Error ("Error while reading SearchPeers from cluster master" , err )
182
+ return nil , fmt .Errorf ("unable to read searchpeers from cluster master" )
183
+ }
184
+ _ , err = findNode (nodeFQDN , nodes )
185
+ if err != nil {
186
+ return nil , err
187
+ }
188
+
189
+ /*
190
+ // Generate credentials
191
+ userUUID, err := uuid.GenerateUUID()
192
+ if err != nil {
193
+ return nil, err
194
+ }
195
+ userPrefix := role.UserPrefix
196
+ if role.UserPrefix == defaultUserPrefix {
197
+ userPrefix = fmt.Sprintf("%s_%s", role.UserPrefix, req.DisplayName)
198
+ }
199
+ username := fmt.Sprintf("%s_%s", userPrefix, userUUID)
200
+ passwd, err := uuid.GenerateUUID()
201
+ if err != nil {
202
+ return nil, errwrap.Wrapf("error generating new password {{err}}", err)
203
+ }
204
+ opts := splunk.CreateUserOptions{
205
+ Name: username,
206
+ Password: passwd,
207
+ Roles: role.Roles,
208
+ DefaultApp: role.DefaultApp,
209
+ Email: role.Email,
210
+ TZ: role.TZ,
211
+ }
212
+ if _, _, err := conn.AccessControl.Authentication.Users.Create(&opts); err != nil {
213
+ return nil, err
214
+ }
215
+
216
+ resp := b.Secret(secretCredsType).Response(map[string]interface{}{
217
+ // return to user
218
+ "username": username,
219
+ "password": passwd,
220
+ "roles": role.Roles,
221
+ "connection": role.Connection,
222
+ "url": conn.Params().BaseURL,
223
+ }, map[string]interface{}{
224
+ // store (with lease)
225
+ "username": username,
226
+ "role": name,
227
+ "connection": role.Connection,
228
+ })
229
+ resp.Secret.TTL = role.DefaultTTL
230
+ resp.Secret.MaxTTL = role.MaxTTL
231
+
232
+ return resp, nil
233
+ */
234
+ return nil , fmt .Errorf ("XXX" )
235
+ }
236
+ func (b * backend ) credsReadHandler (ctx context.Context , req * logical.Request , d * framework.FieldData ) (* logical.Response , error ) {
237
+ name := d .Get ("name" ).(string )
238
+ node_fqdn , present := d .GetOk ("node_fqdn" )
239
+ // if node_fqdn is specified then the treat the request for a multi-node deployment
240
+ if present {
241
+ b .Logger ().Debug (fmt .Sprintf ("node_fqdn: [%s] specified for role: [%s]. using clustered mode getting temporary creds" , node_fqdn .(string ), name ))
242
+ return b .credsReadHandlerMulti (ctx , req , d )
243
+ }
244
+ b .Logger ().Debug (fmt .Sprintf ("node_fqdn not specified for role: [%s]. using standalone mode getting temporary creds" , name ))
245
+ return b .credsReadHandlerStandalone (ctx , req , d )
246
+ }
247
+
103
248
const pathCredsCreateHelpSyn = `
104
249
Request Splunk credentials for a certain role.
105
250
`
0 commit comments