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

     1  package notmain
     2  
     3  import (
     4  	"context"
     5  	"flag"
     6  	"net/http"
     7  	"os"
     8  
     9  	"github.com/aws/aws-sdk-go-v2/aws"
    10  	"github.com/aws/aws-sdk-go-v2/config"
    11  	"github.com/aws/aws-sdk-go-v2/service/s3"
    12  	awsl "github.com/aws/smithy-go/logging"
    13  	"github.com/jmhodges/clock"
    14  
    15  	"github.com/letsencrypt/boulder/cmd"
    16  	"github.com/letsencrypt/boulder/crl/storer"
    17  	cspb "github.com/letsencrypt/boulder/crl/storer/proto"
    18  	"github.com/letsencrypt/boulder/features"
    19  	bgrpc "github.com/letsencrypt/boulder/grpc"
    20  	"github.com/letsencrypt/boulder/issuance"
    21  	blog "github.com/letsencrypt/boulder/log"
    22  )
    23  
    24  type Config struct {
    25  	CRLStorer struct {
    26  		cmd.ServiceConfig
    27  
    28  		// IssuerCerts is a list of paths to issuer certificates on disk. These will
    29  		// be used to validate the CRLs received by this service before uploading
    30  		// them.
    31  		IssuerCerts []string `validate:"min=1,dive,required"`
    32  
    33  		// S3Endpoint is the URL at which the S3-API-compatible object storage
    34  		// service can be reached. This can be used to point to a non-Amazon storage
    35  		// service, or to point to a fake service for testing. It should be left
    36  		// blank by default.
    37  		S3Endpoint string
    38  		// S3Bucket is the AWS Bucket that uploads should go to. Must be created
    39  		// (and have appropriate permissions set) beforehand.
    40  		S3Bucket string
    41  		// AWSConfigFile is the path to a file on disk containing an AWS config.
    42  		// The format of the configuration file is specified at
    43  		// https://docs.aws.amazon.com/sdkref/latest/guide/file-format.html.
    44  		AWSConfigFile string
    45  		// AWSCredsFile is the path to a file on disk containing AWS credentials.
    46  		// The format of the credentials file is specified at
    47  		// https://docs.aws.amazon.com/sdkref/latest/guide/file-format.html.
    48  		AWSCredsFile string
    49  
    50  		Features features.Config
    51  	}
    52  
    53  	Syslog        cmd.SyslogConfig
    54  	OpenTelemetry cmd.OpenTelemetryConfig
    55  }
    56  
    57  // awsLogger implements the github.com/aws/smithy-go/logging.Logger interface.
    58  type awsLogger struct {
    59  	blog.Logger
    60  }
    61  
    62  func (log awsLogger) Logf(c awsl.Classification, format string, v ...any) {
    63  	switch c {
    64  	case awsl.Debug:
    65  		log.Debugf(format, v...)
    66  	case awsl.Warn:
    67  		log.Warningf(format, v...)
    68  	}
    69  }
    70  
    71  func main() {
    72  	grpcAddr := flag.String("addr", "", "gRPC listen address override")
    73  	debugAddr := flag.String("debug-addr", "", "Debug server address override")
    74  	configFile := flag.String("config", "", "File path to the configuration file for this service")
    75  	flag.Parse()
    76  	if *configFile == "" {
    77  		flag.Usage()
    78  		os.Exit(1)
    79  	}
    80  
    81  	var c Config
    82  	err := cmd.ReadConfigFile(*configFile, &c)
    83  	cmd.FailOnError(err, "Reading JSON config file into config structure")
    84  
    85  	features.Set(c.CRLStorer.Features)
    86  
    87  	if *grpcAddr != "" {
    88  		c.CRLStorer.GRPC.Address = *grpcAddr
    89  	}
    90  	if *debugAddr != "" {
    91  		c.CRLStorer.DebugAddr = *debugAddr
    92  	}
    93  
    94  	scope, logger, oTelShutdown := cmd.StatsAndLogging(c.Syslog, c.OpenTelemetry, c.CRLStorer.DebugAddr)
    95  	defer oTelShutdown(context.Background())
    96  	logger.Info(cmd.VersionString())
    97  	clk := clock.New()
    98  
    99  	tlsConfig, err := c.CRLStorer.TLS.Load(scope)
   100  	cmd.FailOnError(err, "TLS config")
   101  
   102  	issuers := make([]*issuance.Certificate, 0, len(c.CRLStorer.IssuerCerts))
   103  	for _, filepath := range c.CRLStorer.IssuerCerts {
   104  		cert, err := issuance.LoadCertificate(filepath)
   105  		cmd.FailOnError(err, "Failed to load issuer cert")
   106  		issuers = append(issuers, cert)
   107  	}
   108  
   109  	// Load the "default" AWS configuration, but override the set of config and
   110  	// credential files it reads from to just those specified in our JSON config,
   111  	// to ensure that it's not accidentally reading anything from the homedir or
   112  	// its other default config locations.
   113  	awsConfig, err := config.LoadDefaultConfig(
   114  		context.Background(),
   115  		config.WithSharedConfigFiles([]string{c.CRLStorer.AWSConfigFile}),
   116  		config.WithSharedCredentialsFiles([]string{c.CRLStorer.AWSCredsFile}),
   117  		config.WithHTTPClient(new(http.Client)),
   118  		config.WithLogger(awsLogger{logger}),
   119  		config.WithClientLogMode(aws.LogRequestEventMessage|aws.LogResponseEventMessage),
   120  	)
   121  	cmd.FailOnError(err, "Failed to load AWS config")
   122  
   123  	s3opts := make([]func(*s3.Options), 0)
   124  	if c.CRLStorer.S3Endpoint != "" {
   125  		s3opts = append(
   126  			s3opts,
   127  			s3.WithEndpointResolver(s3.EndpointResolverFromURL(c.CRLStorer.S3Endpoint)),
   128  			func(o *s3.Options) { o.UsePathStyle = true },
   129  		)
   130  	}
   131  	s3client := s3.NewFromConfig(awsConfig, s3opts...)
   132  
   133  	csi, err := storer.New(issuers, s3client, c.CRLStorer.S3Bucket, scope, logger, clk)
   134  	cmd.FailOnError(err, "Failed to create CRLStorer impl")
   135  
   136  	start, err := bgrpc.NewServer(c.CRLStorer.GRPC, logger).Add(
   137  		&cspb.CRLStorer_ServiceDesc, csi).Build(tlsConfig, scope, clk)
   138  	cmd.FailOnError(err, "Unable to setup CRLStorer gRPC server")
   139  
   140  	cmd.FailOnError(start(), "CRLStorer gRPC service failed")
   141  }
   142  
   143  func init() {
   144  	cmd.RegisterCommand("crl-storer", main, &cmd.ConfigValidator{Config: &Config{}})
   145  }