Advertise available profiles in directory resource (#7603)
Change the way profiles are configured at the WFE to allow them to be accompanied by descriptive strings. Augment the construction of the directory resource's "meta" sub-object to include these profile names and descriptions. This config swap is safe, since no Boulder WFE instance is configured with `CertificateProfileNames` yet. Fixes https://github.com/letsencrypt/boulder/issues/7602
This commit is contained in:
parent
848a9ea696
commit
48439e4532
|
|
@ -155,11 +155,11 @@ type Config struct {
|
|||
// the CA and RA configurations.
|
||||
MaxNames int `validate:"min=0,max=100"`
|
||||
|
||||
// CertificateProfileNames is the list of acceptable certificate profile
|
||||
// names for newOrder requests. Requests with a profile name not in this
|
||||
// list will be rejected. This field is optional; if unset, no profile
|
||||
// names are accepted.
|
||||
CertificateProfileNames []string `validate:"omitempty,dive,alphanum,min=1,max=32"`
|
||||
// CertProfiles is a map of acceptable certificate profile names to
|
||||
// descriptions (perhaps including URLs) of those profiles. NewOrder
|
||||
// Requests with a profile name not present in this map will be rejected.
|
||||
// This field is optional; if unset, no profile names are accepted.
|
||||
CertProfiles map[string]string `validate:"omitempty,dive,keys,alphanum,min=1,max=32,endkeys"`
|
||||
}
|
||||
|
||||
Syslog cmd.SyslogConfig
|
||||
|
|
@ -355,7 +355,7 @@ func main() {
|
|||
limiter,
|
||||
txnBuilder,
|
||||
maxNames,
|
||||
c.WFE.CertificateProfileNames,
|
||||
c.WFE.CertProfiles,
|
||||
)
|
||||
cmd.FailOnError(err, "Unable to create WFE")
|
||||
|
||||
|
|
|
|||
|
|
@ -131,9 +131,9 @@
|
|||
"TrackReplacementCertificatesARI": true,
|
||||
"CheckRenewalExemptionAtWFE": true
|
||||
},
|
||||
"certificateProfileNames": [
|
||||
"defaultBoulderCertificateProfile"
|
||||
]
|
||||
"certProfiles": {
|
||||
"defaultBoulderCertificateProfile": "The normal profile you know and love"
|
||||
}
|
||||
},
|
||||
"syslog": {
|
||||
"stdoutlevel": 4,
|
||||
|
|
|
|||
26
wfe2/wfe.go
26
wfe2/wfe.go
|
|
@ -21,6 +21,7 @@ import (
|
|||
"github.com/prometheus/client_golang/prometheus"
|
||||
"go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"
|
||||
"go.opentelemetry.io/otel/trace"
|
||||
"golang.org/x/exp/maps"
|
||||
"google.golang.org/protobuf/types/known/emptypb"
|
||||
|
||||
"github.com/letsencrypt/boulder/core"
|
||||
|
|
@ -29,18 +30,16 @@ import (
|
|||
"github.com/letsencrypt/boulder/features"
|
||||
"github.com/letsencrypt/boulder/goodkey"
|
||||
bgrpc "github.com/letsencrypt/boulder/grpc"
|
||||
"github.com/letsencrypt/boulder/policy"
|
||||
"github.com/letsencrypt/boulder/ratelimits"
|
||||
|
||||
// 'grpc/noncebalancer' is imported for its init function.
|
||||
_ "github.com/letsencrypt/boulder/grpc/noncebalancer"
|
||||
_ "github.com/letsencrypt/boulder/grpc/noncebalancer" // imported for its init function.
|
||||
"github.com/letsencrypt/boulder/identifier"
|
||||
"github.com/letsencrypt/boulder/issuance"
|
||||
blog "github.com/letsencrypt/boulder/log"
|
||||
"github.com/letsencrypt/boulder/metrics/measured_http"
|
||||
"github.com/letsencrypt/boulder/nonce"
|
||||
"github.com/letsencrypt/boulder/policy"
|
||||
"github.com/letsencrypt/boulder/probs"
|
||||
rapb "github.com/letsencrypt/boulder/ra/proto"
|
||||
"github.com/letsencrypt/boulder/ratelimits"
|
||||
"github.com/letsencrypt/boulder/revocation"
|
||||
sapb "github.com/letsencrypt/boulder/sa/proto"
|
||||
"github.com/letsencrypt/boulder/web"
|
||||
|
|
@ -165,10 +164,10 @@ type WebFrontEndImpl struct {
|
|||
txnBuilder *ratelimits.TransactionBuilder
|
||||
maxNames int
|
||||
|
||||
// certificateProfileNames is a list of profile names that are allowed to be
|
||||
// passed to the newOrder endpoint. If a profile name is not in this list,
|
||||
// the request will be rejected as malformed.
|
||||
certificateProfileNames []string
|
||||
// certProfiles is a map of acceptable certificate profile names to
|
||||
// descriptions (perhaps including URLs) of those profiles. NewOrder
|
||||
// Requests with a profile name not present in this map will be rejected.
|
||||
certProfiles map[string]string
|
||||
}
|
||||
|
||||
// NewWebFrontEndImpl constructs a web service for Boulder
|
||||
|
|
@ -192,7 +191,7 @@ func NewWebFrontEndImpl(
|
|||
limiter *ratelimits.Limiter,
|
||||
txnBuilder *ratelimits.TransactionBuilder,
|
||||
maxNames int,
|
||||
certificateProfileNames []string,
|
||||
certProfiles map[string]string,
|
||||
) (WebFrontEndImpl, error) {
|
||||
if len(issuerCertificates) == 0 {
|
||||
return WebFrontEndImpl{}, errors.New("must provide at least one issuer certificate")
|
||||
|
|
@ -230,7 +229,7 @@ func NewWebFrontEndImpl(
|
|||
limiter: limiter,
|
||||
txnBuilder: txnBuilder,
|
||||
maxNames: maxNames,
|
||||
certificateProfileNames: certificateProfileNames,
|
||||
certProfiles: certProfiles,
|
||||
}
|
||||
|
||||
return wfe, nil
|
||||
|
|
@ -550,6 +549,9 @@ func (wfe *WebFrontEndImpl) Directory(
|
|||
wfe.DirectoryCAAIdentity,
|
||||
}
|
||||
}
|
||||
if len(wfe.certProfiles) != 0 {
|
||||
metaMap["profiles"] = wfe.certProfiles
|
||||
}
|
||||
// The "meta" directory entry may also include a string with a website URL
|
||||
if wfe.DirectoryWebsite != "" {
|
||||
metaMap["website"] = wfe.DirectoryWebsite
|
||||
|
|
@ -2190,7 +2192,7 @@ func (wfe *WebFrontEndImpl) validateCertificateProfileName(profile string) error
|
|||
// No profile name is specified.
|
||||
return nil
|
||||
}
|
||||
if !slices.Contains(wfe.certificateProfileNames, profile) {
|
||||
if !slices.Contains(maps.Keys(wfe.certProfiles), profile) {
|
||||
// The profile name is not in the list of configured profiles.
|
||||
return errors.New("not a recognized profile name")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -407,7 +407,7 @@ func setupWFE(t *testing.T) (WebFrontEndImpl, clock.FakeClock, requestSigner) {
|
|||
limiter,
|
||||
txnBuilder,
|
||||
100,
|
||||
[]string{""},
|
||||
nil,
|
||||
)
|
||||
test.AssertNotError(t, err, "Unable to create WFE")
|
||||
|
||||
|
|
@ -3816,7 +3816,7 @@ func TestNewOrderWithProfile(t *testing.T) {
|
|||
expectProfileName := "test-profile"
|
||||
wfe.ra = &mockRA{expectProfileName: expectProfileName}
|
||||
mux := wfe.Handler(metrics.NoopRegisterer)
|
||||
wfe.certificateProfileNames = []string{expectProfileName}
|
||||
wfe.certProfiles = map[string]string{expectProfileName: "description"}
|
||||
|
||||
// Test that the newOrder endpoint returns the proper error if an invalid
|
||||
// profile is specified.
|
||||
|
|
@ -3855,8 +3855,8 @@ func TestNewOrderWithProfile(t *testing.T) {
|
|||
test.AssertNotError(t, err, "Failed to unmarshal order response")
|
||||
test.AssertEquals(t, errorResp1["status"], "valid")
|
||||
|
||||
// Set the acceptable profiles to an empty list, the WFE should no longer accept any profiles.
|
||||
wfe.certificateProfileNames = []string{}
|
||||
// Set the acceptable profiles to the empty set, the WFE should no longer accept any profiles.
|
||||
wfe.certProfiles = map[string]string{}
|
||||
responseWriter = httptest.NewRecorder()
|
||||
r = signAndPost(signer, newOrderPath, "http://localhost"+newOrderPath, validOrderBody)
|
||||
mux.ServeHTTP(responseWriter, r)
|
||||
|
|
|
|||
Loading…
Reference in New Issue