boulder/cmd/crl-storer/main.go

145 lines
4.7 KiB
Go

package notmain
import (
"context"
"flag"
"net/http"
"os"
"github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/aws-sdk-go-v2/config"
"github.com/aws/aws-sdk-go-v2/service/s3"
awsl "github.com/aws/smithy-go/logging"
"github.com/letsencrypt/boulder/cmd"
"github.com/letsencrypt/boulder/crl/storer"
cspb "github.com/letsencrypt/boulder/crl/storer/proto"
"github.com/letsencrypt/boulder/features"
bgrpc "github.com/letsencrypt/boulder/grpc"
"github.com/letsencrypt/boulder/issuance"
blog "github.com/letsencrypt/boulder/log"
)
type Config struct {
CRLStorer struct {
cmd.ServiceConfig
// IssuerCerts is a list of paths to issuer certificates on disk. These will
// be used to validate the CRLs received by this service before uploading
// them.
IssuerCerts []string `validate:"min=1,dive,required"`
// S3Endpoint is the URL at which the S3-API-compatible object storage
// service can be reached. This can be used to point to a non-Amazon storage
// service, or to point to a fake service for testing. It should be left
// blank by default.
S3Endpoint string
// S3Bucket is the AWS Bucket that uploads should go to. Must be created
// (and have appropriate permissions set) beforehand.
S3Bucket string
// AWSConfigFile is the path to a file on disk containing an AWS config.
// The format of the configuration file is specified at
// https://docs.aws.amazon.com/sdkref/latest/guide/file-format.html.
AWSConfigFile string
// AWSCredsFile is the path to a file on disk containing AWS credentials.
// The format of the credentials file is specified at
// https://docs.aws.amazon.com/sdkref/latest/guide/file-format.html.
AWSCredsFile string
Features features.Config
}
Syslog cmd.SyslogConfig
OpenTelemetry cmd.OpenTelemetryConfig
}
// awsLogger implements the github.com/aws/smithy-go/logging.Logger interface.
type awsLogger struct {
blog.Logger
}
func (log awsLogger) Logf(c awsl.Classification, format string, v ...interface{}) {
switch c {
case awsl.Debug:
log.Debugf(format, v...)
case awsl.Warn:
log.Warningf(format, v...)
}
}
func main() {
grpcAddr := flag.String("addr", "", "gRPC listen address override")
debugAddr := flag.String("debug-addr", "", "Debug server address override")
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")
features.Set(c.CRLStorer.Features)
if *grpcAddr != "" {
c.CRLStorer.GRPC.Address = *grpcAddr
}
if *debugAddr != "" {
c.CRLStorer.DebugAddr = *debugAddr
}
scope, logger, oTelShutdown := cmd.StatsAndLogging(c.Syslog, c.OpenTelemetry, c.CRLStorer.DebugAddr)
defer oTelShutdown(context.Background())
logger.Info(cmd.VersionString())
clk := cmd.Clock()
tlsConfig, err := c.CRLStorer.TLS.Load(scope)
cmd.FailOnError(err, "TLS config")
issuers := make([]*issuance.Certificate, 0, len(c.CRLStorer.IssuerCerts))
for _, filepath := range c.CRLStorer.IssuerCerts {
cert, err := issuance.LoadCertificate(filepath)
cmd.FailOnError(err, "Failed to load issuer cert")
issuers = append(issuers, cert)
}
// Load the "default" AWS configuration, but override the set of config and
// credential files it reads from to just those specified in our JSON config,
// to ensure that it's not accidentally reading anything from the homedir or
// its other default config locations.
awsConfig, err := config.LoadDefaultConfig(
context.Background(),
config.WithSharedConfigFiles([]string{c.CRLStorer.AWSConfigFile}),
config.WithSharedCredentialsFiles([]string{c.CRLStorer.AWSCredsFile}),
config.WithHTTPClient(new(http.Client)),
config.WithLogger(awsLogger{logger}),
config.WithClientLogMode(aws.LogRequestEventMessage|aws.LogResponseEventMessage),
)
cmd.FailOnError(err, "Failed to load AWS config")
s3opts := make([]func(*s3.Options), 0)
if c.CRLStorer.S3Endpoint != "" {
s3opts = append(
s3opts,
s3.WithEndpointResolver(s3.EndpointResolverFromURL(c.CRLStorer.S3Endpoint)),
func(o *s3.Options) { o.UsePathStyle = true },
)
}
s3client := s3.NewFromConfig(awsConfig, s3opts...)
csi, err := storer.New(issuers, s3client, c.CRLStorer.S3Bucket, scope, logger, clk)
cmd.FailOnError(err, "Failed to create CRLStorer impl")
start, err := bgrpc.NewServer(c.CRLStorer.GRPC, logger).Add(
&cspb.CRLStorer_ServiceDesc, csi).Build(tlsConfig, scope, clk)
cmd.FailOnError(err, "Unable to setup CRLStorer gRPC server")
cmd.FailOnError(start(), "CRLStorer gRPC service failed")
}
func init() {
cmd.RegisterCommand("crl-storer", main, &cmd.ConfigValidator{Config: &Config{}})
}