Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RA: Clean up deprecated validation configuration #7992

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 3 additions & 47 deletions cmd/boulder-ra/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import (
"context"
"flag"
"os"
"time"

akamaipb "github.com/letsencrypt/boulder/akamai/proto"
"github.com/letsencrypt/boulder/allowlist"
Expand Down Expand Up @@ -81,37 +80,18 @@ type Config struct {
// configurations.
MaxNames int `validate:"required,min=1,max=100"`

// AuthorizationLifetimeDays defines how long authorizations will be
// considered valid for. Given a value of 300 days when used with a 90-day
// cert lifetime, this allows creation of certs that will cover a whole
// year, plus a grace period of a month.
//
// Deprecated: use ValidationProfiles.[profile].ValidAuthzLifetime instead.
// TODO(#7986): Remove this.
AuthorizationLifetimeDays int `validate:"omitempty,required_without=ValidationProfiles,min=1,max=397"`

// PendingAuthorizationLifetimeDays defines how long authorizations may be in
// the pending state. If you can't respond to a challenge this quickly, then
// you need to request a new challenge.
//
// Deprecated: use ValidationProfiles.[profile].PendingAuthzLifetime instead.
// TODO(#7986): Remove this.
PendingAuthorizationLifetimeDays int `validate:"omitempty,required_without=ValidationProfiles,min=1,max=29"`

// ValidationProfiles is a map of validation profiles to their
// respective issuance allow lists. If a profile is not included in this
// mapping, it cannot be used by any account. If this field is left
// empty, all profiles are open to all accounts.
// TODO(#7986): Make this field required.
ValidationProfiles map[string]ra.ValidationProfileConfig `validate:"omitempty"`
ValidationProfiles map[string]ra.ValidationProfileConfig `validate:"required"`

// DefaultProfileName sets the profile to use if one wasn't provided by the
// client in the new-order request. Must match a configured validation
// profile or the RA will fail to start. Must match a certificate profile
// configured in the CA or finalization will fail for orders using this
// default.
// TODO(#7986): Make this field unconditionally required.
DefaultProfileName string `validate:"required_with=ValidationProfiles"`
DefaultProfileName string `validate:"required"`

// MustStapleAllowList specifies the path to a YAML file containing a
// list of account IDs permitted to request certificates with the OCSP
Expand All @@ -123,13 +103,6 @@ type Config struct {
// GoodKey is an embedded config stanza for the goodkey library.
GoodKey goodkey.Config

// OrderLifetime is how far in the future an Order's expiration date should
// be set when it is first created.
//
// Deprecated: Use ValidationProfiles.[profile].OrderLifetime instead.
// TODO(#7986): Remove this.
OrderLifetime config.Duration `validate:"omitempty,required_without=ValidationProfiles"`

// FinalizeTimeout is how long the RA is willing to wait for the Order
// finalization process to take. This config parameter only has an effect
// if the AsyncFinalization feature flag is enabled. Any systems which
Expand Down Expand Up @@ -266,25 +239,8 @@ func main() {

ctp = ctpolicy.New(pubc, sctLogs, infoLogs, finalLogs, c.RA.CTLogs.Stagger.Duration, logger, scope)

// TODO(#7986): Remove this fallback, error out if no default is configured.
if c.RA.DefaultProfileName == "" {
c.RA.DefaultProfileName = ra.UnconfiguredDefaultProfileName
}
logger.Infof("Configured default profile name set to: %s", c.RA.DefaultProfileName)

// TODO(#7986): Remove this fallback, error out if no profiles are configured.
if len(c.RA.ValidationProfiles) == 0 {
c.RA.ValidationProfiles = map[string]ra.ValidationProfileConfig{
c.RA.DefaultProfileName: {
PendingAuthzLifetime: config.Duration{
Duration: time.Duration(c.RA.PendingAuthorizationLifetimeDays) * 24 * time.Hour},
ValidAuthzLifetime: config.Duration{
Duration: time.Duration(c.RA.AuthorizationLifetimeDays) * 24 * time.Hour},
OrderLifetime: c.RA.OrderLifetime,
// Leave the allowlist empty, so all accounts have access to this
// default profile.
},
}
cmd.Fail("At least one profile must be configured")
}

validationProfiles, err := ra.NewValidationProfiles(c.RA.DefaultProfileName, c.RA.ValidationProfiles)
Expand Down
16 changes: 5 additions & 11 deletions ra/ra.go
Original file line number Diff line number Diff line change
Expand Up @@ -275,12 +275,6 @@ func NewRegistrationAuthorityImpl(
return ra
}

// UnconfiguredDefaultProfileName is a unique string which the RA can use to
// identify a profile, but also detect that no profiles were explicitly
// configured, and therefore should not be assumed to exist outside the RA.
// TODO(#7986): Remove this when the defaultProfileName config is required.
const UnconfiguredDefaultProfileName = "unconfiguredDefaultProfileName"

// ValidationProfileConfig is a config struct which can be used to create a
// ValidationProfile.
type ValidationProfileConfig struct {
Expand Down Expand Up @@ -340,6 +334,10 @@ type validationProfiles struct {
// configs and default name. It enforces that the given authorization lifetimes
// are within the bounds mandated by the Baseline Requirements.
func NewValidationProfiles(defaultName string, configs map[string]ValidationProfileConfig) (*validationProfiles, error) {
if defaultName == "" {
return nil, errors.New("default profile name must be configured")
}

profiles := make(map[string]*validationProfile, len(configs))

for name, config := range configs {
Expand Down Expand Up @@ -1188,12 +1186,8 @@ func (ra *RegistrationAuthorityImpl) issueCertificateOuter(
logEvent.PreviousCertificateIssued = timestamps.Timestamps[0].AsTime()
}

// If the order didn't request a specific profile and we have a default
// configured, provide it to the CA so we can stop relying on the CA's
// configured default.
// TODO(#7309): Make this unconditional.
profileName := order.CertificateProfileName
if profileName == "" && ra.profiles.defaultName != UnconfiguredDefaultProfileName {
if profileName == "" {
profileName = ra.profiles.defaultName
}

Expand Down
16 changes: 13 additions & 3 deletions test/config/ra.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,9 @@
"debugAddr": ":8002",
"hostnamePolicyFile": "test/hostname-policy.yaml",
"maxNames": 100,
"authorizationLifetimeDays": 30,
"pendingAuthorizationLifetimeDays": 7,
"goodkey": {
"fermatRounds": 100
},
"orderLifetime": "168h",
"issuerCerts": [
"test/certs/webpki/int-rsa-a.cert.pem",
"test/certs/webpki/int-rsa-b.cert.pem",
Expand All @@ -43,6 +40,19 @@
"test/certs/webpki/int-ecdsa-b.cert.pem",
"test/certs/webpki/int-ecdsa-c.cert.pem"
],
"validationProfiles": {
"legacy": {
"pendingAuthzLifetime": "168h",
"validAuthzLifetime": "720h",
"orderLifetime": "168h"
},
"modern": {
"pendingAuthzLifetime": "7h",
"validAuthzLifetime": "7h",
"orderLifetime": "7h"
}
},
"defaultProfileName": "legacy",
"tls": {
"caCertFile": "test/certs/ipki/minica.pem",
"certFile": "test/certs/ipki/ra.boulder/cert.pem",
Expand Down
Loading