...

Source file src/github.com/letsencrypt/boulder/cmd/crl-updater/main.go

Documentation: github.com/letsencrypt/boulder/cmd/crl-updater

     1  package notmain
     2  
     3  import (
     4  	"context"
     5  	"errors"
     6  	"flag"
     7  	"os"
     8  	"time"
     9  
    10  	capb "github.com/letsencrypt/boulder/ca/proto"
    11  	"github.com/letsencrypt/boulder/cmd"
    12  	"github.com/letsencrypt/boulder/config"
    13  	cspb "github.com/letsencrypt/boulder/crl/storer/proto"
    14  	"github.com/letsencrypt/boulder/crl/updater"
    15  	"github.com/letsencrypt/boulder/features"
    16  	bgrpc "github.com/letsencrypt/boulder/grpc"
    17  	"github.com/letsencrypt/boulder/issuance"
    18  	sapb "github.com/letsencrypt/boulder/sa/proto"
    19  )
    20  
    21  type Config struct {
    22  	CRLUpdater struct {
    23  		DebugAddr string
    24  
    25  		// TLS client certificate, private key, and trusted root bundle.
    26  		TLS cmd.TLSConfig
    27  
    28  		SAService           *cmd.GRPCClientConfig
    29  		CRLGeneratorService *cmd.GRPCClientConfig
    30  		CRLStorerService    *cmd.GRPCClientConfig
    31  
    32  		// IssuerCerts is a list of paths to issuer certificates on disk. This
    33  		// controls the set of CRLs which will be published by this updater: it will
    34  		// publish one set of NumShards CRL shards for each issuer in this list.
    35  		IssuerCerts []string `validate:"min=1,dive,required"`
    36  
    37  		// NumShards is the number of shards into which each issuer's "full and
    38  		// complete" CRL will be split.
    39  		// WARNING: When this number is changed, the "JSON Array of CRL URLs" field
    40  		// in CCADB MUST be updated.
    41  		NumShards int `validate:"min=1"`
    42  
    43  		// ShardWidth is the amount of time (width on a timeline) that a single
    44  		// shard should cover. Ideally, NumShards*ShardWidth should be an amount of
    45  		// time noticeably larger than the current longest certificate lifetime,
    46  		// but the updater will continue to work if this is not the case (albeit
    47  		// with more confusing mappings of serials to shards).
    48  		// WARNING: When this number is changed, revocation entries will move
    49  		// between shards.
    50  		ShardWidth config.Duration `validate:"-"`
    51  
    52  		// LookbackPeriod is how far back the updater should look for revoked expired
    53  		// certificates. We are required to include every revoked cert in at least
    54  		// one CRL, even if it is revoked seconds before it expires, so this must
    55  		// always be greater than the UpdatePeriod, and should be increased when
    56  		// recovering from an outage to ensure continuity of coverage.
    57  		LookbackPeriod config.Duration `validate:"-"`
    58  
    59  		// CertificateLifetime is the validity period (usually expressed in hours,
    60  		// like "2160h") of the longest-lived currently-unexpired certificate. For
    61  		// Let's Encrypt, this is usually ninety days. If the validity period of
    62  		// the issued certificates ever changes upwards, this value must be updated
    63  		// immediately; if the validity period of the issued certificates ever
    64  		// changes downwards, the value must not change until after all certificates with
    65  		// the old validity period have expired.
    66  		// DEPRECATED: This config value is no longer used.
    67  		// TODO(#6438): Remove this value.
    68  		CertificateLifetime config.Duration `validate:"-"`
    69  
    70  		// UpdatePeriod controls how frequently the crl-updater runs and publishes
    71  		// new versions of every CRL shard. The Baseline Requirements, Section 4.9.7
    72  		// state that this MUST NOT be more than 7 days. We believe that future
    73  		// updates may require that this not be more than 24 hours, and currently
    74  		// recommend an UpdatePeriod of 6 hours.
    75  		UpdatePeriod config.Duration
    76  
    77  		// UpdateOffset controls the times at which crl-updater runs, to avoid
    78  		// scheduling the batch job at exactly midnight. The updater runs every
    79  		// UpdatePeriod, starting from the Unix Epoch plus UpdateOffset, and
    80  		// continuing forward into the future forever. This value must be strictly
    81  		// less than the UpdatePeriod.
    82  		// DEPRECATED: This config value is not relevant with continuous updating.
    83  		// TODO(#7023): Remove this value.
    84  		UpdateOffset config.Duration `validate:"-"`
    85  
    86  		// UpdateTimeout controls how long a single CRL shard is allowed to attempt
    87  		// to update before being timed out. The total CRL updating process may take
    88  		// significantly longer, since a full update cycle may consist of updating
    89  		// many shards with varying degrees of parallelism. This value must be
    90  		// strictly less than the UpdatePeriod. Defaults to 10 minutes, one order
    91  		// of magnitude greater than our p99 update latency.
    92  		UpdateTimeout config.Duration `validate:"-"`
    93  
    94  		// MaxParallelism controls how many workers may be running in parallel.
    95  		// A higher value reduces the total time necessary to update all CRL shards
    96  		// that this updater is responsible for, but also increases the memory used
    97  		// by this updater. Only relevant in -runOnce mode.
    98  		MaxParallelism int `validate:"min=0"`
    99  
   100  		// MaxAttempts control how many times the updater will attempt to generate
   101  		// a single CRL shard. A higher number increases the likelihood of a fully
   102  		// successful run, but also increases the worst-case runtime and db/network
   103  		// load of said run. The default is 1.
   104  		MaxAttempts int `validate:"omitempty,min=1"`
   105  
   106  		Features map[string]bool
   107  	}
   108  
   109  	Syslog        cmd.SyslogConfig
   110  	OpenTelemetry cmd.OpenTelemetryConfig
   111  }
   112  
   113  func main() {
   114  	configFile := flag.String("config", "", "File path to the configuration file for this service")
   115  	debugAddr := flag.String("debug-addr", "", "Debug server address override")
   116  	runOnce := flag.Bool("runOnce", false, "If true, run once immediately and then exit")
   117  	flag.Parse()
   118  	if *configFile == "" {
   119  		flag.Usage()
   120  		os.Exit(1)
   121  	}
   122  
   123  	var c Config
   124  	err := cmd.ReadConfigFile(*configFile, &c)
   125  	cmd.FailOnError(err, "Reading JSON config file into config structure")
   126  
   127  	if *debugAddr != "" {
   128  		c.CRLUpdater.DebugAddr = *debugAddr
   129  	}
   130  
   131  	err = features.Set(c.CRLUpdater.Features)
   132  	cmd.FailOnError(err, "Failed to set feature flags")
   133  
   134  	scope, logger, oTelShutdown := cmd.StatsAndLogging(c.Syslog, c.OpenTelemetry, c.CRLUpdater.DebugAddr)
   135  	defer oTelShutdown(context.Background())
   136  	logger.Info(cmd.VersionString())
   137  	clk := cmd.Clock()
   138  
   139  	tlsConfig, err := c.CRLUpdater.TLS.Load(scope)
   140  	cmd.FailOnError(err, "TLS config")
   141  
   142  	issuers := make([]*issuance.Certificate, 0, len(c.CRLUpdater.IssuerCerts))
   143  	for _, filepath := range c.CRLUpdater.IssuerCerts {
   144  		cert, err := issuance.LoadCertificate(filepath)
   145  		cmd.FailOnError(err, "Failed to load issuer cert")
   146  		issuers = append(issuers, cert)
   147  	}
   148  
   149  	if c.CRLUpdater.ShardWidth.Duration == 0 {
   150  		c.CRLUpdater.ShardWidth.Duration = 16 * time.Hour
   151  	}
   152  	if c.CRLUpdater.LookbackPeriod.Duration == 0 {
   153  		c.CRLUpdater.LookbackPeriod.Duration = 24 * time.Hour
   154  	}
   155  	if c.CRLUpdater.UpdateTimeout.Duration == 0 {
   156  		c.CRLUpdater.UpdateTimeout.Duration = 10 * time.Minute
   157  	}
   158  
   159  	saConn, err := bgrpc.ClientSetup(c.CRLUpdater.SAService, tlsConfig, scope, clk)
   160  	cmd.FailOnError(err, "Failed to load credentials and create gRPC connection to SA")
   161  	sac := sapb.NewStorageAuthorityClient(saConn)
   162  
   163  	caConn, err := bgrpc.ClientSetup(c.CRLUpdater.CRLGeneratorService, tlsConfig, scope, clk)
   164  	cmd.FailOnError(err, "Failed to load credentials and create gRPC connection to CRLGenerator")
   165  	cac := capb.NewCRLGeneratorClient(caConn)
   166  
   167  	csConn, err := bgrpc.ClientSetup(c.CRLUpdater.CRLStorerService, tlsConfig, scope, clk)
   168  	cmd.FailOnError(err, "Failed to load credentials and create gRPC connection to CRLStorer")
   169  	csc := cspb.NewCRLStorerClient(csConn)
   170  
   171  	u, err := updater.NewUpdater(
   172  		issuers,
   173  		c.CRLUpdater.NumShards,
   174  		c.CRLUpdater.ShardWidth.Duration,
   175  		c.CRLUpdater.LookbackPeriod.Duration,
   176  		c.CRLUpdater.UpdatePeriod.Duration,
   177  		c.CRLUpdater.UpdateTimeout.Duration,
   178  		c.CRLUpdater.MaxParallelism,
   179  		c.CRLUpdater.MaxAttempts,
   180  		sac,
   181  		cac,
   182  		csc,
   183  		scope,
   184  		logger,
   185  		clk,
   186  	)
   187  	cmd.FailOnError(err, "Failed to create crl-updater")
   188  
   189  	ctx, cancel := context.WithCancel(context.Background())
   190  	go cmd.CatchSignals(cancel)
   191  
   192  	if *runOnce {
   193  		err = u.RunOnce(ctx)
   194  		if err != nil && !errors.Is(err, context.Canceled) {
   195  			cmd.FailOnError(err, "")
   196  		}
   197  	} else {
   198  		err = u.Run(ctx)
   199  		if err != nil && !errors.Is(err, context.Canceled) {
   200  			cmd.FailOnError(err, "")
   201  		}
   202  	}
   203  }
   204  
   205  func init() {
   206  	cmd.RegisterCommand("crl-updater", main, &cmd.ConfigValidator{Config: &Config{}})
   207  }
   208  

View as plain text