2019-04-25 22:54:48 +03:00
|
|
|
package caddytls
|
|
|
|
|
|
|
|
import (
|
|
|
|
"encoding/json"
|
|
|
|
"fmt"
|
2019-04-26 21:35:39 +03:00
|
|
|
"time"
|
2019-04-25 22:54:48 +03:00
|
|
|
|
|
|
|
"github.com/go-acme/lego/certcrypto"
|
|
|
|
|
2019-06-04 22:52:37 +03:00
|
|
|
"github.com/caddyserver/caddy2"
|
2019-04-25 22:54:48 +03:00
|
|
|
"github.com/go-acme/lego/challenge"
|
|
|
|
"github.com/mholt/certmagic"
|
|
|
|
)
|
|
|
|
|
|
|
|
func init() {
|
|
|
|
caddy2.RegisterModule(caddy2.Module{
|
|
|
|
Name: "tls.management.acme",
|
2019-06-05 07:43:21 +03:00
|
|
|
New: func() interface{} { return new(ACMEManagerMaker) },
|
2019-04-25 22:54:48 +03:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2019-06-05 07:43:21 +03:00
|
|
|
// ACMEManagerMaker makes an ACME manager
|
|
|
|
// for managing certificates using ACME.
|
|
|
|
// If crafting one manually rather than
|
|
|
|
// through the config-unmarshal process
|
|
|
|
// (provisioning), be sure to call
|
|
|
|
// SetDefaults to ensure sane defaults
|
|
|
|
// after you have configured this struct
|
|
|
|
// to your liking.
|
|
|
|
type ACMEManagerMaker struct {
|
2019-04-25 22:54:48 +03:00
|
|
|
CA string `json:"ca,omitempty"`
|
|
|
|
Email string `json:"email,omitempty"`
|
|
|
|
RenewAhead caddy2.Duration `json:"renew_ahead,omitempty"`
|
|
|
|
KeyType string `json:"key_type,omitempty"`
|
|
|
|
ACMETimeout caddy2.Duration `json:"acme_timeout,omitempty"`
|
|
|
|
MustStaple bool `json:"must_staple,omitempty"`
|
|
|
|
Challenges ChallengesConfig `json:"challenges"`
|
|
|
|
OnDemand *OnDemandConfig `json:"on_demand,omitempty"`
|
|
|
|
Storage json.RawMessage `json:"storage,omitempty"`
|
|
|
|
|
|
|
|
storage certmagic.Storage
|
|
|
|
keyType certcrypto.KeyType
|
|
|
|
}
|
|
|
|
|
2019-06-05 07:43:21 +03:00
|
|
|
// newManager is a no-op to satisfy the ManagerMaker interface,
|
|
|
|
// because this manager type is a special case.
|
|
|
|
func (m *ACMEManagerMaker) newManager(interactive bool) (certmagic.Manager, error) {
|
2019-04-26 21:35:39 +03:00
|
|
|
return nil, nil
|
|
|
|
}
|
2019-04-25 22:54:48 +03:00
|
|
|
|
2019-06-05 07:43:21 +03:00
|
|
|
// Provision sets up m.
|
|
|
|
func (m *ACMEManagerMaker) Provision(ctx caddy2.Context) error {
|
2019-04-25 22:54:48 +03:00
|
|
|
// DNS providers
|
|
|
|
if m.Challenges.DNS != nil {
|
2019-06-05 07:43:21 +03:00
|
|
|
val, err := ctx.LoadModuleInline("provider", "tls.dns", m.Challenges.DNSRaw)
|
2019-04-25 22:54:48 +03:00
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("loading TLS storage module: %s", err)
|
|
|
|
}
|
2019-06-05 07:43:21 +03:00
|
|
|
m.Challenges.DNS = val.(challenge.Provider)
|
|
|
|
m.Challenges.DNSRaw = nil // allow GC to deallocate - TODO: Does this help?
|
2019-04-25 22:54:48 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
// policy-specific storage implementation
|
|
|
|
if m.Storage != nil {
|
2019-05-17 01:05:38 +03:00
|
|
|
val, err := ctx.LoadModuleInline("system", "caddy.storage", m.Storage)
|
2019-04-25 22:54:48 +03:00
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("loading TLS storage module: %s", err)
|
|
|
|
}
|
|
|
|
cmStorage, err := val.(caddy2.StorageConverter).CertMagicStorage()
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("creating TLS storage configuration: %v", err)
|
|
|
|
}
|
|
|
|
m.storage = cmStorage
|
|
|
|
m.Storage = nil // allow GC to deallocate - TODO: Does this help?
|
|
|
|
}
|
|
|
|
|
2019-06-05 07:43:21 +03:00
|
|
|
m.SetDefaults()
|
2019-04-26 21:35:39 +03:00
|
|
|
|
2019-04-25 22:54:48 +03:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2019-06-05 07:43:21 +03:00
|
|
|
// SetDefaults sets necessary values that are
|
2019-04-26 21:35:39 +03:00
|
|
|
// currently empty to their default values.
|
2019-06-05 07:43:21 +03:00
|
|
|
func (m *ACMEManagerMaker) SetDefaults() {
|
2019-04-26 21:35:39 +03:00
|
|
|
if m.CA == "" {
|
|
|
|
m.CA = certmagic.LetsEncryptStagingCA // certmagic.Default.CA // TODO: When not testing, switch to production CA
|
|
|
|
}
|
|
|
|
if m.Email == "" {
|
|
|
|
m.Email = certmagic.Default.Email
|
|
|
|
}
|
|
|
|
if m.RenewAhead == 0 {
|
|
|
|
m.RenewAhead = caddy2.Duration(certmagic.Default.RenewDurationBefore)
|
|
|
|
}
|
|
|
|
if m.keyType == "" {
|
|
|
|
m.keyType = certmagic.Default.KeyType
|
|
|
|
}
|
|
|
|
if m.storage == nil {
|
|
|
|
m.storage = certmagic.Default.Storage
|
|
|
|
}
|
2019-04-25 22:54:48 +03:00
|
|
|
}
|
|
|
|
|
2019-04-26 21:35:39 +03:00
|
|
|
// makeCertMagicConfig converts m into a certmagic.Config, because
|
|
|
|
// this is a special case where the default manager is the certmagic
|
|
|
|
// Config and not a separate manager.
|
2019-06-05 07:43:21 +03:00
|
|
|
func (m *ACMEManagerMaker) makeCertMagicConfig(ctx caddy2.Context) certmagic.Config {
|
2019-04-26 21:35:39 +03:00
|
|
|
storage := m.storage
|
|
|
|
if storage == nil {
|
2019-05-17 01:05:38 +03:00
|
|
|
storage = ctx.Storage()
|
2019-04-26 21:35:39 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
var ond *certmagic.OnDemandConfig
|
|
|
|
if m.OnDemand != nil {
|
|
|
|
ond = &certmagic.OnDemandConfig{
|
|
|
|
// TODO: fill this out
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return certmagic.Config{
|
2019-05-21 23:22:33 +03:00
|
|
|
CA: m.CA,
|
2019-04-26 21:35:39 +03:00
|
|
|
Email: m.Email,
|
|
|
|
Agreed: true,
|
|
|
|
DisableHTTPChallenge: m.Challenges.HTTP.Disabled,
|
|
|
|
DisableTLSALPNChallenge: m.Challenges.TLSALPN.Disabled,
|
|
|
|
RenewDurationBefore: time.Duration(m.RenewAhead),
|
|
|
|
AltHTTPPort: m.Challenges.HTTP.AlternatePort,
|
|
|
|
AltTLSALPNPort: m.Challenges.TLSALPN.AlternatePort,
|
2019-06-05 07:43:21 +03:00
|
|
|
DNSProvider: m.Challenges.DNS,
|
2019-04-26 21:35:39 +03:00
|
|
|
KeyType: supportedCertKeyTypes[m.KeyType],
|
|
|
|
CertObtainTimeout: time.Duration(m.ACMETimeout),
|
|
|
|
OnDemand: ond,
|
|
|
|
MustStaple: m.MustStaple,
|
|
|
|
Storage: storage,
|
|
|
|
// TODO: listenHost
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// supportedCertKeyTypes is all the key types that are supported
|
|
|
|
// for certificates that are obtained through ACME.
|
|
|
|
var supportedCertKeyTypes = map[string]certcrypto.KeyType{
|
|
|
|
"RSA2048": certcrypto.RSA2048,
|
|
|
|
"RSA4096": certcrypto.RSA4096,
|
|
|
|
"P256": certcrypto.EC256,
|
|
|
|
"P384": certcrypto.EC384,
|
2019-04-25 22:54:48 +03:00
|
|
|
}
|
2019-06-05 07:43:21 +03:00
|
|
|
|
|
|
|
// Interface guard
|
|
|
|
var _ managerMaker = (*ACMEManagerMaker)(nil)
|