Skip to content

Commit

Permalink
fix: override secrets from path (#204)
Browse files Browse the repository at this point in the history
  • Loading branch information
csatib02 authored Sep 17, 2024
1 parent 8710e33 commit 608681f
Show file tree
Hide file tree
Showing 10 changed files with 86 additions and 21 deletions.
5 changes: 3 additions & 2 deletions e2e/bao-provider.bats
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ assert_output_contains() {

run_output=$(./secret-init env | grep 'API_KEY\|RABBITMQ_USERNAME\|RABBITMQ_PASSWORD')
assert_success

# Get the lease ID after renewing the secret
secret_info_after=$(docker exec "$bao_container_name" bao read -format=json database/creds/my-role)
lease_id_after=$(echo "$secret_info_after" | jq -r '.lease_id')
Expand All @@ -173,12 +173,13 @@ assert_output_contains() {
}

@test "secrets successfully loaded from bao using BAO_FROM_PATH" {
setup_bao_provider

# unset env vars to ensure secret-init will utilize BAO_FROM_PATH
unset API_KEY
unset RABBITMQ_USERNAME
unset RABBITMQ_PASSWORD

setup_bao_provider
set_bao_token 227e1cce-6bf7-30bb-2d2a-acc854318caf
add_secrets_to_bao
export BAO_FROM_PATH="secret/data/test/api,secret/data/test/rabbitmq"
Expand Down
5 changes: 3 additions & 2 deletions e2e/vault-provider.bats
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ assert_output_contains() {

run_output=$(./secret-init env | grep 'MYSQL_PASSWORD\|AWS_SECRET_ACCESS_KEY\|AWS_ACCESS_KEY_ID')
assert_success

# Get the lease duration after renewal
secret_info_after=$(docker exec "$vault_container_name" vault read -format=json database/creds/my-role)
lease_id_after=$(echo "$secret_info_after" | jq -r '.lease_id')
Expand All @@ -173,12 +173,13 @@ assert_output_contains() {
}

@test "secrets successfully loaded from vault using VAULT_FROM_PATH" {
setup_vault_provider

# unset env vars to ensure secret-init will utilize VAULT_FROM_PATH
unset MYSQL_PASSWORD
unset AWS_SECRET_ACCESS_KEY
unset AWS_ACCESS_KEY_ID

setup_vault_provider
set_vault_token 227e1cce-6bf7-30bb-2d2a-acc854318caf
add_secrets_to_vault
export VAULT_FROM_PATH="secret/data/test/mysql,secret/data/test/aws"
Expand Down
23 changes: 22 additions & 1 deletion env_store.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ func (s *EnvStore) GetSecretReferences() map[string][]string {
}
}
}
checkFromPath(s.data, &secretReferences)

return secretReferences
}
Expand Down Expand Up @@ -190,10 +191,30 @@ func (s *EnvStore) workaroundForBao(ctx context.Context, vaultPaths []string) ([
// ConvertProviderSecrets converts the loaded secrets to environment variables
func (s *EnvStore) ConvertProviderSecrets(providerSecrets []provider.Secret) []string {
var secretsEnv []string

for _, secret := range providerSecrets {
secretsEnv = append(secretsEnv, fmt.Sprintf("%s=%s", secret.Key, secret.Value))
}

return secretsEnv
}

// Handle the edge case where *_FROM_PATH is defined but no direct env-var references are present
// in this case the provider should be created with an empty list of secret references
// leaving the secret injection to the provider
func checkFromPath(environ map[string]string, secretReferences *map[string][]string) {
if environ == nil || secretReferences == nil {
return
}

if _, ok := (*secretReferences)[vault.ProviderType]; !ok {
if _, ok := environ[vault.FromPathEnv]; ok {
(*secretReferences)[vault.ProviderType] = []string{}
}
}

if _, ok := (*secretReferences)[bao.ProviderType]; !ok {
if _, ok := environ[bao.FromPathEnv]; ok {
(*secretReferences)[bao.ProviderType] = []string{}
}
}
}
13 changes: 9 additions & 4 deletions pkg/provider/bao/bao.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import (

"github.com/bank-vaults/secret-init/pkg/common"
"github.com/bank-vaults/secret-init/pkg/provider"
"github.com/bank-vaults/secret-init/pkg/utils"
)

const (
Expand Down Expand Up @@ -125,14 +126,18 @@ func NewProvider(_ context.Context, appConfig *common.Config) (provider.Provider
// returns: []provider.Secret{provider.Secret{Path: "MYSQL_PASSWORD", Value: "password"}}
func (p *Provider) LoadSecrets(ctx context.Context, paths []string) ([]provider.Secret, error) {
sanitized := sanitized{login: p.isLogin}
baoEnviron := parsePathsToMap(paths)

secretInjector := injector.NewSecretInjector(p.injectorConfig, p.client, p.secretRenewer, slog.Default())
inject := func(key, value string) {
// Check for key duplication
if utils.IsKeyDuplicated(&sanitized.secrets, key) {
slog.Warn(fmt.Sprintf("Deduplication detected for key: %s", key))
return
}

sanitized.append(key, value)
}

err := secretInjector.InjectSecretsFromBao(baoEnviron, inject)
err := secretInjector.InjectSecretsFromBao(parsePathsToMap(paths), inject)
if err != nil {
return nil, fmt.Errorf("failed to inject secrets from bao: %w", err)
}
Expand All @@ -145,7 +150,7 @@ func (p *Provider) LoadSecrets(ctx context.Context, paths []string) ([]provider.
}

if p.revokeToken {
// ref: https://www.vaultproject.io/api/auth/token/index.html#revoke-a-token-self-
// ref: https://www.vaultproject.io/api/auth/token/index.html#revoke-a-token-self
err := p.client.RawClient().Auth().Token().RevokeSelfWithContext(ctx, p.client.RawClient().Token())
if err != nil {
// Do not exit on error, token revoking can be denied by policy
Expand Down
6 changes: 3 additions & 3 deletions pkg/provider/bao/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ const (
passthroughEnv = "BAO_PASSTHROUGH"
logLevelEnv = "BAO_LOG_LEVEL"
revokeTokenEnv = "BAO_REVOKE_TOKEN"
fromPathEnv = "BAO_FROM_PATH"
FromPathEnv = "BAO_FROM_PATH"
)

type Config struct {
Expand Down Expand Up @@ -110,7 +110,7 @@ var sanitizeEnvmap = map[string]envType{
passthroughEnv: {login: false},
logLevelEnv: {login: false},
revokeTokenEnv: {login: false},
fromPathEnv: {login: false},
FromPathEnv: {login: false},
}

func LoadConfig() (*Config, error) {
Expand Down Expand Up @@ -182,7 +182,7 @@ func LoadConfig() (*Config, error) {
TransitPath: os.Getenv(transitPathEnv),
TransitBatchSize: cast.ToInt(os.Getenv(transitBatchSizeEnv)),
IgnoreMissingSecrets: cast.ToBool(os.Getenv(ignoreMissingSecretsEnv)), // Used both for reading secrets and transit encryption
FromPath: os.Getenv(fromPathEnv),
FromPath: os.Getenv(FromPathEnv),
RevokeToken: cast.ToBool(os.Getenv(revokeTokenEnv)),
}, nil
}
2 changes: 1 addition & 1 deletion pkg/provider/bao/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ func TestConfig(t *testing.T) {
transitBatchSizeEnv: "10",
ignoreMissingSecretsEnv: "true",
revokeTokenEnv: "true",
fromPathEnv: "secret/data/test",
FromPathEnv: "secret/data/test",
},
wantConfig: &Config{
IsLogin: true,
Expand Down
6 changes: 3 additions & 3 deletions pkg/provider/vault/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ const (
passthroughEnv = "VAULT_PASSTHROUGH"
logLevelEnv = "VAULT_LOG_LEVEL"
revokeTokenEnv = "VAULT_REVOKE_TOKEN"
fromPathEnv = "VAULT_FROM_PATH"
FromPathEnv = "VAULT_FROM_PATH"
)

type Config struct {
Expand Down Expand Up @@ -110,7 +110,7 @@ var sanitizeEnvmap = map[string]envType{
passthroughEnv: {login: false},
logLevelEnv: {login: false},
revokeTokenEnv: {login: false},
fromPathEnv: {login: false},
FromPathEnv: {login: false},
}

func LoadConfig() (*Config, error) {
Expand Down Expand Up @@ -176,7 +176,7 @@ func LoadConfig() (*Config, error) {
TransitPath: os.Getenv(transitPathEnv),
TransitBatchSize: cast.ToInt(os.Getenv(transitBatchSizeEnv)),
IgnoreMissingSecrets: cast.ToBool(os.Getenv(ignoreMissingSecretsEnv)), // Used both for reading secrets and transit encryption
FromPath: os.Getenv(fromPathEnv),
FromPath: os.Getenv(FromPathEnv),
RevokeToken: cast.ToBool(os.Getenv(revokeTokenEnv)),
}, nil
}
2 changes: 1 addition & 1 deletion pkg/provider/vault/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ func TestConfig(t *testing.T) {
transitBatchSizeEnv: "10",
ignoreMissingSecretsEnv: "true",
revokeTokenEnv: "true",
fromPathEnv: "secret/data/test",
FromPathEnv: "secret/data/test",
},
wantConfig: &Config{
IsLogin: true,
Expand Down
13 changes: 9 additions & 4 deletions pkg/provider/vault/vault.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import (

"github.com/bank-vaults/secret-init/pkg/common"
"github.com/bank-vaults/secret-init/pkg/provider"
"github.com/bank-vaults/secret-init/pkg/utils"
)

const (
Expand Down Expand Up @@ -125,14 +126,18 @@ func NewProvider(_ context.Context, appConfig *common.Config) (provider.Provider
// returns: []provider.Secret{provider.Secret{Path: "MYSQL_PASSWORD", Value: "password"}}
func (p *Provider) LoadSecrets(ctx context.Context, paths []string) ([]provider.Secret, error) {
sanitized := sanitized{login: p.isLogin}
vaultEnviron := parsePathsToMap(paths)

secretInjector := injector.NewSecretInjector(p.injectorConfig, p.client, p.secretRenewer, slog.Default())
inject := func(key, value string) {
// Check for key duplication
if utils.IsKeyDuplicated(&sanitized.secrets, key) {
slog.Warn(fmt.Sprintf("Duplication detected for key: %s, skipping it", key))
return
}

sanitized.append(key, value)
}

err := secretInjector.InjectSecretsFromVault(vaultEnviron, inject)
err := secretInjector.InjectSecretsFromVault(parsePathsToMap(paths), inject)
if err != nil {
return nil, fmt.Errorf("failed to inject secrets from vault: %w", err)
}
Expand All @@ -145,7 +150,7 @@ func (p *Provider) LoadSecrets(ctx context.Context, paths []string) ([]provider.
}

if p.revokeToken {
// ref: https://www.vaultproject.io/api/auth/token/index.html#revoke-a-token-self-
// ref: https://www.vaultproject.io/api/auth/token/index.html#revoke-a-token-self
err := p.client.RawClient().Auth().Token().RevokeSelfWithContext(ctx, p.client.RawClient().Token())
if err != nil {
// Do not exit on error, token revoking can be denied by policy
Expand Down
32 changes: 32 additions & 0 deletions pkg/utils/helpers.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// Copyright © 2024 Bank-Vaults Maintainers
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package utils

import "github.com/bank-vaults/secret-init/pkg/provider"

// Checks whether a key is duplicated in the secrets slice
func IsKeyDuplicated(secrets *[]provider.Secret, searchKey string) bool {
if secrets == nil {
return false
}

for _, secret := range *secrets {
if secret.Key == searchKey {
return true
}
}

return false
}

0 comments on commit 608681f

Please sign in to comment.