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 (
"io/ioutil"
"log"
"net/http"
"path/filepath"
"golang.org/x/crypto/acme"
)
......@@ -46,6 +45,9 @@ func NewACME(config *Config) (*ACME, error) {
if config.Email == "" {
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
v := make(map[string]validator)
......@@ -77,7 +79,7 @@ func NewACME(config *Config) (*ACME, error) {
return &ACME{
email: config.Email,
accountKeyPath: filepath.Join(config.Dir, "account.key"),
accountKeyPath: config.AccountKeyPath,
directoryURL: directoryURL,
handler: h,
validators: v,
......
......@@ -17,7 +17,7 @@ import (
var (
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
......
......@@ -14,19 +14,28 @@ import (
// 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
type Config struct {
Addr string `yaml:"addr"`
Testing bool `yaml:"testing"`
DirectoryURL string `yaml:"directory_url"`
DefaultChallengeType string `yaml:"default_challenge"`
UseRSA bool `yaml:"use_rsa"`
RenewalDays int `yaml:"renewal_days"`
AccountKeyPath string `yaml:"account_key_path"`
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"`
} `yaml:"output"`
HTTP struct {
Enabled bool `yaml:"enabled"`
......@@ -79,12 +88,11 @@ func readCertConfigs(path string) ([]*certConfig, error) {
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"))
if err != nil {
return nil, err
}
var out []*certConfig
for _, f := range files {
cc, err := readCertConfigs(f)
if err != nil {
......@@ -97,8 +105,20 @@ func readCertConfigsFromDir(dir string) ([]*certConfig, error) {
log.Printf("configuration error in %s: %v", f, err)
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
}
......@@ -13,7 +13,6 @@ import (
"errors"
"io"
"log"
"path/filepath"
"sync"
"time"
......@@ -75,7 +74,7 @@ type CertGenerator interface {
// Manager periodically renews certificates before they expire, and
// responds to http-01 validation requests.
type Manager struct {
configDir string
configDirs []string
useRSA bool
storage certStorage
certs []*certInfo
......@@ -89,13 +88,16 @@ type Manager struct {
// NewManager creates a new Manager with the given configuration.
func NewManager(config *Config, certGen CertGenerator) (*Manager, error) {
// Validate the configuration.
if config.Dir == "" {
return nil, errors.New("configuration parameter 'cert_dir' is unset")
if len(config.Dirs) == 0 {
return nil, errors.New("configuration parameter 'config_dirs' is unset")
}
if config.Output.Path == "" {
return nil, errors.New("'output.path' is unset")
}
m := &Manager{
useRSA: config.UseRSA,
configDir: filepath.Join(config.Dir, "config"),
configDirs: config.Dirs,
doneCh: make(chan bool),
configCh: make(chan []*certConfig, 1),
certGen: certGen,
......@@ -105,11 +107,11 @@ func NewManager(config *Config, certGen CertGenerator) (*Manager, error) {
m.renewalDays = 15
}
ds := &dirStorage{root: filepath.Join(config.Dir, "certs")}
if config.ReplDS == nil {
ds := &dirStorage{root: config.Output.Path}
if config.Output.ReplDS == nil {
m.storage = ds
} else {
r, err := replds.NewPublicClient(config.ReplDS)
r, err := replds.NewPublicClient(config.Output.ReplDS)
if err != nil {
return nil, err
}
......@@ -126,7 +128,7 @@ func NewManager(config *Config, certGen CertGenerator) (*Manager, error) {
// cause background processing to stop, interrupting all running
// updates.
func (m *Manager) Start(ctx context.Context) error {
domains, err := readCertConfigsFromDir(m.configDir)
domains, err := readCertConfigsFromDirs(m.configDirs)
if err != nil {
return err
}
......@@ -145,7 +147,7 @@ func (m *Manager) Wait() {
// Reload configuration.
func (m *Manager) Reload() {
domains, err := readCertConfigsFromDir(m.configDir)
domains, err := readCertConfigsFromDirs(m.configDirs)
if err != nil {
log.Printf("error reading config: %v", err)
return
......
......@@ -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.
// The first function returned is a cleanup callback.
// The second function returned is the cancel callback.
......@@ -42,10 +52,7 @@ func newTestManager(t testing.TB, g CertGenerator) (func(), context.CancelFunc,
0644,
)
m, err := NewManager(&Config{
Dir: dir,
Email: "test@example.com",
}, g)
m, err := NewManager(newTestConfig(dir), g)
if err != nil {
t.Fatal(err)
}
......@@ -114,11 +121,11 @@ func TestManager_NewCert(t *testing.T) {
// Verify that the credentials have successfully been written
// 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 {
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 {
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