Skip to content

Commit 3de251f

Browse files
authored
Add ReadSettings to get config settings from context (#118)
1 parent 68cd8f7 commit 3de251f

File tree

5 files changed

+370
-66
lines changed

5 files changed

+370
-66
lines changed

pkg/awsds/authSettings.go

Lines changed: 197 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,197 @@
1+
package awsds
2+
3+
import (
4+
"context"
5+
"os"
6+
"strconv"
7+
"strings"
8+
9+
"github.com/aws/aws-sdk-go/aws/credentials/stscreds"
10+
"github.com/grafana/grafana-plugin-sdk-go/backend"
11+
"github.com/grafana/grafana-plugin-sdk-go/backend/gtime"
12+
"github.com/grafana/grafana-plugin-sdk-go/backend/proxy"
13+
)
14+
15+
const (
16+
// AllowedAuthProvidersEnvVarKeyName is the string literal for the aws allowed auth providers environment variable key name
17+
AllowedAuthProvidersEnvVarKeyName = "AWS_AUTH_AllowedAuthProviders"
18+
19+
// AssumeRoleEnabledEnvVarKeyName is the string literal for the aws assume role enabled environment variable key name
20+
AssumeRoleEnabledEnvVarKeyName = "AWS_AUTH_AssumeRoleEnabled"
21+
22+
// SessionDurationEnvVarKeyName is the string literal for the session duration variable key name
23+
SessionDurationEnvVarKeyName = "AWS_AUTH_SESSION_DURATION"
24+
25+
// GrafanaAssumeRoleExternalIdKeyName is the string literal for the grafana assume role external id environment variable key name
26+
GrafanaAssumeRoleExternalIdKeyName = "AWS_AUTH_EXTERNAL_ID"
27+
28+
// GrafanaListMetricsPageLimit is the string literal for the cloudwatch list metrics page limit key name
29+
GrafanaListMetricsPageLimit = "AWS_CW_LIST_METRICS_PAGE_LIMIT"
30+
31+
defaultAssumeRoleEnabled = true
32+
defaultListMetricsPageLimit = 500
33+
defaultSecureSocksDSProxyEnabled = false
34+
)
35+
36+
// ReadAuthSettings gets the Grafana auth settings from the context if its available, the environment variables if not
37+
func ReadAuthSettings(ctx context.Context) *AuthSettings {
38+
settings, exists := ReadAuthSettingsFromContext(ctx)
39+
if !exists {
40+
settings = ReadAuthSettingsFromEnvironmentVariables()
41+
}
42+
return settings
43+
}
44+
45+
func defaultAuthSettings() *AuthSettings {
46+
return &AuthSettings{
47+
AllowedAuthProviders: []string{"default", "keys", "credentials"},
48+
AssumeRoleEnabled: defaultAssumeRoleEnabled,
49+
SessionDuration: &stscreds.DefaultDuration,
50+
ListMetricsPageLimit: defaultListMetricsPageLimit,
51+
SecureSocksDSProxyEnabled: defaultSecureSocksDSProxyEnabled,
52+
}
53+
}
54+
55+
// ReadAuthSettingsFromContext tries to get the auth settings from the GrafanaConfig in ctx, and returns true if it finds a config
56+
func ReadAuthSettingsFromContext(ctx context.Context) (*AuthSettings, bool) {
57+
cfg := backend.GrafanaConfigFromContext(ctx)
58+
// initialize settings with the default values set
59+
settings := defaultAuthSettings()
60+
if cfg == nil {
61+
return settings, false
62+
}
63+
hasSettings := false
64+
65+
if providers := cfg.Get(AllowedAuthProvidersEnvVarKeyName); providers != "" {
66+
allowedAuthProviders := []string{}
67+
for _, authProvider := range strings.Split(providers, ",") {
68+
authProvider = strings.TrimSpace(authProvider)
69+
if authProvider != "" {
70+
allowedAuthProviders = append(allowedAuthProviders, authProvider)
71+
}
72+
}
73+
if len(allowedAuthProviders) != 0 {
74+
settings.AllowedAuthProviders = allowedAuthProviders
75+
}
76+
hasSettings = true
77+
}
78+
79+
if v := cfg.Get(AssumeRoleEnabledEnvVarKeyName); v != "" {
80+
assumeRoleEnabled, err := strconv.ParseBool(v)
81+
if err == nil {
82+
settings.AssumeRoleEnabled = assumeRoleEnabled
83+
} else {
84+
backend.Logger.Error("could not parse context variable", "var", AllowedAuthProvidersEnvVarKeyName)
85+
}
86+
hasSettings = true
87+
}
88+
89+
if v := cfg.Get(GrafanaAssumeRoleExternalIdKeyName); v != "" {
90+
settings.ExternalID = v
91+
hasSettings = true
92+
}
93+
94+
if v := cfg.Get(GrafanaListMetricsPageLimit); v != "" {
95+
listMetricsPageLimit, err := strconv.Atoi(v)
96+
if err == nil {
97+
settings.ListMetricsPageLimit = listMetricsPageLimit
98+
} else {
99+
backend.Logger.Error("could not parse context variable", "var", GrafanaListMetricsPageLimit)
100+
}
101+
hasSettings = true
102+
}
103+
104+
if v := cfg.Get(proxy.PluginSecureSocksProxyEnabled); v != "" {
105+
secureSocksDSProxyEnabled, err := strconv.ParseBool(v)
106+
if err == nil {
107+
settings.SecureSocksDSProxyEnabled = secureSocksDSProxyEnabled
108+
} else {
109+
backend.Logger.Error("could not parse context variable", "var", proxy.PluginSecureSocksProxyEnabled)
110+
}
111+
hasSettings = true
112+
}
113+
114+
// Users set session duration directly as an environment variable
115+
sessionDurationString := os.Getenv(SessionDurationEnvVarKeyName)
116+
if sessionDurationString != "" {
117+
sessionDuration, err := gtime.ParseDuration(sessionDurationString)
118+
if err == nil {
119+
settings.SessionDuration = &sessionDuration
120+
} else {
121+
backend.Logger.Error("could not parse env variable", "var", SessionDurationEnvVarKeyName)
122+
}
123+
}
124+
125+
return settings, hasSettings
126+
}
127+
128+
// ReadAuthSettingsFromEnvironmentVariables gets the Grafana auth settings from the environment variables
129+
// Deprecated: Use ReadAuthSettingsFromContext instead
130+
func ReadAuthSettingsFromEnvironmentVariables() *AuthSettings {
131+
authSettings := &AuthSettings{}
132+
allowedAuthProviders := []string{}
133+
providers := os.Getenv(AllowedAuthProvidersEnvVarKeyName)
134+
for _, authProvider := range strings.Split(providers, ",") {
135+
authProvider = strings.TrimSpace(authProvider)
136+
if authProvider != "" {
137+
allowedAuthProviders = append(allowedAuthProviders, authProvider)
138+
}
139+
}
140+
141+
if len(allowedAuthProviders) == 0 {
142+
allowedAuthProviders = []string{"default", "keys", "credentials"}
143+
backend.Logger.Warn("could not find allowed auth providers. falling back to 'default, keys, credentials'")
144+
}
145+
authSettings.AllowedAuthProviders = allowedAuthProviders
146+
147+
assumeRoleEnabledString := os.Getenv(AssumeRoleEnabledEnvVarKeyName)
148+
if len(assumeRoleEnabledString) == 0 {
149+
backend.Logger.Warn("environment variable missing. falling back to enable assume role", "var", AssumeRoleEnabledEnvVarKeyName)
150+
assumeRoleEnabledString = "true"
151+
}
152+
153+
var err error
154+
authSettings.AssumeRoleEnabled, err = strconv.ParseBool(assumeRoleEnabledString)
155+
if err != nil {
156+
backend.Logger.Error("could not parse env variable", "var", AssumeRoleEnabledEnvVarKeyName)
157+
authSettings.AssumeRoleEnabled = defaultAssumeRoleEnabled
158+
}
159+
160+
authSettings.ExternalID = os.Getenv(GrafanaAssumeRoleExternalIdKeyName)
161+
162+
listMetricsPageLimitString := os.Getenv(GrafanaListMetricsPageLimit)
163+
if len(listMetricsPageLimitString) == 0 {
164+
backend.Logger.Warn("environment variable missing. falling back to default page limit", "var", GrafanaListMetricsPageLimit)
165+
listMetricsPageLimitString = "500"
166+
}
167+
168+
authSettings.ListMetricsPageLimit, err = strconv.Atoi(listMetricsPageLimitString)
169+
if err != nil {
170+
backend.Logger.Error("could not parse env variable", "var", GrafanaListMetricsPageLimit)
171+
authSettings.ListMetricsPageLimit = defaultListMetricsPageLimit
172+
}
173+
174+
sessionDurationString := os.Getenv(SessionDurationEnvVarKeyName)
175+
if sessionDurationString != "" {
176+
sessionDuration, err := gtime.ParseDuration(sessionDurationString)
177+
if err != nil {
178+
backend.Logger.Error("could not parse env variable", "var", SessionDurationEnvVarKeyName)
179+
} else {
180+
authSettings.SessionDuration = &sessionDuration
181+
}
182+
}
183+
184+
proxyEnabledString := os.Getenv(proxy.PluginSecureSocksProxyEnabled)
185+
if len(proxyEnabledString) == 0 {
186+
backend.Logger.Warn("environment variable missing. falling back to enable assume role", "var", AssumeRoleEnabledEnvVarKeyName)
187+
proxyEnabledString = "false"
188+
}
189+
190+
authSettings.SecureSocksDSProxyEnabled, err = strconv.ParseBool(proxyEnabledString)
191+
if err != nil {
192+
backend.Logger.Error("could not parse env variable", "var", proxy.PluginSecureSocksProxyEnabled)
193+
authSettings.SecureSocksDSProxyEnabled = defaultSecureSocksDSProxyEnabled
194+
}
195+
196+
return authSettings
197+
}

pkg/awsds/authSettings_test.go

Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
package awsds
2+
3+
import (
4+
"context"
5+
"os"
6+
"testing"
7+
"time"
8+
9+
"github.com/aws/aws-sdk-go/aws/credentials/stscreds"
10+
"github.com/grafana/grafana-plugin-sdk-go/backend"
11+
"github.com/grafana/grafana-plugin-sdk-go/backend/proxy"
12+
"github.com/stretchr/testify/require"
13+
)
14+
15+
func TestReadAuthSettingsFromContext(t *testing.T) {
16+
tcs := []struct {
17+
name string
18+
cfg *backend.GrafanaCfg
19+
expectedSettings *AuthSettings
20+
expectedHasSettings bool
21+
}{
22+
{
23+
name: "nil config",
24+
cfg: nil,
25+
expectedSettings: defaultAuthSettings(),
26+
expectedHasSettings: false,
27+
},
28+
{
29+
name: "empty config",
30+
cfg: &backend.GrafanaCfg{},
31+
expectedSettings: defaultAuthSettings(),
32+
expectedHasSettings: false,
33+
},
34+
{
35+
name: "nil config map",
36+
cfg: backend.NewGrafanaCfg(nil),
37+
expectedSettings: defaultAuthSettings(),
38+
expectedHasSettings: false,
39+
},
40+
{
41+
name: "empty config map",
42+
cfg: backend.NewGrafanaCfg(make(map[string]string)),
43+
expectedSettings: defaultAuthSettings(),
44+
expectedHasSettings: false,
45+
},
46+
{
47+
name: "aws settings in config",
48+
cfg: backend.NewGrafanaCfg(map[string]string{
49+
AllowedAuthProvidersEnvVarKeyName: "foo , bar,baz",
50+
AssumeRoleEnabledEnvVarKeyName: "false",
51+
GrafanaAssumeRoleExternalIdKeyName: "mock_id",
52+
GrafanaListMetricsPageLimit: "50",
53+
proxy.PluginSecureSocksProxyEnabled: "true",
54+
}),
55+
expectedSettings: &AuthSettings{
56+
AllowedAuthProviders: []string{"foo", "bar", "baz"},
57+
AssumeRoleEnabled: false,
58+
ExternalID: "mock_id",
59+
ListMetricsPageLimit: 50,
60+
SessionDuration: &stscreds.DefaultDuration,
61+
SecureSocksDSProxyEnabled: true,
62+
},
63+
expectedHasSettings: true,
64+
},
65+
}
66+
for _, tc := range tcs {
67+
t.Run(tc.name, func(t *testing.T) {
68+
ctx := backend.WithGrafanaConfig(context.Background(), tc.cfg)
69+
settings, hasSettings := ReadAuthSettingsFromContext(ctx)
70+
71+
require.Equal(t, tc.expectedHasSettings, hasSettings)
72+
require.Equal(t, tc.expectedSettings, settings)
73+
})
74+
}
75+
}
76+
77+
func TestReadAuthSettings(t *testing.T) {
78+
originalExternalId := os.Getenv(GrafanaAssumeRoleExternalIdKeyName)
79+
os.Setenv(GrafanaAssumeRoleExternalIdKeyName, "env_id")
80+
defer func() {
81+
os.Setenv(GrafanaAssumeRoleExternalIdKeyName, originalExternalId)
82+
}()
83+
84+
expectedDuration, err := time.ParseDuration("20m")
85+
require.NoError(t, err)
86+
expectedSessionContextSettings := &AuthSettings{
87+
AllowedAuthProviders: []string{"foo", "bar", "baz"},
88+
AssumeRoleEnabled: false,
89+
SessionDuration: &expectedDuration, //20 minutes in nanoseconds count,
90+
ExternalID: "mock_id",
91+
ListMetricsPageLimit: 50,
92+
SecureSocksDSProxyEnabled: true,
93+
}
94+
95+
expectedSessionEnvSettings := &AuthSettings{
96+
AllowedAuthProviders: []string{"env1", "env2"},
97+
AssumeRoleEnabled: true,
98+
SessionDuration: &expectedDuration,
99+
ExternalID: "env_id",
100+
ListMetricsPageLimit: 30,
101+
SecureSocksDSProxyEnabled: false,
102+
}
103+
104+
require.NoError(t, os.Setenv(AllowedAuthProvidersEnvVarKeyName, "env1,env2"))
105+
require.NoError(t, os.Setenv(AssumeRoleEnabledEnvVarKeyName, "true"))
106+
require.NoError(t, os.Setenv(GrafanaListMetricsPageLimit, "30"))
107+
require.NoError(t, os.Setenv(SessionDurationEnvVarKeyName, "20m"))
108+
require.NoError(t, os.Setenv(proxy.PluginSecureSocksProxyEnabled, "false"))
109+
defer unsetEnvironmentVariables()
110+
111+
tcs := []struct {
112+
name string
113+
cfg *backend.GrafanaCfg
114+
expectedSettings *AuthSettings
115+
}{
116+
{
117+
name: "read from env if config is nil",
118+
cfg: nil,
119+
expectedSettings: expectedSessionEnvSettings,
120+
},
121+
{
122+
name: "read from env if config is empty",
123+
cfg: &backend.GrafanaCfg{},
124+
expectedSettings: expectedSessionEnvSettings,
125+
},
126+
{
127+
name: "read from env if config map is nil",
128+
cfg: backend.NewGrafanaCfg(nil),
129+
expectedSettings: expectedSessionEnvSettings,
130+
},
131+
{
132+
name: "read from env if config map is empty",
133+
cfg: backend.NewGrafanaCfg(make(map[string]string)),
134+
expectedSettings: expectedSessionEnvSettings,
135+
},
136+
{
137+
name: "read from context",
138+
cfg: backend.NewGrafanaCfg(map[string]string{
139+
AllowedAuthProvidersEnvVarKeyName: "foo , bar,baz",
140+
AssumeRoleEnabledEnvVarKeyName: "false",
141+
GrafanaAssumeRoleExternalIdKeyName: "mock_id",
142+
GrafanaListMetricsPageLimit: "50",
143+
proxy.PluginSecureSocksProxyEnabled: "true",
144+
}),
145+
expectedSettings: expectedSessionContextSettings,
146+
},
147+
}
148+
149+
for _, tc := range tcs {
150+
t.Run(tc.name, func(t *testing.T) {
151+
ctx := backend.WithGrafanaConfig(context.Background(), tc.cfg)
152+
settings := ReadAuthSettings(ctx)
153+
154+
require.Equal(t, tc.expectedSettings, settings)
155+
})
156+
}
157+
}

0 commit comments

Comments
 (0)