From cd60afb8fb222eeda80aa0cf718044fc9cd9a279 Mon Sep 17 00:00:00 2001 From: Francis Lavoie Date: Sun, 28 Nov 2021 15:56:15 -0500 Subject: [PATCH] httpcaddyfile: Support configuring `pki` app names via global options --- caddyconfig/httpcaddyfile/pkiapp.go | 94 ++++++++++++++++++- .../global_options_skip_install_trust.txt | 86 +++++++++++++++++ 2 files changed, 177 insertions(+), 3 deletions(-) diff --git a/caddyconfig/httpcaddyfile/pkiapp.go b/caddyconfig/httpcaddyfile/pkiapp.go index a21951db154..dad5ddde861 100644 --- a/caddyconfig/httpcaddyfile/pkiapp.go +++ b/caddyconfig/httpcaddyfile/pkiapp.go @@ -16,23 +16,106 @@ package httpcaddyfile import ( "github.com/caddyserver/caddy/v2/caddyconfig" + "github.com/caddyserver/caddy/v2/caddyconfig/caddyfile" "github.com/caddyserver/caddy/v2/modules/caddypki" ) +func init() { + RegisterGlobalOption("pki", parsePKIApp) +} + +// parsePKIApp parses the global log option. Syntax: +// +// pki [id] { +// name +// root_common_name +// intermediate_common_name +// } +// +// When the CA ID is unspecified, 'local' is assumed. +// +func parsePKIApp(d *caddyfile.Dispenser, existingVal interface{}) (interface{}, error) { + var pki *caddypki.PKI + if existingVal != nil { + unwrappedPki, ok := existingVal.(*caddypki.PKI) + if !ok { + return nil, d.Errf("failed to unwrap existing PKI value") + } + pki = unwrappedPki + } else { + pki = &caddypki.PKI{CAs: make(map[string]*caddypki.CA)} + } + + pkiCa := new(caddypki.CA) + for d.Next() { + if d.NextArg() { + pkiCa.ID = d.Val() + if d.NextArg() { + return nil, d.ArgErr() + } + } + for nesting := d.Nesting(); d.NextBlock(nesting); { + switch d.Val() { + case "name": + if !d.NextArg() { + return nil, d.ArgErr() + } + pkiCa.Name = d.Val() + + case "root_common_name": + if !d.NextArg() { + return nil, d.ArgErr() + } + pkiCa.Name = d.Val() + + case "intermediate_common_name": + if !d.NextArg() { + return nil, d.ArgErr() + } + pkiCa.Name = d.Val() + + default: + return nil, d.Errf("unrecognized pki option '%s'", d.Val()) + } + } + } + if pkiCa.ID == "" { + pkiCa.ID = caddypki.DefaultCAID + } + + pki.CAs[pkiCa.ID] = pkiCa + + return pki, nil +} + func (st ServerType) buildPKIApp( pairings []sbAddrAssociation, options map[string]interface{}, warnings []caddyconfig.Warning, ) (*caddypki.PKI, []caddyconfig.Warning, error) { - pkiApp := &caddypki.PKI{CAs: make(map[string]*caddypki.CA)} - skipInstallTrust := false if _, ok := options["skip_install_trust"]; ok { skipInstallTrust = true } falseBool := false + // Load the PKI app configured via global options + var pkiApp *caddypki.PKI + unwrappedPki, ok := options["pki"].(*caddypki.PKI) + if ok { + pkiApp = unwrappedPki + } else { + pkiApp = &caddypki.PKI{CAs: make(map[string]*caddypki.CA)} + } + for _, ca := range pkiApp.CAs { + if skipInstallTrust { + ca.InstallTrust = &falseBool + } + pkiApp.CAs[ca.ID] = ca + } + + // Add in the CAs configured via directives for _, p := range pairings { for _, sblock := range p.serverBlocks { // find all the CAs that were defined and add them to the app config @@ -42,7 +125,12 @@ func (st ServerType) buildPKIApp( if skipInstallTrust { ca.InstallTrust = &falseBool } - pkiApp.CAs[ca.ID] = ca + + // the CA might already exist from global options, so + // don't overwrite it in that case + if _, ok := pkiApp.CAs[ca.ID]; !ok { + pkiApp.CAs[ca.ID] = ca + } } } } diff --git a/caddytest/integration/caddyfile_adapt/global_options_skip_install_trust.txt b/caddytest/integration/caddyfile_adapt/global_options_skip_install_trust.txt index f949ac1af75..469cecaffd5 100644 --- a/caddytest/integration/caddyfile_adapt/global_options_skip_install_trust.txt +++ b/caddytest/integration/caddyfile_adapt/global_options_skip_install_trust.txt @@ -1,10 +1,32 @@ { skip_install_trust + pki { + name "Local" + root_common_name "Custom Local Root Name" + intermediate_common_name "Custom Local Intermediate Name" + } + pki foo { + name "Foo" + root_common_name "Custom Foo Root Name" + intermediate_common_name "Custom Foo Intermediate Name" + } } a.example.com { tls internal } + +acme.example.com { + acme_server { + ca foo + } +} + +acme-bar.example.com { + acme_server { + ca bar + } +} ---------- { "apps": { @@ -15,6 +37,56 @@ a.example.com { ":443" ], "routes": [ + { + "match": [ + { + "host": [ + "acme-bar.example.com" + ] + } + ], + "handle": [ + { + "handler": "subroute", + "routes": [ + { + "handle": [ + { + "ca": "bar", + "handler": "acme_server" + } + ] + } + ] + } + ], + "terminal": true + }, + { + "match": [ + { + "host": [ + "acme.example.com" + ] + } + ], + "handle": [ + { + "handler": "subroute", + "routes": [ + { + "handle": [ + { + "ca": "foo", + "handler": "acme_server" + } + ] + } + ] + } + ], + "terminal": true + }, { "match": [ { @@ -31,7 +103,15 @@ a.example.com { }, "pki": { "certificate_authorities": { + "bar": { + "install_trust": false + }, + "foo": { + "name": "Custom Foo Intermediate Name", + "install_trust": false + }, "local": { + "name": "Custom Local Intermediate Name", "install_trust": false } } @@ -39,6 +119,12 @@ a.example.com { "tls": { "automation": { "policies": [ + { + "subjects": [ + "acme-bar.example.com", + "acme.example.com" + ] + }, { "subjects": [ "a.example.com"