Skip to content

Commit

Permalink
pki: Avoid provisioning the local CA when not necessary (#4463)
Browse files Browse the repository at this point in the history
* pki: Avoid provisioning the `local` CA when not necessary

* pki: Refactor CA loading to keep the logic in the PKI app
  • Loading branch information
francislavoie committed Dec 13, 2021
1 parent 81ee34e commit c04d24c
Show file tree
Hide file tree
Showing 3 changed files with 59 additions and 20 deletions.
6 changes: 3 additions & 3 deletions modules/caddypki/acmeserver/acmeserver.go
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down
58 changes: 48 additions & 10 deletions modules/caddypki/pki.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"`

Expand All @@ -54,26 +56,36 @@ 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 {
return fmt.Errorf("provisioning CA '%s': %v", caID, err)
}
}

// 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
Expand Down Expand Up @@ -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)
Expand Down
15 changes: 8 additions & 7 deletions modules/caddytls/internalissuer.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ import (
"context"
"crypto/x509"
"encoding/pem"
"fmt"
"time"

"github.com/caddyserver/caddy/v2"
Expand Down Expand Up @@ -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

Expand Down

0 comments on commit c04d24c

Please sign in to comment.