238 lines
		
	
	
		
			7.0 KiB
		
	
	
	
		
			Go
		
	
	
	
			
		
		
	
	
			238 lines
		
	
	
		
			7.0 KiB
		
	
	
	
		
			Go
		
	
	
	
| package main
 | |
| 
 | |
| import (
 | |
| 	"crypto/tls"
 | |
| 	"flag"
 | |
| 	"fmt"
 | |
| 	"net"
 | |
| 	"os"
 | |
| 	"time"
 | |
| 
 | |
| 	"google.golang.org/grpc"
 | |
| 
 | |
| 	"github.com/letsencrypt/boulder/bdns"
 | |
| 	caPB "github.com/letsencrypt/boulder/ca/proto"
 | |
| 	"github.com/letsencrypt/boulder/cmd"
 | |
| 	"github.com/letsencrypt/boulder/core"
 | |
| 	"github.com/letsencrypt/boulder/features"
 | |
| 	"github.com/letsencrypt/boulder/goodkey"
 | |
| 	bgrpc "github.com/letsencrypt/boulder/grpc"
 | |
| 	"github.com/letsencrypt/boulder/policy"
 | |
| 	pubPB "github.com/letsencrypt/boulder/publisher/proto"
 | |
| 	"github.com/letsencrypt/boulder/ra"
 | |
| 	rapb "github.com/letsencrypt/boulder/ra/proto"
 | |
| 	sapb "github.com/letsencrypt/boulder/sa/proto"
 | |
| 	vaPB "github.com/letsencrypt/boulder/va/proto"
 | |
| )
 | |
| 
 | |
| type config struct {
 | |
| 	RA struct {
 | |
| 		cmd.ServiceConfig
 | |
| 		cmd.HostnamePolicyConfig
 | |
| 
 | |
| 		RateLimitPoliciesFilename string
 | |
| 
 | |
| 		MaxContactsPerRegistration int
 | |
| 
 | |
| 		// UseIsSafeDomain determines whether to call VA.IsSafeDomain
 | |
| 		UseIsSafeDomain bool // TODO: remove after va IsSafeDomain deploy
 | |
| 
 | |
| 		// The number of times to try a DNS query (that has a temporary error)
 | |
| 		// before giving up. May be short-circuited by deadlines. A zero value
 | |
| 		// will be turned into 1.
 | |
| 		DNSTries int
 | |
| 
 | |
| 		SAService        *cmd.GRPCClientConfig
 | |
| 		VAService        *cmd.GRPCClientConfig
 | |
| 		CAService        *cmd.GRPCClientConfig
 | |
| 		PublisherService *cmd.GRPCClientConfig
 | |
| 
 | |
| 		MaxNames     int
 | |
| 		DoNotForceCN bool
 | |
| 
 | |
| 		// Controls behaviour of the RA when asked to create a new authz for
 | |
| 		// a name/regID that already has a valid authz. False preserves historic
 | |
| 		// behaviour and ignores the existing authz and creates a new one. True
 | |
| 		// instructs the RA to reuse the previously created authz in lieu of
 | |
| 		// creating another.
 | |
| 		ReuseValidAuthz bool
 | |
| 
 | |
| 		// AuthorizationLifetimeDays defines how long authorizations will be
 | |
| 		// considered valid for. Given a value of 300 days when used with a 90-day
 | |
| 		// cert lifetime, this allows creation of certs that will cover a whole
 | |
| 		// year, plus a grace period of a month.
 | |
| 		AuthorizationLifetimeDays int
 | |
| 
 | |
| 		// PendingAuthorizationLifetimeDays defines how long authorizations may be in
 | |
| 		// the pending state. If you can't respond to a challenge this quickly, then
 | |
| 		// you need to request a new challenge.
 | |
| 		PendingAuthorizationLifetimeDays int
 | |
| 
 | |
| 		// WeakKeyFile is the path to a JSON file containing truncated RSA modulus
 | |
| 		// hashes of known easily enumerable keys.
 | |
| 		WeakKeyFile string
 | |
| 
 | |
| 		OrderLifetime cmd.ConfigDuration
 | |
| 
 | |
| 		Features map[string]bool
 | |
| 	}
 | |
| 
 | |
| 	PA cmd.PAConfig
 | |
| 
 | |
| 	Syslog cmd.SyslogConfig
 | |
| 
 | |
| 	Common struct {
 | |
| 		DNSResolver               string
 | |
| 		DNSTimeout                string
 | |
| 		DNSAllowLoopbackAddresses bool
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func main() {
 | |
| 	configFile := flag.String("config", "", "File path to the configuration file for this service")
 | |
| 	flag.Parse()
 | |
| 	if *configFile == "" {
 | |
| 		flag.Usage()
 | |
| 		os.Exit(1)
 | |
| 	}
 | |
| 
 | |
| 	var c config
 | |
| 	err := cmd.ReadConfigFile(*configFile, &c)
 | |
| 	cmd.FailOnError(err, "Reading JSON config file into config structure")
 | |
| 
 | |
| 	err = features.Set(c.RA.Features)
 | |
| 	cmd.FailOnError(err, "Failed to set feature flags")
 | |
| 
 | |
| 	scope, logger := cmd.StatsAndLogging(c.Syslog, c.RA.DebugAddr)
 | |
| 	defer logger.AuditPanic()
 | |
| 	logger.Info(cmd.VersionString())
 | |
| 
 | |
| 	// Validate PA config and set defaults if needed
 | |
| 	cmd.FailOnError(c.PA.CheckChallenges(), "Invalid PA configuration")
 | |
| 
 | |
| 	pa, err := policy.New(c.PA.Challenges)
 | |
| 	cmd.FailOnError(err, "Couldn't create PA")
 | |
| 
 | |
| 	if c.RA.HostnamePolicyFile == "" {
 | |
| 		cmd.FailOnError(fmt.Errorf("HostnamePolicyFile must be provided."), "")
 | |
| 	}
 | |
| 	err = pa.SetHostnamePolicyFile(c.RA.HostnamePolicyFile)
 | |
| 	cmd.FailOnError(err, "Couldn't load hostname policy file")
 | |
| 
 | |
| 	var tls *tls.Config
 | |
| 	if c.RA.TLS.CertFile != nil {
 | |
| 		tls, err = c.RA.TLS.Load()
 | |
| 		cmd.FailOnError(err, "TLS config")
 | |
| 	}
 | |
| 
 | |
| 	vaConn, err := bgrpc.ClientSetup(c.RA.VAService, tls, scope)
 | |
| 	cmd.FailOnError(err, "Unable to create VA client")
 | |
| 	vac := bgrpc.NewValidationAuthorityGRPCClient(vaConn)
 | |
| 
 | |
| 	caaClient := vaPB.NewCAAClient(vaConn)
 | |
| 
 | |
| 	caConn, err := bgrpc.ClientSetup(c.RA.CAService, tls, scope)
 | |
| 	cmd.FailOnError(err, "Unable to create CA client")
 | |
| 	// Build a CA client that is only capable of issuing certificates, not
 | |
| 	// signing OCSP. TODO(jsha): Once we've fully moved to gRPC, replace this
 | |
| 	// with a plain caPB.NewCertificateAuthorityClient.
 | |
| 	cac := bgrpc.NewCertificateAuthorityClient(caPB.NewCertificateAuthorityClient(caConn), nil)
 | |
| 
 | |
| 	var pubc core.Publisher
 | |
| 	if c.RA.PublisherService != nil {
 | |
| 		conn, err := bgrpc.ClientSetup(c.RA.PublisherService, tls, scope)
 | |
| 		cmd.FailOnError(err, "Failed to load credentials and create gRPC connection to Publisher")
 | |
| 		pubc = bgrpc.NewPublisherClientWrapper(pubPB.NewPublisherClient(conn))
 | |
| 	}
 | |
| 
 | |
| 	conn, err := bgrpc.ClientSetup(c.RA.SAService, tls, scope)
 | |
| 	cmd.FailOnError(err, "Failed to load credentials and create gRPC connection to SA")
 | |
| 	sac := bgrpc.NewStorageAuthorityClient(sapb.NewStorageAuthorityClient(conn))
 | |
| 
 | |
| 	// TODO(patf): remove once RA.authorizationLifetimeDays is deployed
 | |
| 	authorizationLifetime := 300 * 24 * time.Hour
 | |
| 	if c.RA.AuthorizationLifetimeDays != 0 {
 | |
| 		authorizationLifetime = time.Duration(c.RA.AuthorizationLifetimeDays) * 24 * time.Hour
 | |
| 	}
 | |
| 
 | |
| 	// TODO(patf): remove once RA.pendingAuthorizationLifetimeDays is deployed
 | |
| 	pendingAuthorizationLifetime := 7 * 24 * time.Hour
 | |
| 	if c.RA.PendingAuthorizationLifetimeDays != 0 {
 | |
| 		pendingAuthorizationLifetime = time.Duration(c.RA.PendingAuthorizationLifetimeDays) * 24 * time.Hour
 | |
| 	}
 | |
| 
 | |
| 	kp, err := goodkey.NewKeyPolicy(c.RA.WeakKeyFile)
 | |
| 	cmd.FailOnError(err, "Unable to create key policy")
 | |
| 
 | |
| 	rai := ra.NewRegistrationAuthorityImpl(
 | |
| 		cmd.Clock(),
 | |
| 		logger,
 | |
| 		scope,
 | |
| 		c.RA.MaxContactsPerRegistration,
 | |
| 		kp,
 | |
| 		c.RA.MaxNames,
 | |
| 		c.RA.DoNotForceCN,
 | |
| 		c.RA.ReuseValidAuthz,
 | |
| 		authorizationLifetime,
 | |
| 		pendingAuthorizationLifetime,
 | |
| 		pubc,
 | |
| 		caaClient,
 | |
| 		c.RA.OrderLifetime.Duration,
 | |
| 	)
 | |
| 
 | |
| 	policyErr := rai.SetRateLimitPoliciesFile(c.RA.RateLimitPoliciesFilename)
 | |
| 	cmd.FailOnError(policyErr, "Couldn't load rate limit policies file")
 | |
| 	rai.PA = pa
 | |
| 
 | |
| 	raDNSTimeout, err := time.ParseDuration(c.Common.DNSTimeout)
 | |
| 	cmd.FailOnError(err, "Couldn't parse RA DNS timeout")
 | |
| 	dnsTries := c.RA.DNSTries
 | |
| 	if dnsTries < 1 {
 | |
| 		dnsTries = 1
 | |
| 	}
 | |
| 	if !c.Common.DNSAllowLoopbackAddresses {
 | |
| 		rai.DNSClient = bdns.NewDNSClientImpl(
 | |
| 			raDNSTimeout,
 | |
| 			[]string{c.Common.DNSResolver},
 | |
| 			nil,
 | |
| 			scope,
 | |
| 			cmd.Clock(),
 | |
| 			dnsTries)
 | |
| 	} else {
 | |
| 		rai.DNSClient = bdns.NewTestDNSClientImpl(
 | |
| 			raDNSTimeout,
 | |
| 			[]string{c.Common.DNSResolver},
 | |
| 			scope,
 | |
| 			cmd.Clock(),
 | |
| 			dnsTries)
 | |
| 	}
 | |
| 
 | |
| 	rai.VA = vac
 | |
| 	rai.CA = cac
 | |
| 	rai.SA = sac
 | |
| 
 | |
| 	err = rai.UpdateIssuedCountForever()
 | |
| 	cmd.FailOnError(err, "Updating total issuance count")
 | |
| 
 | |
| 	var grpcSrv *grpc.Server
 | |
| 	if c.RA.GRPC != nil {
 | |
| 		var listener net.Listener
 | |
| 		grpcSrv, listener, err = bgrpc.NewServer(c.RA.GRPC, tls, scope)
 | |
| 		cmd.FailOnError(err, "Unable to setup RA gRPC server")
 | |
| 		gw := bgrpc.NewRegistrationAuthorityServer(rai)
 | |
| 		rapb.RegisterRegistrationAuthorityServer(grpcSrv, gw)
 | |
| 		go func() {
 | |
| 			err = cmd.FilterShutdownErrors(grpcSrv.Serve(listener))
 | |
| 			cmd.FailOnError(err, "RA gRPC service failed")
 | |
| 		}()
 | |
| 	}
 | |
| 
 | |
| 	go cmd.CatchSignals(logger, func() {
 | |
| 		if grpcSrv != nil {
 | |
| 			grpcSrv.GracefulStop()
 | |
| 		}
 | |
| 	})
 | |
| 
 | |
| 	select {}
 | |
| }
 |