Skip to content
Snippets Groups Projects
Commit 50c8662b authored by ale's avatar ale
Browse files

Minor changes to configuration

Support multiple config_dirs, name all paths explicitly instead of
simply using predefined subdirectories.
parent 5e94ddcc
No related branches found
No related tags found
No related merge requests found
...@@ -13,7 +13,6 @@ import ( ...@@ -13,7 +13,6 @@ import (
"io/ioutil" "io/ioutil"
"log" "log"
"net/http" "net/http"
"path/filepath"
"golang.org/x/crypto/acme" "golang.org/x/crypto/acme"
) )
...@@ -46,6 +45,9 @@ func NewACME(config *Config) (*ACME, error) { ...@@ -46,6 +45,9 @@ func NewACME(config *Config) (*ACME, error) {
if config.Email == "" { if config.Email == "" {
return nil, errors.New("configuration parameter 'email' is unset") return nil, errors.New("configuration parameter 'email' is unset")
} }
if config.AccountKeyPath == "" {
return nil, errors.New("configuration parameter 'account_key_path' is unset")
}
var h http.Handler var h http.Handler
v := make(map[string]validator) v := make(map[string]validator)
...@@ -77,7 +79,7 @@ func NewACME(config *Config) (*ACME, error) { ...@@ -77,7 +79,7 @@ func NewACME(config *Config) (*ACME, error) {
return &ACME{ return &ACME{
email: config.Email, email: config.Email,
accountKeyPath: filepath.Join(config.Dir, "account.key"), accountKeyPath: config.AccountKeyPath,
directoryURL: directoryURL, directoryURL: directoryURL,
handler: h, handler: h,
validators: v, validators: v,
......
...@@ -17,7 +17,7 @@ import ( ...@@ -17,7 +17,7 @@ import (
var ( var (
addr = flag.String("addr", ":2780", "tcp `address` to listen on") addr = flag.String("addr", ":2780", "tcp `address` to listen on")
configFile = flag.String("config", "/etc/acmeserver/config.yml", "configuration `file`") configFile = flag.String("config", "/etc/acme/config.yml", "configuration `file`")
) )
// Config ties together the acmeserver Config and the standard // Config ties together the acmeserver Config and the standard
......
...@@ -14,19 +14,28 @@ import ( ...@@ -14,19 +14,28 @@ import (
// Config holds the configuration for an acmeserver instance. // Config holds the configuration for an acmeserver instance.
// //
// The reason for supporting multiple config_dirs is to allow
// integration with third-party automation systems: in some cases,
// automation tools need control of an entire directory in order to
// safely delete entries that no longer exist.
//
// nolint: maligned // nolint: maligned
type Config struct { type Config struct {
Addr string `yaml:"addr"`
Testing bool `yaml:"testing"` Testing bool `yaml:"testing"`
DirectoryURL string `yaml:"directory_url"` DirectoryURL string `yaml:"directory_url"`
DefaultChallengeType string `yaml:"default_challenge"` DefaultChallengeType string `yaml:"default_challenge"`
UseRSA bool `yaml:"use_rsa"` UseRSA bool `yaml:"use_rsa"`
RenewalDays int `yaml:"renewal_days"` RenewalDays int `yaml:"renewal_days"`
AccountKeyPath string `yaml:"account_key_path"`
Email string `yaml:"email"` Email string `yaml:"email"`
Dir string `yaml:"cert_dir"` Dirs []string `yaml:"config_dirs"`
Output struct {
Path string `yaml:"path"`
ReplDS *clientutil.BackendConfig `yaml:"replds"` ReplDS *clientutil.BackendConfig `yaml:"replds"`
} `yaml:"output"`
HTTP struct { HTTP struct {
Enabled bool `yaml:"enabled"` Enabled bool `yaml:"enabled"`
...@@ -79,12 +88,11 @@ func readCertConfigs(path string) ([]*certConfig, error) { ...@@ -79,12 +88,11 @@ func readCertConfigs(path string) ([]*certConfig, error) {
return cc, nil return cc, nil
} }
func readCertConfigsFromDir(dir string) ([]*certConfig, error) { func readCertConfigsFromDir(dir string, certs []*certConfig) ([]*certConfig, error) {
files, err := filepath.Glob(filepath.Join(dir, "*.yml")) files, err := filepath.Glob(filepath.Join(dir, "*.yml"))
if err != nil { if err != nil {
return nil, err return nil, err
} }
var out []*certConfig
for _, f := range files { for _, f := range files {
cc, err := readCertConfigs(f) cc, err := readCertConfigs(f)
if err != nil { if err != nil {
...@@ -97,8 +105,20 @@ func readCertConfigsFromDir(dir string) ([]*certConfig, error) { ...@@ -97,8 +105,20 @@ func readCertConfigsFromDir(dir string) ([]*certConfig, error) {
log.Printf("configuration error in %s: %v", f, err) log.Printf("configuration error in %s: %v", f, err)
continue continue
} }
out = append(out, c) certs = append(certs, c)
}
}
return certs, nil
}
func readCertConfigsFromDirs(dirs []string) ([]*certConfig, error) {
var out []*certConfig
for _, dir := range dirs {
certs, err := readCertConfigsFromDir(dir, out)
if err != nil {
return nil, err
} }
out = certs
} }
return out, nil return out, nil
} }
...@@ -13,7 +13,6 @@ import ( ...@@ -13,7 +13,6 @@ import (
"errors" "errors"
"io" "io"
"log" "log"
"path/filepath"
"sync" "sync"
"time" "time"
...@@ -75,7 +74,7 @@ type CertGenerator interface { ...@@ -75,7 +74,7 @@ type CertGenerator interface {
// Manager periodically renews certificates before they expire, and // Manager periodically renews certificates before they expire, and
// responds to http-01 validation requests. // responds to http-01 validation requests.
type Manager struct { type Manager struct {
configDir string configDirs []string
useRSA bool useRSA bool
storage certStorage storage certStorage
certs []*certInfo certs []*certInfo
...@@ -89,13 +88,16 @@ type Manager struct { ...@@ -89,13 +88,16 @@ type Manager struct {
// NewManager creates a new Manager with the given configuration. // NewManager creates a new Manager with the given configuration.
func NewManager(config *Config, certGen CertGenerator) (*Manager, error) { func NewManager(config *Config, certGen CertGenerator) (*Manager, error) {
// Validate the configuration. // Validate the configuration.
if config.Dir == "" { if len(config.Dirs) == 0 {
return nil, errors.New("configuration parameter 'cert_dir' is unset") return nil, errors.New("configuration parameter 'config_dirs' is unset")
}
if config.Output.Path == "" {
return nil, errors.New("'output.path' is unset")
} }
m := &Manager{ m := &Manager{
useRSA: config.UseRSA, useRSA: config.UseRSA,
configDir: filepath.Join(config.Dir, "config"), configDirs: config.Dirs,
doneCh: make(chan bool), doneCh: make(chan bool),
configCh: make(chan []*certConfig, 1), configCh: make(chan []*certConfig, 1),
certGen: certGen, certGen: certGen,
...@@ -105,11 +107,11 @@ func NewManager(config *Config, certGen CertGenerator) (*Manager, error) { ...@@ -105,11 +107,11 @@ func NewManager(config *Config, certGen CertGenerator) (*Manager, error) {
m.renewalDays = 15 m.renewalDays = 15
} }
ds := &dirStorage{root: filepath.Join(config.Dir, "certs")} ds := &dirStorage{root: config.Output.Path}
if config.ReplDS == nil { if config.Output.ReplDS == nil {
m.storage = ds m.storage = ds
} else { } else {
r, err := replds.NewPublicClient(config.ReplDS) r, err := replds.NewPublicClient(config.Output.ReplDS)
if err != nil { if err != nil {
return nil, err return nil, err
} }
...@@ -126,7 +128,7 @@ func NewManager(config *Config, certGen CertGenerator) (*Manager, error) { ...@@ -126,7 +128,7 @@ func NewManager(config *Config, certGen CertGenerator) (*Manager, error) {
// cause background processing to stop, interrupting all running // cause background processing to stop, interrupting all running
// updates. // updates.
func (m *Manager) Start(ctx context.Context) error { func (m *Manager) Start(ctx context.Context) error {
domains, err := readCertConfigsFromDir(m.configDir) domains, err := readCertConfigsFromDirs(m.configDirs)
if err != nil { if err != nil {
return err return err
} }
...@@ -145,7 +147,7 @@ func (m *Manager) Wait() { ...@@ -145,7 +147,7 @@ func (m *Manager) Wait() {
// Reload configuration. // Reload configuration.
func (m *Manager) Reload() { func (m *Manager) Reload() {
domains, err := readCertConfigsFromDir(m.configDir) domains, err := readCertConfigsFromDirs(m.configDirs)
if err != nil { if err != nil {
log.Printf("error reading config: %v", err) log.Printf("error reading config: %v", err)
return return
......
...@@ -26,6 +26,16 @@ func (s *slowACME) GetCertificate(ctx context.Context, _ crypto.Signer, _ *certC ...@@ -26,6 +26,16 @@ func (s *slowACME) GetCertificate(ctx context.Context, _ crypto.Signer, _ *certC
} }
} }
func newTestConfig(dir string) *Config {
c := Config{
Dirs: []string{filepath.Join(dir, "config")},
AccountKeyPath: filepath.Join(dir, "account.key"),
Email: "test@example.com",
}
c.Output.Path = filepath.Join(dir, "certs")
return &c
}
// Create a new test function. // Create a new test function.
// The first function returned is a cleanup callback. // The first function returned is a cleanup callback.
// The second function returned is the cancel callback. // The second function returned is the cancel callback.
...@@ -42,10 +52,7 @@ func newTestManager(t testing.TB, g CertGenerator) (func(), context.CancelFunc, ...@@ -42,10 +52,7 @@ func newTestManager(t testing.TB, g CertGenerator) (func(), context.CancelFunc,
0644, 0644,
) )
m, err := NewManager(&Config{ m, err := NewManager(newTestConfig(dir), g)
Dir: dir,
Email: "test@example.com",
}, g)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
...@@ -114,11 +121,11 @@ func TestManager_NewCert(t *testing.T) { ...@@ -114,11 +121,11 @@ func TestManager_NewCert(t *testing.T) {
// Verify that the credentials have successfully been written // Verify that the credentials have successfully been written
// to storage. // to storage.
p := filepath.Join(m.configDir, "../certs/example.com/cert.pem") p := filepath.Join(m.configDirs[0], "../certs/example.com/cert.pem")
if _, err := os.Stat(p); err != nil { if _, err := os.Stat(p); err != nil {
t.Fatalf("file not created: %v", err) t.Fatalf("file not created: %v", err)
} }
p = filepath.Join(m.configDir, "../certs/example.com/private_key.pem") p = filepath.Join(m.configDirs[0], "../certs/example.com/private_key.pem")
if _, err := os.Stat(p); err != nil { if _, err := os.Stat(p); err != nil {
t.Fatalf("file not created: %v", err) t.Fatalf("file not created: %v", err)
} }
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment