...

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

Documentation: github.com/letsencrypt/boulder/cmd/boulder-ra

     1  package notmain
     2  
     3  import (
     4  	"context"
     5  	"flag"
     6  	"os"
     7  	"time"
     8  
     9  	akamaipb "github.com/letsencrypt/boulder/akamai/proto"
    10  	capb "github.com/letsencrypt/boulder/ca/proto"
    11  	"github.com/letsencrypt/boulder/cmd"
    12  	"github.com/letsencrypt/boulder/config"
    13  	"github.com/letsencrypt/boulder/ctpolicy"
    14  	"github.com/letsencrypt/boulder/ctpolicy/ctconfig"
    15  	"github.com/letsencrypt/boulder/ctpolicy/loglist"
    16  	"github.com/letsencrypt/boulder/features"
    17  	"github.com/letsencrypt/boulder/goodkey"
    18  	"github.com/letsencrypt/boulder/goodkey/sagoodkey"
    19  	bgrpc "github.com/letsencrypt/boulder/grpc"
    20  	"github.com/letsencrypt/boulder/issuance"
    21  	"github.com/letsencrypt/boulder/policy"
    22  	pubpb "github.com/letsencrypt/boulder/publisher/proto"
    23  	"github.com/letsencrypt/boulder/ra"
    24  	rapb "github.com/letsencrypt/boulder/ra/proto"
    25  	sapb "github.com/letsencrypt/boulder/sa/proto"
    26  	vapb "github.com/letsencrypt/boulder/va/proto"
    27  )
    28  
    29  type Config struct {
    30  	RA struct {
    31  		cmd.ServiceConfig
    32  		cmd.HostnamePolicyConfig
    33  
    34  		RateLimitPoliciesFilename string `validate:"required"`
    35  
    36  		MaxContactsPerRegistration int
    37  
    38  		SAService           *cmd.GRPCClientConfig
    39  		VAService           *cmd.GRPCClientConfig
    40  		CAService           *cmd.GRPCClientConfig
    41  		OCSPService         *cmd.GRPCClientConfig
    42  		PublisherService    *cmd.GRPCClientConfig
    43  		AkamaiPurgerService *cmd.GRPCClientConfig
    44  
    45  		MaxNames int `validate:"required,min=1"`
    46  
    47  		// AuthorizationLifetimeDays defines how long authorizations will be
    48  		// considered valid for. Given a value of 300 days when used with a 90-day
    49  		// cert lifetime, this allows creation of certs that will cover a whole
    50  		// year, plus a grace period of a month.
    51  		AuthorizationLifetimeDays int `validate:"required,min=1,max=397"`
    52  
    53  		// PendingAuthorizationLifetimeDays defines how long authorizations may be in
    54  		// the pending state. If you can't respond to a challenge this quickly, then
    55  		// you need to request a new challenge.
    56  		PendingAuthorizationLifetimeDays int `validate:"required,min=1,max=29"`
    57  
    58  		// GoodKey is an embedded config stanza for the goodkey library.
    59  		GoodKey goodkey.Config
    60  
    61  		// OrderLifetime is how far in the future an Order's expiration date should
    62  		// be set when it is first created.
    63  		OrderLifetime config.Duration
    64  
    65  		// FinalizeTimeout is how long the RA is willing to wait for the Order
    66  		// finalization process to take. This config parameter only has an effect
    67  		// if the AsyncFinalization feature flag is enabled. Any systems which
    68  		// manage the shutdown of an RA must be willing to wait at least this long
    69  		// after sending the shutdown signal, to allow background goroutines to
    70  		// complete.
    71  		FinalizeTimeout config.Duration `validate:"-"`
    72  
    73  		// CTLogs contains groupings of CT logs organized by what organization
    74  		// operates them. When we submit precerts to logs in order to get SCTs, we
    75  		// will submit the cert to one randomly-chosen log from each group, and use
    76  		// the SCTs from the first two groups which reply. This allows us to comply
    77  		// with various CT policies that require (for certs with short lifetimes
    78  		// like ours) two SCTs from logs run by different operators. It also holds
    79  		// a `Stagger` value controlling how long we wait for one operator group
    80  		// to respond before trying a different one.
    81  		CTLogs ctconfig.CTConfig
    82  		// InformationalCTLogs are a set of CT logs we will always submit to
    83  		// but won't ever use the SCTs from. This may be because we want to
    84  		// test them or because they are not yet approved by a browser/root
    85  		// program but we still want our certs to end up there.
    86  		InformationalCTLogs []ctconfig.LogDescription
    87  
    88  		// IssuerCerts are paths to all intermediate certificates which may have
    89  		// been used to issue certificates in the last 90 days. These are used to
    90  		// generate OCSP URLs to purge during revocation.
    91  		IssuerCerts []string `validate:"min=1,dive,required"`
    92  
    93  		Features map[string]bool
    94  	}
    95  
    96  	PA cmd.PAConfig
    97  
    98  	Syslog        cmd.SyslogConfig
    99  	OpenTelemetry cmd.OpenTelemetryConfig
   100  }
   101  
   102  func main() {
   103  	grpcAddr := flag.String("addr", "", "gRPC listen address override")
   104  	debugAddr := flag.String("debug-addr", "", "Debug server address override")
   105  	configFile := flag.String("config", "", "File path to the configuration file for this service")
   106  	flag.Parse()
   107  	if *configFile == "" {
   108  		flag.Usage()
   109  		os.Exit(1)
   110  	}
   111  
   112  	var c Config
   113  	err := cmd.ReadConfigFile(*configFile, &c)
   114  	cmd.FailOnError(err, "Reading JSON config file into config structure")
   115  
   116  	err = features.Set(c.RA.Features)
   117  	cmd.FailOnError(err, "Failed to set feature flags")
   118  
   119  	if *grpcAddr != "" {
   120  		c.RA.GRPC.Address = *grpcAddr
   121  	}
   122  	if *debugAddr != "" {
   123  		c.RA.DebugAddr = *debugAddr
   124  	}
   125  
   126  	scope, logger, oTelShutdown := cmd.StatsAndLogging(c.Syslog, c.OpenTelemetry, c.RA.DebugAddr)
   127  	defer oTelShutdown(context.Background())
   128  	logger.Info(cmd.VersionString())
   129  
   130  	// Validate PA config and set defaults if needed
   131  	cmd.FailOnError(c.PA.CheckChallenges(), "Invalid PA configuration")
   132  
   133  	pa, err := policy.New(c.PA.Challenges, logger)
   134  	cmd.FailOnError(err, "Couldn't create PA")
   135  
   136  	if c.RA.HostnamePolicyFile == "" {
   137  		cmd.Fail("HostnamePolicyFile must be provided.")
   138  	}
   139  	err = pa.LoadHostnamePolicyFile(c.RA.HostnamePolicyFile)
   140  	cmd.FailOnError(err, "Couldn't load hostname policy file")
   141  
   142  	tlsConfig, err := c.RA.TLS.Load(scope)
   143  	cmd.FailOnError(err, "TLS config")
   144  
   145  	clk := cmd.Clock()
   146  
   147  	vaConn, err := bgrpc.ClientSetup(c.RA.VAService, tlsConfig, scope, clk)
   148  	cmd.FailOnError(err, "Unable to create VA client")
   149  	vac := vapb.NewVAClient(vaConn)
   150  	caaClient := vapb.NewCAAClient(vaConn)
   151  
   152  	caConn, err := bgrpc.ClientSetup(c.RA.CAService, tlsConfig, scope, clk)
   153  	cmd.FailOnError(err, "Unable to create CA client")
   154  	cac := capb.NewCertificateAuthorityClient(caConn)
   155  
   156  	ocspConn, err := bgrpc.ClientSetup(c.RA.OCSPService, tlsConfig, scope, clk)
   157  	cmd.FailOnError(err, "Unable to create CA OCSP client")
   158  	ocspc := capb.NewOCSPGeneratorClient(ocspConn)
   159  
   160  	saConn, err := bgrpc.ClientSetup(c.RA.SAService, tlsConfig, scope, clk)
   161  	cmd.FailOnError(err, "Failed to load credentials and create gRPC connection to SA")
   162  	sac := sapb.NewStorageAuthorityClient(saConn)
   163  
   164  	conn, err := bgrpc.ClientSetup(c.RA.PublisherService, tlsConfig, scope, clk)
   165  	cmd.FailOnError(err, "Failed to load credentials and create gRPC connection to Publisher")
   166  	pubc := pubpb.NewPublisherClient(conn)
   167  
   168  	apConn, err := bgrpc.ClientSetup(c.RA.AkamaiPurgerService, tlsConfig, scope, clk)
   169  	cmd.FailOnError(err, "Unable to create a Akamai Purger client")
   170  	apc := akamaipb.NewAkamaiPurgerClient(apConn)
   171  
   172  	issuerCertPaths := c.RA.IssuerCerts
   173  	issuerCerts := make([]*issuance.Certificate, len(issuerCertPaths))
   174  	for i, issuerCertPath := range issuerCertPaths {
   175  		issuerCerts[i], err = issuance.LoadCertificate(issuerCertPath)
   176  		cmd.FailOnError(err, "Failed to load issuer certificate")
   177  	}
   178  
   179  	// Boulder's components assume that there will always be CT logs configured.
   180  	// Issuing a certificate without SCTs embedded is a misissuance event as per
   181  	// our CPS 4.4.2, which declares we will always include at least two SCTs.
   182  	// Exit early if no groups are configured.
   183  	var ctp *ctpolicy.CTPolicy
   184  	if len(c.RA.CTLogs.SCTLogs) <= 0 {
   185  		cmd.Fail("Must configure CTLogs")
   186  	}
   187  
   188  	allLogs, err := loglist.New(c.RA.CTLogs.LogListFile)
   189  	cmd.FailOnError(err, "Failed to parse log list")
   190  
   191  	sctLogs, err := allLogs.SubsetForPurpose(c.RA.CTLogs.SCTLogs, loglist.Issuance)
   192  	cmd.FailOnError(err, "Failed to load SCT logs")
   193  
   194  	infoLogs, err := allLogs.SubsetForPurpose(c.RA.CTLogs.InfoLogs, loglist.Informational)
   195  	cmd.FailOnError(err, "Failed to load informational logs")
   196  
   197  	finalLogs, err := allLogs.SubsetForPurpose(c.RA.CTLogs.FinalLogs, loglist.Informational)
   198  	cmd.FailOnError(err, "Failed to load final logs")
   199  
   200  	ctp = ctpolicy.New(pubc, sctLogs, infoLogs, finalLogs, c.RA.CTLogs.Stagger.Duration, logger, scope)
   201  
   202  	// Baseline Requirements v1.8.1 section 4.2.1: "any reused data, document,
   203  	// or completed validation MUST be obtained no more than 398 days prior
   204  	// to issuing the Certificate". If unconfigured or the configured value is
   205  	// greater than 397 days, bail out.
   206  	if c.RA.AuthorizationLifetimeDays <= 0 || c.RA.AuthorizationLifetimeDays > 397 {
   207  		cmd.Fail("authorizationLifetimeDays value must be greater than 0 and less than 398")
   208  	}
   209  	authorizationLifetime := time.Duration(c.RA.AuthorizationLifetimeDays) * 24 * time.Hour
   210  
   211  	// The Baseline Requirements v1.8.1 state that validation tokens "MUST
   212  	// NOT be used for more than 30 days from its creation". If unconfigured
   213  	// or the configured value pendingAuthorizationLifetimeDays is greater
   214  	// than 29 days, bail out.
   215  	if c.RA.PendingAuthorizationLifetimeDays <= 0 || c.RA.PendingAuthorizationLifetimeDays > 29 {
   216  		cmd.Fail("pendingAuthorizationLifetimeDays value must be greater than 0 and less than 30")
   217  	}
   218  	pendingAuthorizationLifetime := time.Duration(c.RA.PendingAuthorizationLifetimeDays) * 24 * time.Hour
   219  
   220  	if features.Enabled(features.AsyncFinalize) && c.RA.FinalizeTimeout.Duration == 0 {
   221  		cmd.Fail("finalizeTimeout must be supplied when AsyncFinalize feature is enabled")
   222  	}
   223  
   224  	kp, err := sagoodkey.NewKeyPolicy(&c.RA.GoodKey, sac.KeyBlocked)
   225  	cmd.FailOnError(err, "Unable to create key policy")
   226  
   227  	if c.RA.MaxNames == 0 {
   228  		cmd.Fail("Error in RA config: MaxNames must not be 0")
   229  	}
   230  
   231  	rai := ra.NewRegistrationAuthorityImpl(
   232  		clk,
   233  		logger,
   234  		scope,
   235  		c.RA.MaxContactsPerRegistration,
   236  		kp,
   237  		c.RA.MaxNames,
   238  		authorizationLifetime,
   239  		pendingAuthorizationLifetime,
   240  		pubc,
   241  		caaClient,
   242  		c.RA.OrderLifetime.Duration,
   243  		c.RA.FinalizeTimeout.Duration,
   244  		ctp,
   245  		apc,
   246  		issuerCerts,
   247  	)
   248  	defer rai.DrainFinalize()
   249  
   250  	policyErr := rai.LoadRateLimitPoliciesFile(c.RA.RateLimitPoliciesFilename)
   251  	cmd.FailOnError(policyErr, "Couldn't load rate limit policies file")
   252  	rai.PA = pa
   253  
   254  	rai.VA = vac
   255  	rai.CA = cac
   256  	rai.OCSP = ocspc
   257  	rai.SA = sac
   258  
   259  	start, err := bgrpc.NewServer(c.RA.GRPC, logger).Add(
   260  		&rapb.RegistrationAuthority_ServiceDesc, rai).Build(tlsConfig, scope, clk)
   261  	cmd.FailOnError(err, "Unable to setup RA gRPC server")
   262  
   263  	cmd.FailOnError(start(), "RA gRPC service failed")
   264  }
   265  
   266  func init() {
   267  	cmd.RegisterCommand("boulder-ra", main, &cmd.ConfigValidator{Config: &Config{}})
   268  }
   269  

View as plain text