Skip to content

Commit

Permalink
add: secrets can be also passed by file
Browse files Browse the repository at this point in the history
Instead of supplying the secret via env var SECRET they can be also passed via env var SECRET_FILE. The secret is then read from the given file path. If the same secret is supplied in both ways, the value passed directly by env var takes precedence
  • Loading branch information
mgoetzegb committed Nov 28, 2024
1 parent 84079aa commit 796ab7a
Show file tree
Hide file tree
Showing 6 changed files with 107 additions and 2 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ For running the Notification Service outside of docker the latest version of [go

The service is configured via environment variables. Refer to the [Config](pkg/config/config.go) for the available options and their defaults.

The secret `DB_PASSWORD` can be also passed by file. Simply pass the path to the file containing the secret to the service by appending `_FILE` to the env var name, i.e. `DB_PASSWORD_FILE`. If the secret is supplied in both ways, the one directly passed by env var takes precedence.

## Running

> The following instructions are targeted at openSight developers. As end user the services should be run in orchestration with the other openSight services, which is not in the scope of this readme.
Expand Down
7 changes: 7 additions & 0 deletions cmd/notification-service/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (

"github.com/go-playground/validator"
"github.com/greenbone/opensight-notification-service/pkg/config"
"github.com/greenbone/opensight-notification-service/pkg/config/secretfiles"
"github.com/greenbone/opensight-notification-service/pkg/logging"
"github.com/greenbone/opensight-notification-service/pkg/repository"
"github.com/greenbone/opensight-notification-service/pkg/repository/notificationrepository"
Expand All @@ -28,6 +29,12 @@ import (

func main() {
var cfg config.Config
// Note: secrets can be passed directly by env var or via file
// if the same secret is supplied in both ways, the env var takes precedence
err := secretfiles.Read(&cfg)
if err != nil {
log.Fatal().Err(err).Msg("failed to read secrets from files")
}
err = envconfig.Process("", &cfg)
if err != nil {
log.Fatal().Err(err).Msg("failed to read config")
Expand Down
5 changes: 4 additions & 1 deletion docker-compose.service.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,13 @@
services:
notification-service:
build: . # replace this line with `image: ghcr.io/greenbone/notification-service:<desired vibd docker image>` if you want to use an already built image instead of building one from the active working directory
secrets:
- PostgresPassword
environment:
DB_HOST: postgres
DB_PORT: 5432
DB_USERNAME: postgres
DB_PASSWORD: $DB_PASSWORD
DB_PASSWORD_FILE: /run/secrets/PostgresPassword
DB_NAME: notification_service
DB_SSL_MODE: disable
LOG_LEVEL: debug
Expand All @@ -20,3 +22,4 @@ services:
depends_on:
postgres:
condition: service_healthy

8 changes: 7 additions & 1 deletion docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@
services:
postgres:
image: postgres:16
secrets:
- PostgresPassword
environment:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: $DB_PASSWORD
POSTGRES_PASSWORD_FILE: /run/secrets/PostgresPassword
POSTGRES_DB: notification_service
volumes:
- postgres-data:/var/lib/postgresql/data
Expand All @@ -24,3 +26,7 @@ volumes:

networks:
notification-service-net:

secrets:
PostgresPassword:
environment: DB_PASSWORD
22 changes: 22 additions & 0 deletions pkg/config/secretfiles/secret_files.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// SPDX-FileCopyrightText: 2024 Greenbone AG <https://greenbone.net>
//
// SPDX-License-Identifier: AGPL-3.0-or-later

package secretfiles

import (
"github.com/greenbone/opensight-golang-libraries/pkg/secretfiles"
"github.com/greenbone/opensight-notification-service/pkg/config"
)

const (
dbPasswordPathEnvVar = "DB_PASSWORD_FILE"
)

// Read takes the filepaths from environment variables and parses the content
// into the respective secret inside the passed config.
// A failure can have side effects on the passed config, so error from this function
// should be treated as fatal.
func Read(cfg *config.Config) (err error) {
return secretfiles.ReadSecret(dbPasswordPathEnvVar, &cfg.Database.Password)
}
65 changes: 65 additions & 0 deletions pkg/config/secretfiles/secret_files_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
// SPDX-FileCopyrightText: 2024 Greenbone AG <https://greenbone.net>
//
// SPDX-License-Identifier: AGPL-3.0-or-later

package secretfiles

import (
"os"
"testing"

"github.com/greenbone/opensight-notification-service/pkg/config"
"github.com/stretchr/testify/require"
)

func TestRead(t *testing.T) {
// create files containing secrets
tempDir := t.TempDir()
err := os.WriteFile(tempDir+"/db_password", []byte(" db_password \n\n\t"), 0644)
require.NoError(t, err)

tests := map[string]struct {
envVars map[string]string
inputConfig config.Config
wantConfig config.Config
wantErr bool
}{
"read all secrets from files": {
inputConfig: config.Config{},
envVars: map[string]string{
"DB_PASSWORD_FILE": tempDir + "/db_password",
},
wantConfig: config.Config{
Database: config.Database{
Password: `db_password`,
},
},
wantErr: false,
},
"failure with invalid path": {
inputConfig: config.Config{},
envVars: map[string]string{
"DB_PASSWORD_FILE": "/invalid/path",
},
wantErr: true,
},
}

for name, tt := range tests {
t.Run(name, func(t *testing.T) {
// set the environment variables
for key, value := range tt.envVars {
err := os.Setenv(key, value)
require.NoError(t, err)
}

err := Read(&tt.inputConfig)
if tt.wantErr {
require.Error(t, err)
} else {
require.NoError(t, err)
require.Equal(t, tt.wantConfig, tt.inputConfig)
}
})
}
}

0 comments on commit 796ab7a

Please sign in to comment.