Skip to content

Commit 2575e30

Browse files
committed
Support reading secrets from a separate config file
Users can specify a new overlay config file. This file can contain secrets. The file is specified in two ways: - VOUCH_SECRETS_FILE env var: path of the overlay config file - CREDENTIALS_DIRECTORY env var that contains a file called VOUCH_SECRETS_FILE. This can be used with systemd LoadCredential.
1 parent 2d3ea12 commit 2575e30

File tree

4 files changed

+79
-3
lines changed

4 files changed

+79
-3
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
Coming soon! Please document any work in progress here as part of your PR. It will be moved to the next tag when released.
66

7+
- [Support reading secrets from a separate file](https://github.com/vouch/vouch-proxy/pull/487)
8+
79
## v0.37.0
810

911
- [allow configurable Write, Read and Idle timeouts for the http server](https://github.com/vouch/vouch-proxy/pull/468)

config/testing/secret_overlay.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
oauth:
2+
client_secret: my client secret from overlay

pkg/cfg/cfg.go

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,7 @@ func configureFromEnv() bool {
229229
if err != nil {
230230
log.Fatal(err.Error())
231231
}
232+
232233
// did anything change?
233234
if !reflect.DeepEqual(preEnvConfig, *Cfg) ||
234235
!reflect.DeepEqual(preEnvGenOAuth, *GenOAuth) {
@@ -270,8 +271,31 @@ func setRootDir() {
270271

271272
// parseConfig parse the config file
272273
func parseConfigFile() error {
273-
configEnv := os.Getenv(Branding.UCName + "_CONFIG")
274+
secretsFileVar := Branding.UCName + "_SECRETS_FILE"
275+
overlayConfigPath := os.Getenv(secretsFileVar)
276+
if overlayConfigPath == "" {
277+
// see if systemd LoadCredential was used to pass in the overlay config
278+
if credDir := os.Getenv("CREDENTIALS_DIRECTORY"); credDir != "" {
279+
overlayConfigPath = filepath.Join(credDir, secretsFileVar)
280+
if _, err := os.Stat(overlayConfigPath); os.IsNotExist(err) {
281+
log.Warnf("%s not found in CREDENTIALS_DIRECTORY %s", secretsFileVar, credDir)
282+
overlayConfigPath = ""
283+
} else {
284+
log.Infof("reading secrets file from CREDENTIALS_DIRECTORY: %s", overlayConfigPath)
285+
}
286+
}
287+
} else {
288+
log.Infof("reading secrets file from %s env var: %s", secretsFileVar, overlayConfigPath)
289+
}
290+
if overlayConfigPath != "" {
291+
viper.SetConfigFile(overlayConfigPath)
292+
if err := viper.ReadInConfig(); err != nil {
293+
return err
294+
}
295+
viper.SetConfigFile("")
296+
}
274297

298+
configEnv := os.Getenv(Branding.UCName + "_CONFIG")
275299
if configEnv != "" {
276300
log.Warnf("config file loaded from environmental variable %s: %s", Branding.UCName+"_CONFIG", configEnv)
277301
configFile, _ := filepath.Abs(configEnv)
@@ -287,8 +311,8 @@ func parseConfigFile() error {
287311
viper.SetConfigType("yaml")
288312
viper.AddConfigPath(filepath.Join(RootDir, "config"))
289313
}
290-
err := viper.ReadInConfig() // Find and read the config file
291-
if err != nil { // Handle errors reading the config file
314+
err := viper.MergeInConfig() // Find and read the config file
315+
if err != nil { // Handle errors reading the config file
292316

293317
return fmt.Errorf("%w: %s", errConfigNotFound, err)
294318
}

pkg/cfg/oauth_test.go

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,10 @@ OR CONDITIONS OF ANY KIND, either express or implied.
1111
package cfg
1212

1313
import (
14+
"io/ioutil"
1415
"net/url"
16+
"os"
17+
"path/filepath"
1518
"testing"
1619

1720
"github.com/stretchr/testify/assert"
@@ -43,3 +46,48 @@ func Test_configureOAuthWithClaims(t *testing.T) {
4346
assert.Nil(t, err)
4447
assert.Equal(t, authCodeURL.Query().Get("claims"), `{"userinfo":{"email":{"essential":true},"email_verified":{"essential":true},"given_name":{"essential":true},"http://example.info/claims/groups":null,"nickname":null,"picture":null},"id_token":{"acr":{"values":["urn:mace:incommon:iap:silver"]},"auth_time":{"essential":true}}}`)
4548
}
49+
50+
func Test_readOverlayConfig_fileVar(t *testing.T) {
51+
defer cleanupEnv()
52+
rootDir := os.Getenv(Branding.UCName + "_ROOT")
53+
assert.NotEmpty(t, rootDir)
54+
assert.NoError(t, os.Setenv(Branding.UCName+"_SECRETS_FILE", filepath.Join(rootDir, "config/testing/secret_overlay.yml")))
55+
setUp("config/testing/handler_login_url.yml")
56+
assert.Equal(t, "my client secret from overlay", OAuthClient.ClientSecret)
57+
}
58+
59+
func Test_readOverlayConfig_credentialsDir(t *testing.T) {
60+
defer cleanupEnv()
61+
rootDir := os.Getenv(Branding.UCName + "_ROOT")
62+
assert.NotEmpty(t, rootDir)
63+
tempDir, err := ioutil.TempDir("", "")
64+
assert.NoError(t, err)
65+
defer func() {
66+
_ = os.RemoveAll(tempDir)
67+
}()
68+
destFileName := Branding.UCName + "_SECRETS_FILE"
69+
srcFileName := filepath.Join(rootDir, "config/testing/secret_overlay.yml")
70+
assert.NoError(t, os.Symlink(srcFileName, filepath.Join(tempDir, destFileName)))
71+
assert.NoError(t, os.Setenv("CREDENTIALS_DIRECTORY", tempDir))
72+
setUp("config/testing/handler_login_url.yml")
73+
assert.Equal(t, "my client secret from overlay", OAuthClient.ClientSecret)
74+
}
75+
76+
func Test_readOverlayConfig_emptyCredentialsDir(t *testing.T) {
77+
defer cleanupEnv()
78+
tempDir, err := ioutil.TempDir("", "")
79+
assert.NoError(t, err)
80+
defer func() {
81+
_ = os.RemoveAll(tempDir)
82+
}()
83+
assert.NoError(t, os.Setenv("CREDENTIALS_DIRECTORY", tempDir))
84+
setUp("config/testing/handler_login_url.yml")
85+
assert.Equal(t, "", OAuthClient.ClientSecret)
86+
}
87+
88+
func Test_readOverlayConfig_missingCredentialsDir(t *testing.T) {
89+
defer cleanupEnv()
90+
assert.NoError(t, os.Setenv("CREDENTIALS_DIRECTORY", "/this/doesnt/exist"))
91+
setUp("config/testing/handler_login_url.yml")
92+
assert.Equal(t, "", OAuthClient.ClientSecret)
93+
}

0 commit comments

Comments
 (0)