github.com/letsencrypt/boulder@v0.20251208.0/cmd/nonce-service/main.go (about)

     1  package notmain
     2  
     3  import (
     4  	"context"
     5  	"flag"
     6  	"fmt"
     7  	"net"
     8  	"net/netip"
     9  	"os"
    10  
    11  	"github.com/jmhodges/clock"
    12  
    13  	"github.com/letsencrypt/boulder/cmd"
    14  	bgrpc "github.com/letsencrypt/boulder/grpc"
    15  	"github.com/letsencrypt/boulder/nonce"
    16  	noncepb "github.com/letsencrypt/boulder/nonce/proto"
    17  )
    18  
    19  type Config struct {
    20  	NonceService struct {
    21  		cmd.ServiceConfig
    22  
    23  		MaxUsed int
    24  
    25  		// NonceHMACKey is a path to a file containing an HMAC key which is a
    26  		// secret used for deriving the prefix of each nonce instance. It should
    27  		// contain 256 bits (32 bytes) of random data to be suitable as an
    28  		// HMAC-SHA256 key (e.g. the output of `openssl rand -hex 32`). In a
    29  		// multi-DC deployment this value should be the same across all
    30  		// boulder-wfe and nonce-service instances.
    31  		NonceHMACKey cmd.HMACKeyConfig `validate:"required"`
    32  
    33  		Syslog        cmd.SyslogConfig
    34  		OpenTelemetry cmd.OpenTelemetryConfig
    35  	}
    36  }
    37  
    38  func derivePrefix(key []byte, grpcAddr string) (string, error) {
    39  	host, port, err := net.SplitHostPort(grpcAddr)
    40  	if err != nil {
    41  		return "", fmt.Errorf("parsing gRPC listen address: %w", err)
    42  	}
    43  	if host == "" {
    44  		return "", fmt.Errorf("nonce service gRPC address must include an IP address: got %q", grpcAddr)
    45  	}
    46  	if host != "" && port != "" {
    47  		hostIP, err := netip.ParseAddr(host)
    48  		if err != nil {
    49  			return "", fmt.Errorf("gRPC address host part was not an IP address")
    50  		}
    51  		if hostIP.IsUnspecified() {
    52  			return "", fmt.Errorf("nonce service gRPC address must be a specific IP address: got %q", grpcAddr)
    53  		}
    54  	}
    55  	return nonce.DerivePrefix(grpcAddr, key), nil
    56  }
    57  
    58  func main() {
    59  	grpcAddr := flag.String("addr", "", "gRPC listen address override. Also used to derive the nonce prefix.")
    60  	debugAddr := flag.String("debug-addr", "", "Debug server address override")
    61  	configFile := flag.String("config", "", "File path to the configuration file for this service")
    62  	flag.Parse()
    63  
    64  	if *configFile == "" {
    65  		flag.Usage()
    66  		os.Exit(1)
    67  	}
    68  
    69  	var c Config
    70  	err := cmd.ReadConfigFile(*configFile, &c)
    71  	cmd.FailOnError(err, "Reading JSON config file into config structure")
    72  
    73  	if *grpcAddr != "" {
    74  		c.NonceService.GRPC.Address = *grpcAddr
    75  	}
    76  	if *debugAddr != "" {
    77  		c.NonceService.DebugAddr = *debugAddr
    78  	}
    79  
    80  	key, err := c.NonceService.NonceHMACKey.Load()
    81  	cmd.FailOnError(err, "Failed to load nonceHMACKey file.")
    82  
    83  	noncePrefix, err := derivePrefix(key, c.NonceService.GRPC.Address)
    84  	cmd.FailOnError(err, "Failed to derive nonce prefix")
    85  
    86  	scope, logger, oTelShutdown := cmd.StatsAndLogging(c.NonceService.Syslog, c.NonceService.OpenTelemetry, c.NonceService.DebugAddr)
    87  	defer oTelShutdown(context.Background())
    88  	logger.Info(cmd.VersionString())
    89  
    90  	ns, err := nonce.NewNonceService(scope, c.NonceService.MaxUsed, noncePrefix)
    91  	cmd.FailOnError(err, "Failed to initialize nonce service")
    92  
    93  	tlsConfig, err := c.NonceService.TLS.Load(scope)
    94  	cmd.FailOnError(err, "tlsConfig config")
    95  
    96  	start, err := bgrpc.NewServer(c.NonceService.GRPC, logger).Add(
    97  		&noncepb.NonceService_ServiceDesc, ns).Build(tlsConfig, scope, clock.New())
    98  	cmd.FailOnError(err, "Unable to setup nonce service gRPC server")
    99  
   100  	logger.Info(fmt.Sprintf("Nonce server listening on %s with prefix %q", c.NonceService.GRPC.Address, noncePrefix))
   101  
   102  	cmd.FailOnError(start(), "Nonce service gRPC server failed")
   103  }
   104  
   105  func init() {
   106  	cmd.RegisterCommand("nonce-service", main, &cmd.ConfigValidator{Config: &Config{}})
   107  }