boulder/features/features.go

157 lines
6.5 KiB
Go

// features provides the Config struct, which is used to define feature flags
// that can affect behavior across Boulder components. It also maintains a
// global singleton Config which can be referenced by arbitrary Boulder code
// without having to pass a collection of feature flags through the function
// call graph.
package features
import (
"sync"
)
// Config contains one boolean field for every Boulder feature flag. It can be
// included directly in an executable's Config struct to have feature flags be
// automatically parsed by the json config loader; executables that do so must
// then call features.Set(parsedConfig) to load the parsed struct into this
// package's global Config.
type Config struct {
// Deprecated features. These features have no effect. Removing them from
// configuration is safe.
//
// Once all references to them have been removed from deployed configuration,
// they can be deleted from this struct, after which Boulder will fail to
// start if they are present in configuration.
CAAAfterValidation bool
AllowNoCommonName bool
SHA256SubjectKeyIdentifier bool
EnforceMultiVA bool
MultiVAFullResults bool
CertCheckerRequiresCorrespondence bool
ECDSAForAll bool
// ServeRenewalInfo exposes the renewalInfo endpoint in the directory and for
// GET requests. WARNING: This feature is a draft and highly unstable.
ServeRenewalInfo bool
// ExpirationMailerUsesJoin enables using a JOIN query in expiration-mailer
// rather than a SELECT from certificateStatus followed by thousands of
// one-row SELECTs from certificates.
ExpirationMailerUsesJoin bool
// CertCheckerChecksValidations enables an extra query for each certificate
// checked, to find the relevant authzs. Since this query might be
// expensive, we gate it behind a feature flag.
CertCheckerChecksValidations bool
// CertCheckerRequiresValidations causes cert-checker to fail if the
// query enabled by CertCheckerChecksValidations didn't find corresponding
// authorizations.
CertCheckerRequiresValidations bool
// AsyncFinalize enables the RA to return approximately immediately from
// requests to finalize orders. This allows us to take longer getting SCTs,
// issuing certs, and updating the database; it indirectly reduces the number
// of issuances that fail due to timeouts during storage. However, it also
// requires clients to properly implement polling the Order object to wait
// for the cert URL to appear.
AsyncFinalize bool
// DOH enables DNS-over-HTTPS queries for validation
DOH bool
// EnforceMultiCAA causes the VA to kick off remote CAA rechecks when true.
// When false, no remote CAA rechecks will be performed. The primary VA will
// make a valid/invalid decision with the results. The primary VA will
// return an early decision if MultiCAAFullResults is false.
EnforceMultiCAA bool
// MultiCAAFullResults will cause the main VA to block and wait for all of
// the remote VA CAA recheck results instead of returning early if the
// number of failures is greater than the configured
// maxRemoteValidationFailures. Only used when EnforceMultiCAA is true.
MultiCAAFullResults bool
// TrackReplacementCertificatesARI, when enabled, triggers the following
// behavior:
// - SA.NewOrderAndAuthzs: upon receiving a NewOrderRequest with a
// 'replacesSerial' value, will create a new entry in the 'replacement
// Orders' table. This will occur inside of the new order transaction.
// - SA.FinalizeOrder will update the 'replaced' column of any row with
// a 'orderID' matching the finalized order to true. This will occur
// inside of the finalize (order) transaction.
TrackReplacementCertificatesARI bool
// MultipleCertificateProfiles, when enabled, triggers the following
// behavior:
// - SA.NewOrderAndAuthzs: upon receiving a NewOrderRequest with a
// `certificateProfileName` value, will add that value to the database's
// `orders.certificateProfileName` column. Values in this column are
// allowed to be empty.
MultipleCertificateProfiles bool
// CheckRenewalExemptionAtWFE when enabled, triggers the following behavior:
// - WFE.NewOrder: checks if the order is a renewal and if so skips checks
// for NewOrdersPerAccount and NewOrdersPerDomain limits.
// - RA.NewOrderAndAuthzs: skips checks for legacy NewOrdersPerAccount and
// NewOrdersPerDomain limits if the WFE indicates that the order is a
// renewal.
//
// TODO(#7511): Remove this feature flag.
CheckRenewalExemptionAtWFE bool
// CheckIdentifiersPaused checks if any of the identifiers in the order are
// currently paused at NewOrder time. If any are paused, an error is
// returned to the Subscriber indicating that the order cannot be processed
// until the paused identifiers are unpaused and the order is resubmitted.
CheckIdentifiersPaused bool
// UseKvLimitsForNewOrder when enabled, causes the key-value rate limiter to
// be the authoritative source of rate limiting information for new-order
// callers and disables the legacy rate limiting checks.
//
// Note: this flag does not disable writes to the certificatesPerName or
// fqdnSets tables at Finalize time.
UseKvLimitsForNewOrder bool
// UseKvLimitsForNewAccount when enabled, causes the key-value rate limiter
// to be the authoritative source of rate limiting information for
// new-account callers and disables the legacy rate limiting checks.
UseKvLimitsForNewAccount bool
}
var fMu = new(sync.RWMutex)
var global = Config{}
// Set changes the global FeatureSet to match the input FeatureSet. This
// overrides any previous changes made to the global FeatureSet.
//
// When used in tests, the caller must defer features.Reset() to avoid leaving
// dirty global state.
func Set(fs Config) {
fMu.Lock()
defer fMu.Unlock()
// If the FeatureSet type ever changes, this must be updated to still copy
// the input argument, never hold a reference to it.
global = fs
}
// Reset resets all features to their initial state (false).
func Reset() {
fMu.Lock()
defer fMu.Unlock()
global = Config{}
}
// Get returns a copy of the current global FeatureSet, indicating which
// features are currently enabled (set to true). Expected caller behavior looks
// like:
//
// if features.Get().FeatureName { ...
func Get() Config {
fMu.RLock()
defer fMu.RUnlock()
// If the FeatureSet type ever changes, this must be updated to still return
// only a copy of the current state, never a reference directly to it.
return global
}