Skip to content

Commit c5fc885

Browse files
committed
feat: allow the flags to be configurable during runtime
1 parent 0e10834 commit c5fc885

File tree

6 files changed

+174
-7
lines changed

6 files changed

+174
-7
lines changed

README.md

+7-3
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,9 @@ you may or may not be able to access certain paths.
7272
^config?/?$
7373
Lists existing configs
7474
75+
^flags$
76+
Flags for the plugins.
77+
7578
^roles/(?P<role_name>\w(([\w-.]+)?\w)?)$
7679
Create a role with parameters that are used to generate a various access tokens.
7780
@@ -86,9 +89,10 @@ you may or may not be able to access certain paths.
8689
There are some flags we can specify to enable/disable some functionality in the vault plugin.
8790
8891
89-
| Flag | Default value | Description |
90-
|:-----------------:|:-------------:|:---------------------------------------------------------------------------------------|
91-
| show-config-token | false | Display the token value when reading a config on it's endpoint like `/config/default`. |
92+
| Flag | Default value | Description |
93+
|:--------------------------:|:-------------:|:---------------------------------------------------------------------------------------|
94+
| show-config-token | false | Display the token value when reading a config on it's endpoint like `/config/default`. |
95+
| allow-runtime-flags-change | false | Allows you to change the flags at runtime |
9296
9397
## Security Model
9498

backend.go

+5
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ func factory(ctx context.Context, conf *logical.BackendConfig, flags Flags) (log
6262

6363
Paths: framework.PathAppend(
6464
[]*framework.Path{
65+
pathFlags(b),
6566
pathConfig(b),
6667
pathListConfig(b),
6768
pathConfigTokenRotate(b),
@@ -90,6 +91,10 @@ type Backend struct {
9091
// would invalidate the gitlab client, so it will need to be reinitialized
9192
lockClientMutex sync.RWMutex
9293

94+
// Mutex to protect flags change, this is required as it could require reinitialization of some components
95+
// of the plugin
96+
lockFlagsMutex sync.RWMutex
97+
9398
// roleLocks to protect access for roles, during modifications, deletion
9499
roleLocks []*locksutil.LockEntry
95100
}

flags.go

+7-3
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,17 @@
11
package gitlab
22

3-
import "flag"
3+
import (
4+
"flag"
5+
)
46

57
type Flags struct {
6-
ShowConfigToken bool
8+
ShowConfigToken bool `json:"show_config_token" mapstructure:"show_config_token"`
9+
AllowRuntimeFlagsChange bool `json:"allow_runtime_flags_change" mapstructure:"allow_runtime_flags_change"`
710
}
811

912
// FlagSet returns the flag set for configuring the TLS connection
1013
func (f *Flags) FlagSet(fs *flag.FlagSet) *flag.FlagSet {
11-
fs.BoolVar(&f.ShowConfigToken, "show-config-token", false, "")
14+
fs.BoolVar(&f.ShowConfigToken, "show-config-token", false, "Display the token value when reading it's config the configuration endpoint.")
15+
fs.BoolVar(&f.AllowRuntimeFlagsChange, "allow-runtime-flags-change", false, "Allows you to change the flags dynamically at runtime.")
1216
return fs
1317
}

flags_test.go

+3-1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ func TestFlags_FlagSet(t *testing.T) {
1616
flags.FlagSet(fs)
1717

1818
assert.False(t, flags.ShowConfigToken)
19-
assert.NoError(t, fs.Parse([]string{"-show-config-token"}))
19+
assert.False(t, flags.AllowRuntimeFlagsChange)
20+
assert.NoError(t, fs.Parse([]string{"-show-config-token", "-allow-runtime-flags-change"}))
2021
assert.True(t, flags.ShowConfigToken)
22+
assert.True(t, flags.AllowRuntimeFlagsChange)
2123
}

path_flags.go

+106
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
package gitlab
2+
3+
import (
4+
"context"
5+
"net/http"
6+
"strconv"
7+
"strings"
8+
9+
"github.com/hashicorp/vault/sdk/framework"
10+
"github.com/hashicorp/vault/sdk/logical"
11+
"github.com/mitchellh/mapstructure"
12+
)
13+
14+
const (
15+
PathConfigFlags = "flags"
16+
)
17+
18+
var FieldSchemaFlags = map[string]*framework.FieldSchema{
19+
"show_config_token": {
20+
Type: framework.TypeBool,
21+
Description: "Should we display the token value for the roles?",
22+
Default: false,
23+
DisplayAttrs: &framework.DisplayAttributes{Name: "Show Config Token"},
24+
},
25+
}
26+
27+
func (b *Backend) pathFlagsRead(ctx context.Context, req *logical.Request, data *framework.FieldData) (lResp *logical.Response, err error) {
28+
b.lockFlagsMutex.RLock()
29+
defer b.lockFlagsMutex.RUnlock()
30+
var flagData map[string]any
31+
err = mapstructure.Decode(b.flags, &flagData)
32+
return &logical.Response{Data: flagData}, err
33+
}
34+
35+
func (b *Backend) pathFlagsUpdate(ctx context.Context, req *logical.Request, data *framework.FieldData) (lResp *logical.Response, err error) {
36+
b.lockFlagsMutex.Lock()
37+
defer b.lockFlagsMutex.Unlock()
38+
39+
var eventData = make(map[string]string)
40+
41+
if showConfigToken, ok := data.GetOk("show_config_token"); ok {
42+
b.flags.ShowConfigToken = showConfigToken.(bool)
43+
eventData["show_config_token"] = strconv.FormatBool(b.flags.ShowConfigToken)
44+
}
45+
46+
event(ctx, b.Backend, "flags-write", eventData)
47+
48+
var flagData map[string]any
49+
err = mapstructure.Decode(b.flags, &flagData)
50+
return &logical.Response{Data: flagData}, err
51+
}
52+
53+
func pathFlags(b *Backend) *framework.Path {
54+
var operations = map[logical.Operation]framework.OperationHandler{
55+
logical.ReadOperation: &framework.PathOperation{
56+
Callback: b.pathFlagsRead,
57+
DisplayAttrs: &framework.DisplayAttributes{
58+
OperationVerb: "read",
59+
OperationSuffix: "flags",
60+
},
61+
Summary: "Read the flags for the plugin.",
62+
Responses: map[int][]framework.Response{
63+
http.StatusOK: {{
64+
Description: http.StatusText(http.StatusOK),
65+
Fields: FieldSchemaFlags,
66+
}},
67+
},
68+
},
69+
}
70+
71+
if b.flags.AllowRuntimeFlagsChange {
72+
operations[logical.UpdateOperation] = &framework.PathOperation{
73+
Callback: b.pathFlagsUpdate,
74+
DisplayAttrs: &framework.DisplayAttributes{
75+
OperationVerb: "update",
76+
OperationSuffix: "flags",
77+
},
78+
Summary: "Update the flags for the plugin.",
79+
Responses: map[int][]framework.Response{
80+
http.StatusOK: {{
81+
Description: http.StatusText(http.StatusOK),
82+
Fields: FieldSchemaFlags,
83+
}},
84+
http.StatusBadRequest: {{
85+
Description: http.StatusText(http.StatusBadRequest),
86+
Fields: FieldSchemaFlags,
87+
}},
88+
},
89+
}
90+
}
91+
92+
return &framework.Path{
93+
HelpSynopsis: strings.TrimSpace(pathFlagsHelpSynopsis),
94+
HelpDescription: strings.TrimSpace(pathFlagsHelpDescription),
95+
Pattern: PathConfigFlags,
96+
Fields: FieldSchemaFlags,
97+
DisplayAttrs: &framework.DisplayAttributes{
98+
OperationPrefix: operationPrefixGitlabAccessTokens,
99+
},
100+
Operations: operations,
101+
}
102+
}
103+
104+
const pathFlagsHelpSynopsis = `Flags for the plugin.`
105+
106+
const pathFlagsHelpDescription = ``

path_flags_test.go

+46
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
//go:build unit
2+
3+
package gitlab_test
4+
5+
import (
6+
"context"
7+
"testing"
8+
9+
"github.com/hashicorp/vault/sdk/logical"
10+
"github.com/stretchr/testify/require"
11+
12+
gitlab "github.com/ilijamt/vault-plugin-secrets-gitlab"
13+
)
14+
15+
func TestPathFlags(t *testing.T) {
16+
var ctx = context.Background()
17+
b, l, events, err := getBackendWithFlagsWithEvents(ctx, gitlab.Flags{AllowRuntimeFlagsChange: true})
18+
require.NoError(t, err)
19+
20+
resp, err := b.HandleRequest(ctx, &logical.Request{
21+
Operation: logical.ReadOperation,
22+
Path: gitlab.PathConfigFlags, Storage: l,
23+
})
24+
25+
require.NoError(t, err)
26+
require.NotNil(t, resp)
27+
require.NoError(t, resp.Error())
28+
require.False(t, resp.Data["show_config_token"].(bool))
29+
30+
resp, err = b.HandleRequest(ctx, &logical.Request{
31+
Operation: logical.UpdateOperation,
32+
Path: gitlab.PathConfigFlags, Storage: l,
33+
Data: map[string]interface{}{
34+
"show_config_token": "true",
35+
},
36+
})
37+
38+
require.NoError(t, err)
39+
require.NotNil(t, resp)
40+
require.NoError(t, resp.Error())
41+
require.True(t, resp.Data["show_config_token"].(bool))
42+
43+
events.expectEvents(t, []expectedEvent{
44+
{eventType: "gitlab/flags-write"},
45+
})
46+
}

0 commit comments

Comments
 (0)