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

WFE/nonce: Add NonceHMACKey field #7793

Merged
merged 11 commits into from
Nov 13, 2024
22 changes: 19 additions & 3 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 @@ -295,9 +305,15 @@ func main() {
}

var noncePrefixKey string
jprenken marked this conversation as resolved.
Show resolved Hide resolved
if c.WFE.NoncePrefixKey.PasswordFile != "" {
if c.WFE.NonceHMACKey.KeyFile != "" {
keyByte, err := c.WFE.NonceHMACKey.Load()
cmd.FailOnError(err, "Failed to load nonceHMACKey file")
noncePrefixKey = string(keyByte)
} else if c.WFE.NoncePrefixKey.PasswordFile != "" {
noncePrefixKey, err = c.WFE.NoncePrefixKey.Pass()
cmd.FailOnError(err, "Failed to load noncePrefixKey")
cmd.FailOnError(err, "Failed to load noncePrefixKey file")
} 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
36 changes: 22 additions & 14 deletions cmd/nonce-service/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,23 +19,25 @@ 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
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 string
jprenken marked this conversation as resolved.
Show resolved Hide resolved
if c.NonceService.NonceHMACKey.KeyFile != "" {
keyByte, err := c.NonceService.NonceHMACKey.Load()
cmd.FailOnError(err, "Failed to load 'nonceHMACKey' file.")
key = string(keyByte)
} else if c.NonceService.NoncePrefixKey.PasswordFile != "" {
key, err = c.NonceService.NoncePrefixKey.Pass()
cmd.FailOnError(err, "Failed to load 'noncePrefixKey' file.")
} 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
4 changes: 2 additions & 2 deletions test/config-next/nonce-a.json
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
{
"NonceService": {
"maxUsed": 131072,
"noncePrefixKey": {
"passwordFile": "test/secrets/nonce_prefix_key"
"nonceHMACKey": {
"keyFile": "test/secrets/nonce_prefix_key"
},
"syslog": {
"stdoutLevel": 6,
Expand Down
4 changes: 2 additions & 2 deletions test/config-next/nonce-b.json
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
{
"NonceService": {
"maxUsed": 131072,
"noncePrefixKey": {
"passwordFile": "test/secrets/nonce_prefix_key"
"nonceHMACKey": {
"keyFile": "test/secrets/nonce_prefix_key"
},
"syslog": {
"stdoutLevel": 6,
Expand Down
4 changes: 2 additions & 2 deletions test/config-next/wfe2.json
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,8 @@
"noWaitForReady": true,
"hostOverride": "nonce.boulder"
},
"noncePrefixKey": {
"passwordFile": "test/secrets/nonce_prefix_key"
"nonceHMACKey": {
"keyFile": "test/secrets/nonce_prefix_key"
},
"chains": [
[
Expand Down
1 change: 0 additions & 1 deletion test/config/nonce-a.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
{
"NonceService": {
"maxUsed": 131072,
"useDerivablePrefix": true,
"noncePrefixKey": {
"passwordFile": "test/secrets/nonce_prefix_key"
},
Expand Down
1 change: 0 additions & 1 deletion test/config/nonce-b.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
{
"NonceService": {
"maxUsed": 131072,
"useDerivablePrefix": true,
"noncePrefixKey": {
"passwordFile": "test/secrets/nonce_prefix_key"
},
Expand Down
11 changes: 9 additions & 2 deletions test/integration/nonce_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ type nonceBalancerTestConfig struct {
GetNonceService *cmd.GRPCClientConfig
RedeemNonceService *cmd.GRPCClientConfig
NoncePrefixKey cmd.PasswordConfig
NonceHMACKey cmd.HMACKeyConfig
}
}

Expand All @@ -41,8 +42,14 @@ func TestNonceBalancer_NoBackendMatchingPrefix(t *testing.T) {
tlsConfig, err := c.NotWFE.TLS.Load(metrics.NoopRegisterer)
test.AssertNotError(t, err, "Could not load TLS config")

rncKey, err := c.NotWFE.NoncePrefixKey.Pass()
test.AssertNotError(t, err, "Failed to load noncePrefixKey")
var rncKey string
rncKeyByte, err := c.NotWFE.NonceHMACKey.Load()
if err != nil {
rncKey, err = c.NotWFE.NoncePrefixKey.Pass()
test.AssertNotError(t, err, "Failed to load nonceHMACKey or noncePrefixKey")
} else {
rncKey = string(rncKeyByte)
}

clk := clock.New()

Expand Down
4 changes: 2 additions & 2 deletions test/integration/testdata/nonce-client.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@
"noWaitForReady": true,
"hostOverride": "nonce.boulder"
},
"noncePrefixKey": {
"passwordFile": "test/secrets/nonce_prefix_key"
"nonceHMACKey": {
"keyFile": "test/secrets/nonce_prefix_key"
}
}
}
2 changes: 1 addition & 1 deletion test/secrets/nonce_prefix_key
Original file line number Diff line number Diff line change
@@ -1 +1 @@
3b8c758dd85e113ea340ce0b3a99f389d40a308548af94d1730a7692c1874f1f
3b8c758dd85e113ea340ce0b3a99f389