Skip to content

Commit

Permalink
Merge branch 'main' into limit-is-a-pointer
Browse files Browse the repository at this point in the history
  • Loading branch information
beautifulentropy authored Nov 13, 2024
2 parents f4c5ac4 + 26a9910 commit 032c976
Show file tree
Hide file tree
Showing 25 changed files with 155 additions and 116 deletions.
26 changes: 21 additions & 5 deletions cmd/boulder-wfe2/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,13 +71,23 @@ type Config struct {
// local and remote nonce-service instances.
RedeemNonceService *cmd.GRPCClientConfig `validate:"required"`

// NonceHMACKey is a path to a file containing an HMAC key which is a
// secret used for deriving the prefix of each nonce instance. It should
// contain 256 bits (32 bytes) of random data to be suitable as an
// HMAC-SHA256 key (e.g. the output of `openssl rand -hex 32`). In a
// multi-DC deployment this value should be the same across all
// boulder-wfe and nonce-service instances.
NonceHMACKey cmd.HMACKeyConfig `validate:"-"`

// NoncePrefixKey is a secret used for deriving the prefix of each nonce
// instance. It should contain 256 bits of random data to be suitable as
// an HMAC-SHA256 key (e.g. the output of `openssl rand -hex 32`). In a
// multi-DC deployment this value should be the same across all
// boulder-wfe and nonce-service instances.
//
// TODO(#7632) Update this to use the new HMACKeyConfig.
// TODO(#7632): Remove this.
//
// Deprecated: Use NonceHMACKey instead.
NoncePrefixKey cmd.PasswordConfig `validate:"-"`

// Chains is a list of lists of certificate filenames. Each inner list is
Expand Down Expand Up @@ -294,10 +304,16 @@ func main() {
cmd.Fail("'getNonceService' must be configured")
}

var noncePrefixKey string
if c.WFE.NoncePrefixKey.PasswordFile != "" {
noncePrefixKey, err = c.WFE.NoncePrefixKey.Pass()
cmd.FailOnError(err, "Failed to load noncePrefixKey")
var noncePrefixKey []byte
if c.WFE.NonceHMACKey.KeyFile != "" {
noncePrefixKey, err = c.WFE.NonceHMACKey.Load()
cmd.FailOnError(err, "Failed to load nonceHMACKey file")
} else if c.WFE.NoncePrefixKey.PasswordFile != "" {
keyString, err := c.WFE.NoncePrefixKey.Pass()
cmd.FailOnError(err, "Failed to load noncePrefixKey file")
noncePrefixKey = []byte(keyString)
} else {
cmd.Fail("NonceHMACKey KeyFile or NoncePrefixKey PasswordFile must be set")
}

getNonceConn, err := bgrpc.ClientSetup(c.WFE.GetNonceService, tlsConfig, stats, clk)
Expand Down
2 changes: 1 addition & 1 deletion cmd/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -572,7 +572,7 @@ func (hc *HMACKeyConfig) Load() ([]byte, error) {

if len(trimmed) != 32 {
return nil, fmt.Errorf(
"validating unpauseHMACKey, length must be 32 alphanumeric characters, got %d",
"validating HMAC key, length must be 32 alphanumeric characters, got %d",
len(trimmed),
)
}
Expand Down
38 changes: 23 additions & 15 deletions cmd/nonce-service/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,30 +19,32 @@ type Config struct {

MaxUsed int

// UseDerivablePrefix indicates whether to use a nonce prefix derived
// from the gRPC listening address. If this is false, the nonce prefix
// will be the value of the NoncePrefix field. If this is true, the
// NoncePrefixKey field is required.
// TODO(#6610): Remove this.
//
// Deprecated: this value is ignored, and treated as though it is always true.
UseDerivablePrefix bool `validate:"-"`
// NonceHMACKey is a path to a file containing an HMAC key which is a
// secret used for deriving the prefix of each nonce instance. It should
// contain 256 bits (32 bytes) of random data to be suitable as an
// HMAC-SHA256 key (e.g. the output of `openssl rand -hex 32`). In a
// multi-DC deployment this value should be the same across all
// boulder-wfe and nonce-service instances.
NonceHMACKey cmd.HMACKeyConfig `validate:"required_without_all=NoncePrefixKey,structonly"`

// NoncePrefixKey is a secret used for deriving the prefix of each nonce
// instance. It should contain 256 bits (32 bytes) of random data to be
// suitable as an HMAC-SHA256 key (e.g. the output of `openssl rand -hex
// 32`). In a multi-DC deployment this value should be the same across
// all boulder-wfe and nonce-service instances.
//
// TODO(#7632) Update this to use the new HMACKeyConfig.
NoncePrefixKey cmd.PasswordConfig `validate:"required"`
// TODO(#7632): Remove this and change `NonceHMACKey`'s validation to
// just `required.`
//
// Deprecated: Use NonceHMACKey instead.
NoncePrefixKey cmd.PasswordConfig `validate:"required_without_all=NonceHMACKey,structonly"`

Syslog cmd.SyslogConfig
OpenTelemetry cmd.OpenTelemetryConfig
}
}

func derivePrefix(key string, grpcAddr string) (string, error) {
func derivePrefix(key []byte, grpcAddr string) (string, error) {
host, port, err := net.SplitHostPort(grpcAddr)
if err != nil {
return "", fmt.Errorf("parsing gRPC listen address: %w", err)
Expand Down Expand Up @@ -84,12 +86,18 @@ func main() {
c.NonceService.DebugAddr = *debugAddr
}

if c.NonceService.NoncePrefixKey.PasswordFile == "" {
cmd.Fail("NoncePrefixKey PasswordFile must be set")
var key []byte
if c.NonceService.NonceHMACKey.KeyFile != "" {
key, err = c.NonceService.NonceHMACKey.Load()
cmd.FailOnError(err, "Failed to load 'nonceHMACKey' file.")
} else if c.NonceService.NoncePrefixKey.PasswordFile != "" {
keyString, err := c.NonceService.NoncePrefixKey.Pass()
cmd.FailOnError(err, "Failed to load 'noncePrefixKey' file.")
key = []byte(keyString)
} else {
cmd.Fail("NonceHMACKey KeyFile or NoncePrefixKey PasswordFile must be set")
}

key, err := c.NonceService.NoncePrefixKey.Pass()
cmd.FailOnError(err, "Failed to load 'noncePrefixKey' file.")
noncePrefix, err := derivePrefix(key, c.NonceService.GRPC.Address)
cmd.FailOnError(err, "Failed to derive nonce prefix")

Expand Down
17 changes: 0 additions & 17 deletions features/features.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,23 +15,6 @@ import (
// 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
CheckRenewalExemptionAtWFE bool
TrackReplacementCertificatesARI bool
UseKvLimitsForNewAccount bool

// ServeRenewalInfo exposes the renewalInfo endpoint in the directory and for
// GET requests. WARNING: This feature is a draft and highly unstable.
ServeRenewalInfo bool
Expand Down
4 changes: 2 additions & 2 deletions grpc/noncebalancer/noncebalancer.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ var ErrNoBackendsMatchPrefix = status.New(codes.Unavailable, "no backends match
var errMissingPrefixCtxKey = errors.New("nonce.PrefixCtxKey value required in RPC context")
var errMissingHMACKeyCtxKey = errors.New("nonce.HMACKeyCtxKey value required in RPC context")
var errInvalidPrefixCtxKeyType = errors.New("nonce.PrefixCtxKey value in RPC context must be a string")
var errInvalidHMACKeyCtxKeyType = errors.New("nonce.HMACKeyCtxKey value in RPC context must be a string")
var errInvalidHMACKeyCtxKeyType = errors.New("nonce.HMACKeyCtxKey value in RPC context must be a byte slice")

// Balancer implements the base.PickerBuilder interface. It's used to create new
// balancer.Picker instances. It should only be used by nonce-service clients.
Expand Down Expand Up @@ -84,7 +84,7 @@ func (p *Picker) Pick(info balancer.PickInfo) (balancer.PickResult, error) {
// This should never happen.
return balancer.PickResult{}, errMissingHMACKeyCtxKey
}
hmacKey, ok := hmacKeyVal.(string)
hmacKey, ok := hmacKeyVal.([]byte)
if !ok {
// This should never happen.
return balancer.PickResult{}, errInvalidHMACKeyCtxKeyType
Expand Down
19 changes: 10 additions & 9 deletions grpc/noncebalancer/noncebalancer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,20 @@ import (
"context"
"testing"

"github.com/letsencrypt/boulder/nonce"
"github.com/letsencrypt/boulder/test"
"google.golang.org/grpc/balancer"
"google.golang.org/grpc/balancer/base"
"google.golang.org/grpc/resolver"

"github.com/letsencrypt/boulder/nonce"
"github.com/letsencrypt/boulder/test"
)

func TestPickerPicksCorrectBackend(t *testing.T) {
_, p, subConns := setupTest(false)
prefix := nonce.DerivePrefix(subConns[0].addrs[0].Addr, "Kala namak")
prefix := nonce.DerivePrefix(subConns[0].addrs[0].Addr, []byte("Kala namak"))

testCtx := context.WithValue(context.Background(), nonce.PrefixCtxKey{}, "HNmOnt8w")
testCtx = context.WithValue(testCtx, nonce.HMACKeyCtxKey{}, prefix)
testCtx = context.WithValue(testCtx, nonce.HMACKeyCtxKey{}, []byte(prefix))
info := balancer.PickInfo{Ctx: testCtx}

gotPick, err := p.Pick(info)
Expand All @@ -26,9 +27,9 @@ func TestPickerPicksCorrectBackend(t *testing.T) {

func TestPickerMissingPrefixInCtx(t *testing.T) {
_, p, subConns := setupTest(false)
prefix := nonce.DerivePrefix(subConns[0].addrs[0].Addr, "Kala namak")
prefix := nonce.DerivePrefix(subConns[0].addrs[0].Addr, []byte("Kala namak"))

testCtx := context.WithValue(context.Background(), nonce.HMACKeyCtxKey{}, prefix)
testCtx := context.WithValue(context.Background(), nonce.HMACKeyCtxKey{}, []byte(prefix))
info := balancer.PickInfo{Ctx: testCtx}

gotPick, err := p.Pick(info)
Expand All @@ -40,7 +41,7 @@ func TestPickerInvalidPrefixInCtx(t *testing.T) {
_, p, _ := setupTest(false)

testCtx := context.WithValue(context.Background(), nonce.PrefixCtxKey{}, 9)
testCtx = context.WithValue(testCtx, nonce.HMACKeyCtxKey{}, "foobar")
testCtx = context.WithValue(testCtx, nonce.HMACKeyCtxKey{}, []byte("foobar"))
info := balancer.PickInfo{Ctx: testCtx}

gotPick, err := p.Pick(info)
Expand Down Expand Up @@ -73,10 +74,10 @@ func TestPickerInvalidHMACKeyInCtx(t *testing.T) {

func TestPickerNoMatchingSubConnAvailable(t *testing.T) {
_, p, subConns := setupTest(false)
prefix := nonce.DerivePrefix(subConns[0].addrs[0].Addr, "Kala namak")
prefix := nonce.DerivePrefix(subConns[0].addrs[0].Addr, []byte("Kala namak"))

testCtx := context.WithValue(context.Background(), nonce.PrefixCtxKey{}, "rUsTrUin")
testCtx = context.WithValue(testCtx, nonce.HMACKeyCtxKey{}, prefix)
testCtx = context.WithValue(testCtx, nonce.HMACKeyCtxKey{}, []byte(prefix))
info := balancer.PickInfo{Ctx: testCtx}

gotPick, err := p.Pick(info)
Expand Down
4 changes: 2 additions & 2 deletions nonce/nonce.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,8 @@ type HMACKeyCtxKey struct{}
// DerivePrefix derives a nonce prefix from the provided listening address and
// key. The prefix is derived by take the first 8 characters of the base64url
// encoded HMAC-SHA256 hash of the listening address using the provided key.
func DerivePrefix(grpcAddr, key string) string {
h := hmac.New(sha256.New, []byte(key))
func DerivePrefix(grpcAddr string, key []byte) string {
h := hmac.New(sha256.New, key)
h.Write([]byte(grpcAddr))
return base64.RawURLEncoding.EncodeToString(h.Sum(nil))[:PrefixLen]
}
Expand Down
2 changes: 1 addition & 1 deletion nonce/nonce_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,6 @@ func TestNoncePrefixValidation(t *testing.T) {
}

func TestDerivePrefix(t *testing.T) {
prefix := DerivePrefix("192.168.1.1:8080", "3b8c758dd85e113ea340ce0b3a99f389d40a308548af94d1730a7692c1874f1f")
prefix := DerivePrefix("192.168.1.1:8080", []byte("3b8c758dd85e113ea340ce0b3a99f389d40a308548af94d1730a7692c1874f1f"))
test.AssertEquals(t, prefix, "P9qQaK4o")
}
4 changes: 4 additions & 0 deletions ratelimits/limit.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@ import (
// currently configured.
var errLimitDisabled = errors.New("limit disabled")

// limit defines the configuration for a rate limit or a rate limit override.
//
// The zero value of this struct is invalid, because some of the fields must
// be greater than zero.
type limit struct {
// Burst specifies maximum concurrent allowed requests at any given time. It
// must be greater than zero.
Expand Down
Loading

0 comments on commit 032c976

Please sign in to comment.