mirror of
https://codeberg.org/Codeberg/pages-server.git
synced 2024-11-18 10:29:43 +00:00
mv acme config setup into own func
This commit is contained in:
parent
77e39b2213
commit
11fa729686
3 changed files with 106 additions and 84 deletions
|
@ -102,7 +102,12 @@ func Serve(ctx *cli.Context) error {
|
||||||
keyCache, challengeCache, dnsLookupCache, canonicalDomainCache,
|
keyCache, challengeCache, dnsLookupCache, canonicalDomainCache,
|
||||||
keyDatabase))
|
keyDatabase))
|
||||||
|
|
||||||
certificates.SetupCertificates(mainDomainSuffix, acmeAPI, acmeMail, acmeEabHmac, acmeEabKID, dnsProvider, acmeUseRateLimits, acmeAcceptTerms, enableHTTPServer, challengeCache, keyDatabase)
|
acmeConfig, err := certificates.SetupAcmeConfig(acmeAPI, acmeMail, acmeEabHmac, acmeEabKID, acmeAcceptTerms)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
certificates.SetupCertificates(mainDomainSuffix, dnsProvider, acmeConfig, acmeUseRateLimits, enableHTTPServer, challengeCache, keyDatabase)
|
||||||
|
|
||||||
if enableHTTPServer {
|
if enableHTTPServer {
|
||||||
go func() {
|
go func() {
|
||||||
|
|
27
server/certificates/acme_account.go
Normal file
27
server/certificates/acme_account.go
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
package certificates
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto"
|
||||||
|
|
||||||
|
"github.com/go-acme/lego/v4/registration"
|
||||||
|
)
|
||||||
|
|
||||||
|
type AcmeAccount struct {
|
||||||
|
Email string
|
||||||
|
Registration *registration.Resource
|
||||||
|
Key crypto.PrivateKey `json:"-"`
|
||||||
|
KeyPEM string `json:"Key"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// make sure AcmeAccount match User interface
|
||||||
|
var _ registration.User = &AcmeAccount{}
|
||||||
|
|
||||||
|
func (u *AcmeAccount) GetEmail() string {
|
||||||
|
return u.Email
|
||||||
|
}
|
||||||
|
func (u AcmeAccount) GetRegistration() *registration.Resource {
|
||||||
|
return u.Registration
|
||||||
|
}
|
||||||
|
func (u *AcmeAccount) GetPrivateKey() crypto.PrivateKey {
|
||||||
|
return u.Key
|
||||||
|
}
|
|
@ -2,7 +2,6 @@ package certificates
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"crypto"
|
|
||||||
"crypto/ecdsa"
|
"crypto/ecdsa"
|
||||||
"crypto/elliptic"
|
"crypto/elliptic"
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
|
@ -12,15 +11,12 @@ import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"log"
|
|
||||||
"os"
|
"os"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/reugn/equalizer"
|
|
||||||
|
|
||||||
"github.com/go-acme/lego/v4/certcrypto"
|
"github.com/go-acme/lego/v4/certcrypto"
|
||||||
"github.com/go-acme/lego/v4/certificate"
|
"github.com/go-acme/lego/v4/certificate"
|
||||||
"github.com/go-acme/lego/v4/challenge"
|
"github.com/go-acme/lego/v4/challenge"
|
||||||
|
@ -28,6 +24,8 @@ import (
|
||||||
"github.com/go-acme/lego/v4/lego"
|
"github.com/go-acme/lego/v4/lego"
|
||||||
"github.com/go-acme/lego/v4/providers/dns"
|
"github.com/go-acme/lego/v4/providers/dns"
|
||||||
"github.com/go-acme/lego/v4/registration"
|
"github.com/go-acme/lego/v4/registration"
|
||||||
|
"github.com/reugn/equalizer"
|
||||||
|
"github.com/rs/zerolog/log"
|
||||||
|
|
||||||
"codeberg.org/codeberg/pages/server/cache"
|
"codeberg.org/codeberg/pages/server/cache"
|
||||||
"codeberg.org/codeberg/pages/server/database"
|
"codeberg.org/codeberg/pages/server/database"
|
||||||
|
@ -147,26 +145,6 @@ func checkUserLimit(user string) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var myAcmeAccount AcmeAccount
|
|
||||||
var myAcmeConfig *lego.Config
|
|
||||||
|
|
||||||
type AcmeAccount struct {
|
|
||||||
Email string
|
|
||||||
Registration *registration.Resource
|
|
||||||
Key crypto.PrivateKey `json:"-"`
|
|
||||||
KeyPEM string `json:"Key"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (u *AcmeAccount) GetEmail() string {
|
|
||||||
return u.Email
|
|
||||||
}
|
|
||||||
func (u AcmeAccount) GetRegistration() *registration.Resource {
|
|
||||||
return u.Registration
|
|
||||||
}
|
|
||||||
func (u *AcmeAccount) GetPrivateKey() crypto.PrivateKey {
|
|
||||||
return u.Key
|
|
||||||
}
|
|
||||||
|
|
||||||
var acmeClient, mainDomainAcmeClient *lego.Client
|
var acmeClient, mainDomainAcmeClient *lego.Client
|
||||||
var acmeClientCertificateLimitPerUser = map[string]*equalizer.TokenBucket{}
|
var acmeClientCertificateLimitPerUser = map[string]*equalizer.TokenBucket{}
|
||||||
|
|
||||||
|
@ -331,15 +309,12 @@ func obtainCert(acmeClient *lego.Client, domains []string, renew *certificate.Re
|
||||||
return tlsCertificate, nil
|
return tlsCertificate, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func SetupCertificates(mainDomainSuffix []byte, acmeAPI, acmeMail, acmeEabHmac, acmeEabKID, dnsProvider string, acmeUseRateLimits, acmeAcceptTerms, enableHTTPServer bool, challengeCache cache.SetGetKey, keyDatabase database.KeyDB) {
|
func SetupAcmeConfig(acmeAPI, acmeMail, acmeEabHmac, acmeEabKID string, acmeAcceptTerms bool) (*lego.Config, error) {
|
||||||
// getting main cert before ACME account so that we can panic here on database failure without hitting rate limits
|
const configFile = "acme-account.json"
|
||||||
mainCertBytes, err := keyDatabase.Get(mainDomainSuffix)
|
var myAcmeAccount AcmeAccount
|
||||||
if err != nil {
|
var myAcmeConfig *lego.Config
|
||||||
// key database is not working
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if account, err := ioutil.ReadFile("acme-account.json"); err == nil {
|
if account, err := ioutil.ReadFile(configFile); err == nil {
|
||||||
err = json.Unmarshal(account, &myAcmeAccount)
|
err = json.Unmarshal(account, &myAcmeAccount)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
|
@ -351,66 +326,81 @@ func SetupCertificates(mainDomainSuffix []byte, acmeAPI, acmeMail, acmeEabHmac,
|
||||||
myAcmeConfig = lego.NewConfig(&myAcmeAccount)
|
myAcmeConfig = lego.NewConfig(&myAcmeAccount)
|
||||||
myAcmeConfig.CADirURL = acmeAPI
|
myAcmeConfig.CADirURL = acmeAPI
|
||||||
myAcmeConfig.Certificate.KeyType = certcrypto.RSA2048
|
myAcmeConfig.Certificate.KeyType = certcrypto.RSA2048
|
||||||
|
|
||||||
|
// Validate Config
|
||||||
_, err := lego.NewClient(myAcmeConfig)
|
_, err := lego.NewClient(myAcmeConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
// TODO: should we fail hard instead?
|
||||||
log.Printf("[ERROR] Can't create ACME client, continuing with mock certs only: %s", err)
|
log.Printf("[ERROR] Can't create ACME client, continuing with mock certs only: %s", err)
|
||||||
}
|
}
|
||||||
} else if os.IsNotExist(err) {
|
return myAcmeConfig, nil
|
||||||
privateKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
|
} else if !os.IsNotExist(err) {
|
||||||
if err != nil {
|
return nil, err
|
||||||
panic(err)
|
}
|
||||||
}
|
|
||||||
myAcmeAccount = AcmeAccount{
|
|
||||||
Email: acmeMail,
|
|
||||||
Key: privateKey,
|
|
||||||
KeyPEM: string(certcrypto.PEMEncode(privateKey)),
|
|
||||||
}
|
|
||||||
myAcmeConfig = lego.NewConfig(&myAcmeAccount)
|
|
||||||
myAcmeConfig.CADirURL = acmeAPI
|
|
||||||
myAcmeConfig.Certificate.KeyType = certcrypto.RSA2048
|
|
||||||
tempClient, err := lego.NewClient(myAcmeConfig)
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("[ERROR] Can't create ACME client, continuing with mock certs only: %s", err)
|
|
||||||
} else {
|
|
||||||
// accept terms & log in to EAB
|
|
||||||
if acmeEabKID == "" || acmeEabHmac == "" {
|
|
||||||
reg, err := tempClient.Registration.Register(registration.RegisterOptions{TermsOfServiceAgreed: acmeAcceptTerms})
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("[ERROR] Can't register ACME account, continuing with mock certs only: %s", err)
|
|
||||||
} else {
|
|
||||||
myAcmeAccount.Registration = reg
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
reg, err := tempClient.Registration.RegisterWithExternalAccountBinding(registration.RegisterEABOptions{
|
|
||||||
TermsOfServiceAgreed: acmeAcceptTerms,
|
|
||||||
Kid: acmeEabKID,
|
|
||||||
HmacEncoded: acmeEabHmac,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("[ERROR] Can't register ACME account, continuing with mock certs only: %s", err)
|
|
||||||
} else {
|
|
||||||
myAcmeAccount.Registration = reg
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if myAcmeAccount.Registration != nil {
|
privateKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
|
||||||
acmeAccountJson, err := json.Marshal(myAcmeAccount)
|
if err != nil {
|
||||||
if err != nil {
|
panic(err)
|
||||||
log.Printf("[FAIL] Error during json.Marshal(myAcmeAccount), waiting for manual restart to avoid rate limits: %s", err)
|
}
|
||||||
select {}
|
myAcmeAccount = AcmeAccount{
|
||||||
}
|
Email: acmeMail,
|
||||||
err = ioutil.WriteFile("acme-account.json", acmeAccountJson, 0600)
|
Key: privateKey,
|
||||||
if err != nil {
|
KeyPEM: string(certcrypto.PEMEncode(privateKey)),
|
||||||
log.Printf("[FAIL] Error during ioutil.WriteFile(\"acme-account.json\"), waiting for manual restart to avoid rate limits: %s", err)
|
}
|
||||||
select {}
|
myAcmeConfig = lego.NewConfig(&myAcmeAccount)
|
||||||
}
|
myAcmeConfig.CADirURL = acmeAPI
|
||||||
|
myAcmeConfig.Certificate.KeyType = certcrypto.RSA2048
|
||||||
|
tempClient, err := lego.NewClient(myAcmeConfig)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("[ERROR] Can't create ACME client, continuing with mock certs only: %s", err)
|
||||||
|
} else {
|
||||||
|
// accept terms & log in to EAB
|
||||||
|
if acmeEabKID == "" || acmeEabHmac == "" {
|
||||||
|
reg, err := tempClient.Registration.Register(registration.RegisterOptions{TermsOfServiceAgreed: acmeAcceptTerms})
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("[ERROR] Can't register ACME account, continuing with mock certs only: %s", err)
|
||||||
|
} else {
|
||||||
|
myAcmeAccount.Registration = reg
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
reg, err := tempClient.Registration.RegisterWithExternalAccountBinding(registration.RegisterEABOptions{
|
||||||
|
TermsOfServiceAgreed: acmeAcceptTerms,
|
||||||
|
Kid: acmeEabKID,
|
||||||
|
HmacEncoded: acmeEabHmac,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("[ERROR] Can't register ACME account, continuing with mock certs only: %s", err)
|
||||||
|
} else {
|
||||||
|
myAcmeAccount.Registration = reg
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
|
if myAcmeAccount.Registration != nil {
|
||||||
|
acmeAccountJson, err := json.Marshal(myAcmeAccount)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("[FAIL] Error during json.Marshal(myAcmeAccount), waiting for manual restart to avoid rate limits: %s", err)
|
||||||
|
select {}
|
||||||
|
}
|
||||||
|
err = ioutil.WriteFile(configFile, acmeAccountJson, 0600)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("[FAIL] Error during ioutil.WriteFile(\"acme-account.json\"), waiting for manual restart to avoid rate limits: %s", err)
|
||||||
|
select {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return myAcmeConfig, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func SetupCertificates(mainDomainSuffix []byte, dnsProvider string, acmeConfig *lego.Config, acmeUseRateLimits, enableHTTPServer bool, challengeCache cache.SetGetKey, keyDatabase database.KeyDB) {
|
||||||
|
// getting main cert before ACME account so that we can panic here on database failure without hitting rate limits
|
||||||
|
mainCertBytes, err := keyDatabase.Get(mainDomainSuffix)
|
||||||
|
if err != nil {
|
||||||
|
// key database is not working
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
acmeClient, err = lego.NewClient(myAcmeConfig)
|
acmeClient, err = lego.NewClient(acmeConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("[ERROR] Can't create ACME client, continuing with mock certs only: %s", err)
|
log.Printf("[ERROR] Can't create ACME client, continuing with mock certs only: %s", err)
|
||||||
} else {
|
} else {
|
||||||
|
@ -426,7 +416,7 @@ func SetupCertificates(mainDomainSuffix []byte, acmeAPI, acmeMail, acmeEabHmac,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mainDomainAcmeClient, err = lego.NewClient(myAcmeConfig)
|
mainDomainAcmeClient, err = lego.NewClient(acmeConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("[ERROR] Can't create ACME client, continuing with mock certs only: %s", err)
|
log.Printf("[ERROR] Can't create ACME client, continuing with mock certs only: %s", err)
|
||||||
} else {
|
} else {
|
||||||
|
|
Loading…
Reference in a new issue