Skip to content

Commit

Permalink
fix: redact config
Browse files Browse the repository at this point in the history
  • Loading branch information
gi8lino committed Aug 7, 2023
1 parent 71f8f23 commit 85c213e
Show file tree
Hide file tree
Showing 8 changed files with 98 additions and 45 deletions.
14 changes: 14 additions & 0 deletions cmd/serve.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"certalert/internal/server"

"github.com/fsnotify/fsnotify"
"github.com/jinzhu/copier"
log "github.com/sirupsen/logrus"
"github.com/spf13/cobra"
"github.com/spf13/viper"
Expand Down Expand Up @@ -54,9 +55,22 @@ the configuration if changes are detected.
if err := config.ParseConfig(&config.App); err != nil {
log.Fatalf("Unable to parse config: %s", err)
}

copier.Copy(&config.AppCopy, &config.App) // perform a deep copy
// update the config copy with the new values
if err := config.RedactConfig(&config.App); err != nil {
log.Fatalf("Unable to redact config: %s", err)
}

})
viper.WatchConfig()

copier.Copy(&config.AppCopy, &config.App) // perform a deep copy
// this is only necessary if starting the web server
if err := config.RedactConfig(&config.AppCopy); err != nil {
log.Fatalf("Unable to redact config: %s", err)
}

server.RunServer(config.App.Server.Hostname, config.App.Server.Port)
},
}
Expand Down
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ go 1.20
require (
github.com/fsnotify/fsnotify v1.6.0
github.com/gorilla/mux v1.8.0
github.com/jinzhu/copier v0.3.5
github.com/kataras/tablewriter v0.0.0-20180708051242-e063d29b7c23
github.com/pavlo-v-chernykh/keystore-go/v4 v4.4.1
github.com/prometheus/client_golang v1.16.0
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,8 @@ github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/jinzhu/copier v0.3.5 h1:GlvfUwHk62RokgqVNvYsku0TATCF7bAHVwEXoBh3iJg=
github.com/jinzhu/copier v0.3.5/go.mod h1:DfbEm0FYsaqBcKcFuvmOZb218JkPGtvSHsKg8S8hyyg=
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
github.com/kataras/tablewriter v0.0.0-20180708051242-e063d29b7c23 h1:M8exrBzuhWcU6aoHJlHWPe4qFjVKzkMGRal78f5jRRU=
Expand Down
22 changes: 11 additions & 11 deletions internal/config/parse.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,38 +27,38 @@ func validateAuthConfig(authConfig Auth) error {
}

// ParseConfig parse the config file and resolves variables
func ParseConfig(app *Config) (err error) {
app.Pushgateway.Address, err = utils.ResolveVariable(app.Pushgateway.Address)
func ParseConfig(config *Config) (err error) {
config.Pushgateway.Address, err = utils.ResolveVariable(config.Pushgateway.Address)
if err != nil {
return fmt.Errorf("Failed to resolve address for pushgateway: %v", err)
}

if err := validateAuthConfig(app.Pushgateway.Auth); err != nil {
if err := validateAuthConfig(config.Pushgateway.Auth); err != nil {
return err
}

app.Pushgateway.Auth.Basic.Password, err = utils.ResolveVariable(app.Pushgateway.Auth.Basic.Password)
config.Pushgateway.Auth.Basic.Password, err = utils.ResolveVariable(config.Pushgateway.Auth.Basic.Password)
if err != nil {
return fmt.Errorf("Failed to resolve password for pushgateway: %v", err)
}

app.Pushgateway.Auth.Bearer.Token, err = utils.ResolveVariable(app.Pushgateway.Auth.Bearer.Token)
config.Pushgateway.Auth.Bearer.Token, err = utils.ResolveVariable(config.Pushgateway.Auth.Bearer.Token)
if err != nil {
return fmt.Errorf("Failed to resolve token for pushgateway: %v", err)
}

if app.Pushgateway.Job == "" {
app.Pushgateway.Job = "certalert"
if config.Pushgateway.Job == "" {
config.Pushgateway.Job = "certalert"
} else {
app.Pushgateway.Job, err = utils.ResolveVariable(app.Pushgateway.Job)
config.Pushgateway.Job, err = utils.ResolveVariable(config.Pushgateway.Job)
if err != nil {
return fmt.Errorf("Failed to resolve job for pushgateway: %v", err)
}
}

for idx, cert := range app.Certs {
for idx, cert := range config.Certs {
if cert.Enabled != nil && !*cert.Enabled {
app.Certs[idx] = cert // update the certificate in the slice (maybe has changed from enabled to disabled)
config.Certs[idx] = cert // update the certificate in the slice (maybe has changed from enabled to disabled)
log.Debugf("Skip certificate '%s' because is disabled", cert.Name)
continue
}
Expand Down Expand Up @@ -108,7 +108,7 @@ func ParseConfig(app *Config) (err error) {
}
cert.Password = pw

app.Certs[idx] = cert
config.Certs[idx] = cert
}

return nil
Expand Down
40 changes: 40 additions & 0 deletions internal/config/redact.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package config

import (
"certalert/internal/utils"
"strings"
)

// redactVariable redacts sensitive data from the config if it is not prefixed with env: or file:
func redactVariable(s string) string {
if strings.HasPrefix(s, "env:") || strings.HasPrefix(s, "file:") {
return s
}
return "<REDACTED>"
}

// RedactConfig redacts sensitive data from the config
func RedactConfig(config *Config) error {

if utils.HasKey(config.Pushgateway, "Address") {
config.Pushgateway.Address = redactVariable(config.Pushgateway.Address)
}

if utils.HasKey(config.Pushgateway, "Basic.Username") {
config.Pushgateway.Auth.Basic.Username = redactVariable(config.Pushgateway.Auth.Basic.Username)
}

if utils.HasKey(config.Pushgateway, "Basic.Password") {
config.Pushgateway.Auth.Basic.Password = redactVariable(config.Pushgateway.Auth.Basic.Password)
}

if utils.HasKey(config.Pushgateway, "Bearer.Token") {
config.Pushgateway.Auth.Bearer.Token = redactVariable(config.Pushgateway.Auth.Bearer.Token)
}

for idx, cert := range config.Certs {
config.Certs[idx].Password = redactVariable(cert.Password)
}

return nil
}
26 changes: 26 additions & 0 deletions internal/config/redact_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package config

import "testing"

func TestRedactVariable(t *testing.T) {
tests := []struct {
input string
expected string
}{
{"env:SECRET_ENV", "env:SECRET_ENV"}, // Should not redact env: prefixed strings
{"file:/path/to/secret", "file:/path/to/secret"}, // Should not redact file: prefixed strings
{"mysecret", "<REDACTED>"}, // Should redact non-prefixed strings
{"", "<REDACTED>"}, // Should redact empty strings
{"filemysecret", "<REDACTED>"}, // Should redact strings that contains the word 'file' but not prefixed with 'file:'
{"envmysecret", "<REDACTED>"}, // Should redact strings that contains the word 'env' but not prefixed with 'env:'
}

for _, tt := range tests {
t.Run(tt.input, func(t *testing.T) {
actual := redactVariable(tt.input)
if actual != tt.expected {
t.Errorf("expected %s, got %s", tt.expected, actual)
}
})
}
}
3 changes: 3 additions & 0 deletions internal/config/structs.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ import "certalert/internal/certificates"
// Config represents the config file
var App Config

// ConfigCopy represents the config file with sensitive data redacted
var AppCopy Config

// Config represents the config file
type Config struct {
Server Server `json:"server"`
Expand Down
35 changes: 1 addition & 34 deletions internal/handlers/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,52 +3,19 @@ package handlers
import (
"bytes"
"certalert/internal/config"
"certalert/internal/utils"
"net/http"
"strings"

"gopkg.in/yaml.v3"
)

// redactVariable redacts sensitive data from the config if it is not prefixed with env: or file:
func redactVariable(s string) string {
if strings.HasPrefix(s, "env:") || strings.HasPrefix(s, "file:") {
return s
}
return "<REDACTED>"
}

// ConfigHandler returns the config as yaml
func ConfigHandler(w http.ResponseWriter, r *http.Request) {
var b bytes.Buffer
yamlEncoder := yaml.NewEncoder(&b)
defer yamlEncoder.Close()
yamlEncoder.SetIndent(2)

// copy config and remove sensitive data
configCopy := config.App

if utils.HasKey(configCopy.Pushgateway, "Address") {
configCopy.Pushgateway.Address = redactVariable(configCopy.Pushgateway.Address)
}

if utils.HasKey(configCopy.Pushgateway, "Basic.Username") {
configCopy.Pushgateway.Auth.Basic.Username = redactVariable(configCopy.Pushgateway.Auth.Basic.Username)
}

if utils.HasKey(configCopy.Pushgateway, "Basic.Password") {
configCopy.Pushgateway.Auth.Basic.Password = redactVariable(configCopy.Pushgateway.Auth.Basic.Password)
}

if utils.HasKey(configCopy.Pushgateway, "Bearer.Token") {
configCopy.Pushgateway.Auth.Bearer.Token = redactVariable(configCopy.Pushgateway.Auth.Bearer.Token)
}

for idx, cert := range configCopy.Certs {
configCopy.Certs[idx].Password = redactVariable(cert.Password)
}

if err := yamlEncoder.Encode(&configCopy); err != nil {
if err := yamlEncoder.Encode(&config.AppCopy); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
Expand Down

0 comments on commit 85c213e

Please sign in to comment.