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

     1  package notmain
     2  
     3  import (
     4  	"context"
     5  	"flag"
     6  	"fmt"
     7  	"os"
     8  	"runtime"
     9  
    10  	ct "github.com/google/certificate-transparency-go"
    11  	"github.com/jmhodges/clock"
    12  
    13  	"github.com/letsencrypt/boulder/cmd"
    14  	"github.com/letsencrypt/boulder/features"
    15  	bgrpc "github.com/letsencrypt/boulder/grpc"
    16  	"github.com/letsencrypt/boulder/issuance"
    17  	"github.com/letsencrypt/boulder/publisher"
    18  	pubpb "github.com/letsencrypt/boulder/publisher/proto"
    19  )
    20  
    21  type Config struct {
    22  	Publisher struct {
    23  		cmd.ServiceConfig
    24  		Features features.Config
    25  
    26  		// If this is non-zero, profile blocking events such that one even is
    27  		// sampled every N nanoseconds.
    28  		// https://golang.org/pkg/runtime/#SetBlockProfileRate
    29  		BlockProfileRate int
    30  		UserAgent        string
    31  
    32  		// Chains is a list of lists of certificate filenames. Each inner list is
    33  		// a chain, starting with the issuing intermediate, followed by one or
    34  		// more additional certificates, up to and including a root.
    35  		Chains [][]string `validate:"min=1,dive,min=2,dive,required"`
    36  	}
    37  
    38  	Syslog        cmd.SyslogConfig
    39  	OpenTelemetry cmd.OpenTelemetryConfig
    40  }
    41  
    42  func main() {
    43  	grpcAddr := flag.String("addr", "", "gRPC listen address override")
    44  	debugAddr := flag.String("debug-addr", "", "Debug server address override")
    45  	configFile := flag.String("config", "", "File path to the configuration file for this service")
    46  	flag.Parse()
    47  	if *configFile == "" {
    48  		flag.Usage()
    49  		os.Exit(1)
    50  	}
    51  
    52  	var c Config
    53  	err := cmd.ReadConfigFile(*configFile, &c)
    54  	cmd.FailOnError(err, "Reading JSON config file into config structure")
    55  	features.Set(c.Publisher.Features)
    56  
    57  	runtime.SetBlockProfileRate(c.Publisher.BlockProfileRate)
    58  
    59  	if *grpcAddr != "" {
    60  		c.Publisher.GRPC.Address = *grpcAddr
    61  	}
    62  	if *debugAddr != "" {
    63  		c.Publisher.DebugAddr = *debugAddr
    64  	}
    65  	if c.Publisher.UserAgent == "" {
    66  		c.Publisher.UserAgent = "certificate-transparency-go/1.0"
    67  	}
    68  	scope, logger, oTelShutdown := cmd.StatsAndLogging(c.Syslog, c.OpenTelemetry, c.Publisher.DebugAddr)
    69  	defer oTelShutdown(context.Background())
    70  	logger.Info(cmd.VersionString())
    71  
    72  	if c.Publisher.Chains == nil {
    73  		logger.AuditErr("No chain files provided")
    74  		os.Exit(1)
    75  	}
    76  
    77  	bundles := make(map[issuance.NameID][]ct.ASN1Cert)
    78  	for _, files := range c.Publisher.Chains {
    79  		chain, err := issuance.LoadChain(files)
    80  		cmd.FailOnError(err, "failed to load chain.")
    81  		issuer := chain[0]
    82  		id := issuer.NameID()
    83  		if _, exists := bundles[id]; exists {
    84  			cmd.Fail(fmt.Sprintf("Got multiple chains configured for issuer %q", issuer.Subject.CommonName))
    85  		}
    86  		bundles[id] = publisher.GetCTBundleForChain(chain)
    87  	}
    88  
    89  	tlsConfig, err := c.Publisher.TLS.Load(scope)
    90  	cmd.FailOnError(err, "TLS config")
    91  
    92  	clk := clock.New()
    93  
    94  	pubi := publisher.New(bundles, c.Publisher.UserAgent, logger, scope)
    95  
    96  	start, err := bgrpc.NewServer(c.Publisher.GRPC, logger).Add(
    97  		&pubpb.Publisher_ServiceDesc, pubi).Build(tlsConfig, scope, clk)
    98  	cmd.FailOnError(err, "Unable to setup Publisher gRPC server")
    99  
   100  	cmd.FailOnError(start(), "Publisher gRPC service failed")
   101  }
   102  
   103  func init() {
   104  	cmd.RegisterCommand("boulder-publisher", main, &cmd.ConfigValidator{Config: &Config{}})
   105  }