Skip to content

Commit

Permalink
Advertise available profiles in directory resource (#7603)
Browse files Browse the repository at this point in the history
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 #7602
  • Loading branch information
aarongable committed Jul 22, 2024
1 parent 848a9ea commit 48439e4
Show file tree
Hide file tree
Showing 4 changed files with 27 additions and 25 deletions.
12 changes: 6 additions & 6 deletions cmd/boulder-wfe2/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -355,7 +355,7 @@ func main() {
limiter,
txnBuilder,
maxNames,
c.WFE.CertificateProfileNames,
c.WFE.CertProfiles,
)
cmd.FailOnError(err, "Unable to create WFE")

Expand Down
6 changes: 3 additions & 3 deletions test/config-next/wfe2.json
Original file line number Diff line number Diff line change
Expand Up @@ -131,9 +131,9 @@
"TrackReplacementCertificatesARI": true,
"CheckRenewalExemptionAtWFE": true
},
"certificateProfileNames": [
"defaultBoulderCertificateProfile"
]
"certProfiles": {
"defaultBoulderCertificateProfile": "The normal profile you know and love"
}
},
"syslog": {
"stdoutlevel": 4,
Expand Down
26 changes: 14 additions & 12 deletions wfe2/wfe.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -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"
Expand Down Expand Up @@ -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
Expand All @@ -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")
Expand Down Expand Up @@ -230,7 +229,7 @@ func NewWebFrontEndImpl(
limiter: limiter,
txnBuilder: txnBuilder,
maxNames: maxNames,
certificateProfileNames: certificateProfileNames,
certProfiles: certProfiles,
}

return wfe, nil
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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")
}
Expand Down
8 changes: 4 additions & 4 deletions wfe2/wfe_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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")

Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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)
Expand Down

0 comments on commit 48439e4

Please sign in to comment.