Add ConfigSecret.
This allows secret values to be stored externally to the config file, so that config files can be easily shared without revealing secret data.
This commit is contained in:
parent
7ea3f5da08
commit
5dd212dd47
|
|
@ -48,7 +48,7 @@ func setupContext(context *cli.Context) (rpc.RegistrationAuthorityClient, *blog.
|
|||
rac, err := rpc.NewRegistrationAuthorityClient(clientName, amqpConf, stats)
|
||||
cmd.FailOnError(err, "Unable to create CA client")
|
||||
|
||||
dbMap, err := sa.NewDbMap(c.Revoker.DBConnect)
|
||||
dbMap, err := sa.NewDbMap(string(c.Revoker.DBConnect))
|
||||
cmd.FailOnError(err, "Couldn't setup database connection")
|
||||
|
||||
sac, err := rpc.NewStorageAuthorityClient(clientName, amqpConf, stats)
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ func main() {
|
|||
|
||||
go cmd.DebugServer(c.CA.DebugAddr)
|
||||
|
||||
paDbMap, err := sa.NewDbMap(c.PA.DBConnect)
|
||||
paDbMap, err := sa.NewDbMap(string(c.PA.DBConnect))
|
||||
cmd.FailOnError(err, "Couldn't connect to policy database")
|
||||
pa, err := policy.NewPolicyAuthorityImpl(paDbMap, c.PA.EnforcePolicyWhitelist, c.PA.Challenges)
|
||||
cmd.FailOnError(err, "Couldn't create PA")
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ func main() {
|
|||
|
||||
go cmd.DebugServer(c.RA.DebugAddr)
|
||||
|
||||
paDbMap, err := sa.NewDbMap(c.PA.DBConnect)
|
||||
paDbMap, err := sa.NewDbMap(string(c.PA.DBConnect))
|
||||
cmd.FailOnError(err, "Couldn't connect to policy database")
|
||||
pa, err := policy.NewPolicyAuthorityImpl(paDbMap, c.PA.EnforcePolicyWhitelist, c.PA.Challenges)
|
||||
cmd.FailOnError(err, "Couldn't create PA")
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ func main() {
|
|||
saConf := c.SA
|
||||
go cmd.DebugServer(saConf.DebugAddr)
|
||||
|
||||
dbMap, err := sa.NewDbMap(saConf.DBConnect)
|
||||
dbMap, err := sa.NewDbMap(string(saConf.DBConnect))
|
||||
cmd.FailOnError(err, "Couldn't connect to SA database")
|
||||
|
||||
sai, err := sa.NewSQLStorageAuthority(dbMap, clock.Default())
|
||||
|
|
|
|||
|
|
@ -239,10 +239,10 @@ func main() {
|
|||
cmd.FailOnError(c.PA.CheckChallenges(), "Invalid PA configuration")
|
||||
c.PA.SetDefaultChallengesIfEmpty()
|
||||
|
||||
saDbMap, err := sa.NewDbMap(c.CertChecker.DBConnect)
|
||||
saDbMap, err := sa.NewDbMap(string(c.CertChecker.DBConnect))
|
||||
cmd.FailOnError(err, "Could not connect to database")
|
||||
|
||||
paDbMap, err := sa.NewDbMap(c.PA.DBConnect)
|
||||
paDbMap, err := sa.NewDbMap(string(c.PA.DBConnect))
|
||||
cmd.FailOnError(err, "Could not connect to policy database")
|
||||
|
||||
checker := newChecker(saDbMap, paDbMap, clock.Default(), c.PA.EnforcePolicyWhitelist, c.PA.Challenges)
|
||||
|
|
|
|||
|
|
@ -9,6 +9,8 @@ import (
|
|||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
cfsslConfig "github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/config"
|
||||
|
|
@ -65,7 +67,7 @@ type Config struct {
|
|||
SA struct {
|
||||
ServiceConfig
|
||||
|
||||
DBConnect string
|
||||
DBConnect ConfigSecret
|
||||
|
||||
MaxConcurrentRPCServerRequests int64
|
||||
}
|
||||
|
|
@ -183,7 +185,7 @@ type ServiceConfig struct {
|
|||
// AMQPConfig describes how to connect to AMQP, and how to speak to each of the
|
||||
// RPC services we offer via AMQP.
|
||||
type AMQPConfig struct {
|
||||
Server string
|
||||
Server ConfigSecret
|
||||
Insecure bool
|
||||
RA *RPCServerConfig
|
||||
VA *RPCServerConfig
|
||||
|
|
@ -386,3 +388,35 @@ func (d *ConfigDuration) UnmarshalYAML(unmarshal func(interface{}) error) error
|
|||
d.Duration = dur
|
||||
return nil
|
||||
}
|
||||
|
||||
// A ConfigSecret represents a string-valued config field. It may be specified
|
||||
// directly in the config or, if it starts with the string "secret:", its
|
||||
// contents are read from the filename that comes after "secret:", with
|
||||
// trailing newlines removed.
|
||||
type ConfigSecret string
|
||||
|
||||
var errSecretMustBeString = errors.New("cannot JSON unmarshal something other than a string into a ConfigSecret")
|
||||
|
||||
const secretPrefix = "secret:"
|
||||
|
||||
// UnmarshalJSON unmarshals a ConfigSecret
|
||||
func (d *ConfigSecret) UnmarshalJSON(b []byte) error {
|
||||
s := ""
|
||||
err := json.Unmarshal(b, &s)
|
||||
if err != nil {
|
||||
if _, ok := err.(*json.UnmarshalTypeError); ok {
|
||||
return errSecretMustBeString
|
||||
}
|
||||
return err
|
||||
}
|
||||
if !strings.HasPrefix(s, secretPrefix) {
|
||||
*d = ConfigSecret(s)
|
||||
return nil
|
||||
}
|
||||
contents, err := ioutil.ReadFile(s[len(secretPrefix):])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*d = ConfigSecret(strings.TrimRight(string(contents), "\n"))
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,32 @@
|
|||
package cmd
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"os"
|
||||
"path"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestConfigSecret(t *testing.T) {
|
||||
type hasASecret struct {
|
||||
Value ConfigSecret
|
||||
}
|
||||
var twocankeep hasASecret
|
||||
err := json.Unmarshal([]byte(`{"value": "hi"}`), &twocankeep)
|
||||
if err != nil {
|
||||
t.Fatalf("Error unmarshaling: %s", err)
|
||||
}
|
||||
if twocankeep.Value != "hi" {
|
||||
t.Errorf("Expected parsed value to be \"hi\", got %q", twocankeep.Value)
|
||||
}
|
||||
|
||||
os.Chdir(path.Base(os.Args[0]))
|
||||
var oneofthemisdead hasASecret
|
||||
err = json.Unmarshal([]byte(`{"value": "secret:testdata/secret"}`), &oneofthemisdead)
|
||||
if err != nil {
|
||||
t.Fatalf("Error unmarshaling: %s", err)
|
||||
}
|
||||
if oneofthemisdead.Value != "test secret" {
|
||||
t.Errorf("Expected parsed value to be \"test secret\", got %q", twocankeep.Value)
|
||||
}
|
||||
}
|
||||
|
|
@ -231,7 +231,7 @@ func main() {
|
|||
go cmd.DebugServer(c.Mailer.DebugAddr)
|
||||
|
||||
// Configure DB
|
||||
dbMap, err := sa.NewDbMap(c.Mailer.DBConnect)
|
||||
dbMap, err := sa.NewDbMap(string(c.Mailer.DBConnect))
|
||||
cmd.FailOnError(err, "Could not connect to database")
|
||||
|
||||
amqpConf := c.SA.AMQP
|
||||
|
|
|
|||
|
|
@ -150,7 +150,7 @@ func main() {
|
|||
|
||||
app.Action = func(c cmd.Config, stats statsd.Statter, auditlogger *blog.AuditLogger) {
|
||||
// Configure DB
|
||||
dbMap, err := sa.NewDbMap(c.PA.DBConnect)
|
||||
dbMap, err := sa.NewDbMap(string(c.PA.DBConnect))
|
||||
cmd.FailOnError(err, "Could not connect to database")
|
||||
|
||||
dbMap.AddTableWithName(core.ExternalCert{}, "externalCerts").SetKeys(false, "SHA1")
|
||||
|
|
|
|||
|
|
@ -560,7 +560,7 @@ func main() {
|
|||
go cmd.ProfileCmd("OCSP-Updater", stats)
|
||||
|
||||
// Configure DB
|
||||
dbMap, err := sa.NewDbMap(conf.DBConnect)
|
||||
dbMap, err := sa.NewDbMap(string(conf.DBConnect))
|
||||
cmd.FailOnError(err, "Could not connect to database")
|
||||
|
||||
cac, pubc, sac := setupClients(conf, stats)
|
||||
|
|
|
|||
|
|
@ -110,7 +110,7 @@ func setupFromContext(context *cli.Context) (*policy.PolicyAuthorityDatabaseImpl
|
|||
err = json.Unmarshal(configJSON, &c)
|
||||
cmd.FailOnError(err, "Couldn't unmarshal configuration object")
|
||||
|
||||
dbMap, err := sa.NewDbMap(c.PA.DBConnect)
|
||||
dbMap, err := sa.NewDbMap(string(c.PA.DBConnect))
|
||||
cmd.FailOnError(err, "Failed to create DB map")
|
||||
|
||||
padb, err := policy.NewPolicyAuthorityDatabaseImpl(dbMap)
|
||||
|
|
|
|||
|
|
@ -0,0 +1 @@
|
|||
test secret
|
||||
|
|
@ -296,14 +296,15 @@ func AmqpChannel(conf *cmd.AMQPConfig) (*amqp.Channel, error) {
|
|||
|
||||
log := blog.GetAuditLogger()
|
||||
|
||||
server := string(conf.Server)
|
||||
if conf.Insecure == true {
|
||||
// If the Insecure flag is true, then just go ahead and connect
|
||||
conn, err = amqp.Dial(conf.Server)
|
||||
conn, err = amqp.Dial(server)
|
||||
} else {
|
||||
// The insecure flag is false or not set, so we need to load up the options
|
||||
log.Info("AMQPS: Loading TLS Options.")
|
||||
|
||||
if strings.HasPrefix(conf.Server, "amqps") == false {
|
||||
if strings.HasPrefix(server, "amqps") == false {
|
||||
err = fmt.Errorf("AMQPS: Not using an AMQPS URL. To use AMQP instead of AMQPS, set insecure=true")
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -347,7 +348,7 @@ func AmqpChannel(conf *cmd.AMQPConfig) (*amqp.Channel, error) {
|
|||
log.Info("AMQPS: Configured CA certificate for AMQPS.")
|
||||
}
|
||||
|
||||
conn, err = amqp.DialTLS(conf.Server, cfg)
|
||||
conn, err = amqp.DialTLS(server, cfg)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@
|
|||
"shutdownKillTimeout": "1m",
|
||||
"debugAddr": "localhost:8000",
|
||||
"amqp": {
|
||||
"server": "amqp://guest:guest@localhost:5673",
|
||||
"server": "secret:test/secrets/amqp",
|
||||
"insecure": true,
|
||||
"RA": {
|
||||
"server": "RA.server",
|
||||
|
|
@ -96,7 +96,7 @@
|
|||
"maxConcurrentRPCServerRequests": 16,
|
||||
"hsmFaultTimeout": "300s",
|
||||
"amqp": {
|
||||
"server": "amqp://guest:guest@localhost:5673",
|
||||
"server": "secret:test/secrets/amqp",
|
||||
"insecure": true,
|
||||
"serviceQueue": "CA.server",
|
||||
"SA": {
|
||||
|
|
@ -111,7 +111,7 @@
|
|||
},
|
||||
|
||||
"pa": {
|
||||
"dbConnect": "mysql+tcp://policy@localhost:3306/boulder_policy_integration",
|
||||
"dbConnect": "secret:test/secrets/pa_dburl",
|
||||
"challenges": {
|
||||
"simpleHttp": true,
|
||||
"dvsni": true,
|
||||
|
|
@ -127,7 +127,7 @@
|
|||
"maxContactsPerRegistration": 100,
|
||||
"debugAddr": "localhost:8002",
|
||||
"amqp": {
|
||||
"server": "amqp://guest:guest@localhost:5673",
|
||||
"server": "secret:test/secrets/amqp",
|
||||
"insecure": true,
|
||||
"serviceQueue": "RA.server",
|
||||
"VA": {
|
||||
|
|
@ -147,11 +147,11 @@
|
|||
},
|
||||
|
||||
"sa": {
|
||||
"dbConnect": "mysql+tcp://sa@localhost:3306/boulder_sa_integration",
|
||||
"dbConnect": "secret:test/secrets/sa_dburl",
|
||||
"maxConcurrentRPCServerRequests": 16,
|
||||
"debugAddr": "localhost:8003",
|
||||
"amqp": {
|
||||
"server": "amqp://guest:guest@localhost:5673",
|
||||
"server": "secret:test/secrets/amqp",
|
||||
"insecure": true,
|
||||
"serviceQueue": "SA.server"
|
||||
}
|
||||
|
|
@ -167,7 +167,7 @@
|
|||
},
|
||||
"maxConcurrentRPCServerRequests": 16,
|
||||
"amqp": {
|
||||
"server": "amqp://guest:guest@localhost:5673",
|
||||
"server": "secret:test/secrets/amqp",
|
||||
"insecure": true,
|
||||
"serviceQueue": "VA.server",
|
||||
"RA": {
|
||||
|
|
@ -182,9 +182,9 @@
|
|||
},
|
||||
|
||||
"revoker": {
|
||||
"dbConnect": "mysql+tcp://revoker@localhost:3306/boulder_sa_integration",
|
||||
"dbConnect": "secret:test/secrets/revoker_dburl",
|
||||
"amqp": {
|
||||
"server": "amqp://guest:guest@localhost:5673",
|
||||
"server": "secret:test/secrets/amqp",
|
||||
"insecure": true,
|
||||
"RA": {
|
||||
"server": "RA.server",
|
||||
|
|
@ -208,7 +208,7 @@
|
|||
},
|
||||
|
||||
"ocspUpdater": {
|
||||
"dbConnect": "mysql+tcp://ocsp_update@localhost:3306/boulder_sa_integration",
|
||||
"dbConnect": "secret:test/secrets/ocsp_updater_dburl",
|
||||
"newCertificateWindow": "1s",
|
||||
"oldOCSPWindow": "2s",
|
||||
"missingSCTWindow": "1m",
|
||||
|
|
@ -223,7 +223,7 @@
|
|||
"signFailureBackoffMax": "30m",
|
||||
"debugAddr": "localhost:8006",
|
||||
"amqp": {
|
||||
"server": "amqp://guest:guest@localhost:5673",
|
||||
"server": "secret:test/secrets/amqp",
|
||||
"insecure": true,
|
||||
"SA": {
|
||||
"server": "SA.server",
|
||||
|
|
@ -243,7 +243,7 @@
|
|||
"activityMonitor": {
|
||||
"debugAddr": "localhost:8007",
|
||||
"amqp": {
|
||||
"server": "amqp://guest:guest@localhost:5673",
|
||||
"server": "secret:test/secrets/amqp",
|
||||
"insecure": true
|
||||
}
|
||||
},
|
||||
|
|
@ -253,7 +253,7 @@
|
|||
"port": "25",
|
||||
"username": "cert-master@example.com",
|
||||
"password": "password",
|
||||
"dbConnect": "mysql+tcp://mailer@localhost:3306/boulder_sa_integration",
|
||||
"dbConnect": "secret:test/secrets/mailer_dburl",
|
||||
"messageLimit": 0,
|
||||
"nagTimes": ["24h", "72h", "168h", "336h"],
|
||||
"nagCheckInterval": "24h",
|
||||
|
|
@ -265,7 +265,7 @@
|
|||
"maxConcurrentRPCServerRequests": 16,
|
||||
"debugAddr": "localhost:8009",
|
||||
"amqp": {
|
||||
"server": "amqp://guest:guest@localhost:5673",
|
||||
"server": "secret:test/secrets/amqp",
|
||||
"insecure": true,
|
||||
"serviceQueue": "Publisher.server",
|
||||
"SA": {
|
||||
|
|
@ -295,7 +295,7 @@
|
|||
},
|
||||
|
||||
"certChecker": {
|
||||
"dbConnect": "mysql+tcp://cert_checker@localhost:3306/boulder_sa_integration"
|
||||
"dbConnect": "secret:test/secrets/cert_checker_dburl"
|
||||
},
|
||||
|
||||
"subscriberAgreementURL": "http://127.0.0.1:4001/terms/v1"
|
||||
|
|
|
|||
|
|
@ -0,0 +1 @@
|
|||
amqp://guest:guest@localhost:5673
|
||||
|
|
@ -0,0 +1 @@
|
|||
mysql+tcp://cert_checker@localhost:3306/boulder_sa_integration
|
||||
|
|
@ -0,0 +1 @@
|
|||
mysql+tcp://mailer@localhost:3306/boulder_sa_integration
|
||||
|
|
@ -0,0 +1 @@
|
|||
mysql+tcp://ocsp_update@localhost:3306/boulder_sa_integration
|
||||
|
|
@ -0,0 +1 @@
|
|||
mysql+tcp://policy@localhost:3306/boulder_policy_integration
|
||||
|
|
@ -0,0 +1 @@
|
|||
mysql+tcp://revoker@localhost:3306/boulder_sa_integration
|
||||
|
|
@ -0,0 +1 @@
|
|||
mysql+tcp://sa@localhost:3306/boulder_sa_integration
|
||||
Loading…
Reference in New Issue