1
0
Fork 0

Add KV datastore

Signed-off-by: Emile Vauge <emile@vauge.com>
This commit is contained in:
Emile Vauge 2016-08-16 19:13:18 +02:00
parent 38b62d4ae3
commit 5a0440d6f8
No known key found for this signature in database
GPG key ID: D808B4C167352E59
21 changed files with 498 additions and 46 deletions

View file

@ -173,6 +173,7 @@ type ACME struct {
storageLock sync.RWMutex
client *acme.Client
account *Account
defaultCertificate *tls.Certificate
}
//Domains parse []Domain
@ -216,28 +217,50 @@ type Domain struct {
SANs []string
}
// CreateConfig creates a tls.config from using ACME configuration
func (a *ACME) CreateConfig(tlsConfig *tls.Config, CheckOnDemandDomain func(domain string) bool) error {
func (a *ACME) init() error {
if len(a.Store) == 0 {
a.Store = a.StorageFile
}
acme.Logger = fmtlog.New(ioutil.Discard, "", 0)
if len(a.StorageFile) == 0 {
return errors.New("Empty StorageFile, please provide a filename for certs storage")
}
log.Debugf("Generating default certificate...")
if len(tlsConfig.Certificates) == 0 {
// no certificates in TLS config, so we add a default one
cert, err := generateDefaultCertificate()
if err != nil {
return err
}
tlsConfig.Certificates = append(tlsConfig.Certificates, *cert)
// no certificates in TLS config, so we add a default one
cert, err := generateDefaultCertificate()
if err != nil {
return err
}
a.defaultCertificate = cert
return nil
}
// CreateClusterConfig creates a tls.config from using ACME configuration
func (a *ACME) CreateClusterConfig(tlsConfig *tls.Config, CheckOnDemandDomain func(domain string) bool) error {
err := a.init()
if err != nil {
return err
}
if len(a.Store) == 0 {
return errors.New("Empty Store, please provide a filename/key for certs storage")
}
tlsConfig.Certificates = append(tlsConfig.Certificates, *a.defaultCertificate)
return nil
}
// CreateLocalConfig creates a tls.config from using ACME configuration
func (a *ACME) CreateLocalConfig(tlsConfig *tls.Config, CheckOnDemandDomain func(domain string) bool) error {
err := a.init()
if err != nil {
return err
}
if len(a.Store) == 0 {
return errors.New("Empty Store, please provide a filename/key for certs storage")
}
tlsConfig.Certificates = append(tlsConfig.Certificates, *a.defaultCertificate)
var needRegister bool
var err error
// if certificates in storage, load them
if fileInfo, err := os.Stat(a.StorageFile); err == nil && fileInfo.Size() != 0 {
if fileInfo, fileErr := os.Stat(a.Store); fileErr == nil && fileInfo.Size() != 0 {
log.Infof("Loading ACME certificates...")
// load account
a.account, err = a.loadAccount(a)
@ -265,7 +288,10 @@ func (a *ACME) CreateConfig(tlsConfig *tls.Config, CheckOnDemandDomain func(doma
}
a.client.ExcludeChallenges([]acme.Challenge{acme.HTTP01, acme.DNS01})
wrapperChallengeProvider := newWrapperChallengeProvider()
a.client.SetChallengeProvider(acme.TLSSNI01, wrapperChallengeProvider)
err = client.SetChallengeProvider(acme.TLSSNI01, wrapperChallengeProvider)
if err != nil {
return err
}
if needRegister {
// New users will need to register; be sure to save it
@ -322,12 +348,9 @@ func (a *ACME) CreateConfig(tlsConfig *tls.Config, CheckOnDemandDomain func(doma
ticker := time.NewTicker(24 * time.Hour)
safe.Go(func() {
for {
select {
case <-ticker.C:
if err := a.renewCertificates(a.client); err != nil {
log.Errorf("Error renewing ACME certificate %+v: %s", a.account, err.Error())
}
for range ticker.C {
if err := a.renewCertificates(client, account); err != nil {
log.Errorf("Error renewing ACME certificate %+v: %s", account, err.Error())
}
}
@ -470,22 +493,22 @@ func (a *ACME) LoadCertificateForDomains(domains []string) {
func (a *ACME) loadAccount(acmeConfig *ACME) (*Account, error) {
a.storageLock.RLock()
defer a.storageLock.RUnlock()
Account := Account{
account := Account{
DomainsCertificate: DomainsCertificates{},
}
file, err := ioutil.ReadFile(acmeConfig.StorageFile)
file, err := ioutil.ReadFile(acmeConfig.Store)
if err != nil {
return nil, err
}
if err := json.Unmarshal(file, &Account); err != nil {
if err := json.Unmarshal(file, &account); err != nil {
return nil, err
}
err = Account.DomainsCertificate.init()
err = account.DomainsCertificate.init()
if err != nil {
return nil, err
}
log.Infof("Loaded ACME config from storage %s", acmeConfig.StorageFile)
return &Account, nil
log.Infof("Loaded ACME config from store %s", acmeConfig.Store)
return &account, nil
}
func (a *ACME) saveAccount() error {
@ -496,7 +519,7 @@ func (a *ACME) saveAccount() error {
if err != nil {
return err
}
return ioutil.WriteFile(a.StorageFile, data, 0600)
return ioutil.WriteFile(a.Store, data, 0600)
}
func (a *ACME) getDomainsCertificates(client *acme.Client, domains []string) (*Certificate, error) {

View file

@ -8,18 +8,20 @@ import (
"github.com/xenolf/lego/acme"
)
type wrapperChallengeProvider struct {
var _ acme.ChallengeProvider = (*inMemoryChallengeProvider)(nil)
type inMemoryChallengeProvider struct {
challengeCerts map[string]*tls.Certificate
lock sync.RWMutex
}
func newWrapperChallengeProvider() *wrapperChallengeProvider {
return &wrapperChallengeProvider{
func newWrapperChallengeProvider() *inMemoryChallengeProvider {
return &inMemoryChallengeProvider{
challengeCerts: map[string]*tls.Certificate{},
}
}
func (c *wrapperChallengeProvider) getCertificate(domain string) (cert *tls.Certificate, exists bool) {
func (c *inMemoryChallengeProvider) getCertificate(domain string) (cert *tls.Certificate, exists bool) {
c.lock.RLock()
defer c.lock.RUnlock()
if cert, ok := c.challengeCerts[domain]; ok {
@ -28,7 +30,7 @@ func (c *wrapperChallengeProvider) getCertificate(domain string) (cert *tls.Cert
return nil, false
}
func (c *wrapperChallengeProvider) Present(domain, token, keyAuth string) error {
func (c *inMemoryChallengeProvider) Present(domain, token, keyAuth string) error {
cert, _, err := acme.TLSSNI01ChallengeCert(keyAuth)
if err != nil {
return err
@ -45,10 +47,9 @@ func (c *wrapperChallengeProvider) Present(domain, token, keyAuth string) error
}
return nil
}
func (c *wrapperChallengeProvider) CleanUp(domain, token, keyAuth string) error {
func (c *inMemoryChallengeProvider) CleanUp(domain, token, keyAuth string) error {
c.lock.Lock()
defer c.lock.Unlock()
delete(c.challengeCerts, domain)