pki: Avoid provisioning the local CA when not necessary (#4463)

* pki: Avoid provisioning the `local` CA when not necessary

* pki: Refactor CA loading to keep the logic in the PKI app
This commit is contained in:
Francis Lavoie 2021-12-13 14:25:35 -05:00 committed by GitHub
parent 81ee34e962
commit c04d24cafa
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 59 additions and 20 deletions

View file

@ -102,9 +102,9 @@ func (ash *Handler) Provision(ctx caddy.Context) error {
return err
}
pkiApp := appModule.(*caddypki.PKI)
ca, ok := pkiApp.CAs[ash.CA]
if !ok {
return fmt.Errorf("no certificate authority configured with id: %s", ash.CA)
ca, err := pkiApp.GetCA(ash.CA, &ctx)
if err != nil {
return err
}
database, err := ash.openDatabase()

View file

@ -34,6 +34,8 @@ func init() {
type PKI struct {
// The certificate authorities to manage. Each CA is keyed by an
// ID that is used to uniquely identify it from other CAs.
// At runtime, the GetCA() method should be used instead to ensure
// the default CA is provisioned if it hadn't already been.
// The default CA ID is "local".
CAs map[string]*CA `json:"certificate_authorities,omitempty"`
@ -54,16 +56,6 @@ func (p *PKI) Provision(ctx caddy.Context) error {
p.ctx = ctx
p.log = ctx.Logger(p)
// if this app is initialized at all, ensure there's at
// least a default CA that can be used: the standard CA
// which is used implicitly for signing local-use certs
if p.CAs == nil {
p.CAs = make(map[string]*CA)
}
if _, ok := p.CAs[DefaultCAID]; !ok {
p.CAs[DefaultCAID] = new(CA)
}
for caID, ca := range p.CAs {
err := ca.Provision(ctx, caID, p.log)
if err != nil {
@ -71,9 +63,29 @@ func (p *PKI) Provision(ctx caddy.Context) error {
}
}
// if this app is initialized at all, ensure there's at
// least a default CA that can be used: the standard CA
// which is used implicitly for signing local-use certs
if len(p.CAs) == 0 {
err := p.ProvisionDefaultCA(ctx)
if err != nil {
return fmt.Errorf("provisioning CA '%s': %v", DefaultCAID, err)
}
}
return nil
}
// ProvisionDefaultCA sets up the default CA.
func (p *PKI) ProvisionDefaultCA(ctx caddy.Context) error {
if p.CAs == nil {
p.CAs = make(map[string]*CA)
}
p.CAs[DefaultCAID] = new(CA)
return p.CAs[DefaultCAID].Provision(ctx, DefaultCAID, p.log)
}
// Start starts the PKI app.
func (p *PKI) Start() error {
// install roots to trust store, if not disabled
@ -107,6 +119,32 @@ func (p *PKI) Stop() error {
return nil
}
// GetCA retrieves a CA by ID. If the ID is the default
// CA ID, and it hasn't been provisioned yet, it will
// be provisioned. The context must be passed if this
// is called from a module's Provision().
func (p *PKI) GetCA(id string, ctx *caddy.Context) (*CA, error) {
ca, ok := p.CAs[id]
if !ok {
// for anything other than the default CA ID, error out if it wasn't configured
if id != DefaultCAID {
return nil, fmt.Errorf("no certificate authority configured with id: %s", id)
}
// for the default CA ID, provision it, because we want it to "just work"
if ctx == nil {
return nil, fmt.Errorf("cannot provision default CA without the context")
}
err := p.ProvisionDefaultCA(*ctx)
if err != nil {
return nil, fmt.Errorf("failed to provision default CA: %s", err)
}
ca = p.CAs[id]
}
return ca, nil
}
// Interface guards
var (
_ caddy.Provisioner = (*PKI)(nil)

View file

@ -19,7 +19,6 @@ import (
"context"
"crypto/x509"
"encoding/pem"
"fmt"
"time"
"github.com/caddyserver/caddy/v2"
@ -68,18 +67,20 @@ func (InternalIssuer) CaddyModule() caddy.ModuleInfo {
func (iss *InternalIssuer) Provision(ctx caddy.Context) error {
iss.logger = ctx.Logger(iss)
// set some defaults
if iss.CA == "" {
iss.CA = caddypki.DefaultCAID
}
// get a reference to the configured CA
appModule, err := ctx.App("pki")
if err != nil {
return err
}
pkiApp := appModule.(*caddypki.PKI)
if iss.CA == "" {
iss.CA = caddypki.DefaultCAID
}
ca, ok := pkiApp.CAs[iss.CA]
if !ok {
return fmt.Errorf("no certificate authority configured with id: %s", iss.CA)
ca, err := pkiApp.GetCA(iss.CA, &ctx)
if err != nil {
return err
}
iss.ca = ca