github.com/letsencrypt/boulder@v0.20251208.0/cmd/boulder-ra/main.go (about) 1 package notmain 2 3 import ( 4 "context" 5 "flag" 6 "os" 7 "time" 8 9 "github.com/jmhodges/clock" 10 11 capb "github.com/letsencrypt/boulder/ca/proto" 12 "github.com/letsencrypt/boulder/cmd" 13 "github.com/letsencrypt/boulder/config" 14 "github.com/letsencrypt/boulder/ctpolicy" 15 "github.com/letsencrypt/boulder/ctpolicy/ctconfig" 16 "github.com/letsencrypt/boulder/ctpolicy/loglist" 17 "github.com/letsencrypt/boulder/features" 18 "github.com/letsencrypt/boulder/goodkey" 19 "github.com/letsencrypt/boulder/goodkey/sagoodkey" 20 bgrpc "github.com/letsencrypt/boulder/grpc" 21 "github.com/letsencrypt/boulder/issuance" 22 "github.com/letsencrypt/boulder/policy" 23 pubpb "github.com/letsencrypt/boulder/publisher/proto" 24 "github.com/letsencrypt/boulder/ra" 25 rapb "github.com/letsencrypt/boulder/ra/proto" 26 "github.com/letsencrypt/boulder/ratelimits" 27 bredis "github.com/letsencrypt/boulder/redis" 28 sapb "github.com/letsencrypt/boulder/sa/proto" 29 "github.com/letsencrypt/boulder/va" 30 vapb "github.com/letsencrypt/boulder/va/proto" 31 ) 32 33 type Config struct { 34 RA struct { 35 cmd.ServiceConfig 36 cmd.HostnamePolicyConfig 37 38 // RateLimitPoliciesFilename is deprecated. 39 RateLimitPoliciesFilename string 40 41 MaxContactsPerRegistration int 42 43 SAService *cmd.GRPCClientConfig 44 VAService *cmd.GRPCClientConfig 45 CAService *cmd.GRPCClientConfig 46 PublisherService *cmd.GRPCClientConfig 47 48 // Deprecated: TODO(#8349): Remove this when removing the corresponding 49 // service from the CA. 50 OCSPService *cmd.GRPCClientConfig 51 52 Limiter struct { 53 // Redis contains the configuration necessary to connect to Redis 54 // for rate limiting. This field is required to enable rate 55 // limiting. 56 Redis *bredis.Config `validate:"required_with=Defaults"` 57 58 // Defaults is a path to a YAML file containing default rate limits. 59 // See: ratelimits/README.md for details. This field is required to 60 // enable rate limiting. If any individual rate limit is not set, 61 // that limit will be disabled. Limits passed in this file must be 62 // identical to those in the WFE. 63 // 64 // Note: At this time, only the Failed Authorizations rate limit is 65 // necessary in the RA. 66 Defaults string `validate:"required_with=Redis"` 67 68 // Overrides is a path to a YAML file containing overrides for the 69 // default rate limits. See: ratelimits/README.md for details. If 70 // neither this field nor OverridesFromDB is set, all requesters 71 // will be subject to the default rate limits. Overrides passed in 72 // this file must be identical to those in the WFE. 73 // 74 // Note: At this time, only the Failed Authorizations overrides are 75 // necessary in the RA. 76 Overrides string 77 78 // OverridesFromDB causes the WFE and RA to retrieve rate limit overrides 79 // from the database, instead of from a file. 80 OverridesFromDB bool 81 } 82 83 // MaxNames is the maximum number of subjectAltNames in a single cert. 84 // The value supplied MUST be greater than 0 and no more than 100. These 85 // limits are per section 7.1 of our combined CP/CPS, under "DV-SSL 86 // Subscriber Certificate". The value must match the CA and WFE 87 // configurations. 88 // 89 // Deprecated: Set ValidationProfiles[*].MaxNames instead. 90 MaxNames int `validate:"omitempty,min=1,max=100"` 91 92 // ValidationProfiles is a map of validation profiles to their 93 // respective issuance allow lists. If a profile is not included in this 94 // mapping, it cannot be used by any account. If this field is left 95 // empty, all profiles are open to all accounts. 96 ValidationProfiles map[string]*ra.ValidationProfileConfig `validate:"required"` 97 98 // DefaultProfileName sets the profile to use if one wasn't provided by the 99 // client in the new-order request. Must match a configured validation 100 // profile or the RA will fail to start. Must match a certificate profile 101 // configured in the CA or finalization will fail for orders using this 102 // default. 103 DefaultProfileName string `validate:"required"` 104 105 // GoodKey is an embedded config stanza for the goodkey library. 106 GoodKey goodkey.Config 107 108 // FinalizeTimeout is how long the RA is willing to wait for the Order 109 // finalization process to take. This config parameter only has an effect 110 // if the AsyncFinalization feature flag is enabled. Any systems which 111 // manage the shutdown of an RA must be willing to wait at least this long 112 // after sending the shutdown signal, to allow background goroutines to 113 // complete. 114 FinalizeTimeout config.Duration `validate:"-"` 115 116 // CTLogs contains groupings of CT logs organized by what organization 117 // operates them. When we submit precerts to logs in order to get SCTs, we 118 // will submit the cert to one randomly-chosen log from each group, and use 119 // the SCTs from the first two groups which reply. This allows us to comply 120 // with various CT policies that require (for certs with short lifetimes 121 // like ours) two SCTs from logs run by different operators. It also holds 122 // a `Stagger` value controlling how long we wait for one operator group 123 // to respond before trying a different one. 124 CTLogs ctconfig.CTConfig 125 126 // IssuerCerts are paths to all intermediate certificates which may have 127 // been used to issue certificates in the last 90 days. These are used to 128 // generate OCSP URLs to purge during revocation. 129 IssuerCerts []string `validate:"min=1,dive,required"` 130 131 Features features.Config 132 } 133 134 PA cmd.PAConfig 135 136 Syslog cmd.SyslogConfig 137 OpenTelemetry cmd.OpenTelemetryConfig 138 } 139 140 func main() { 141 grpcAddr := flag.String("addr", "", "gRPC listen address override") 142 debugAddr := flag.String("debug-addr", "", "Debug server address override") 143 configFile := flag.String("config", "", "File path to the configuration file for this service") 144 flag.Parse() 145 if *configFile == "" { 146 flag.Usage() 147 os.Exit(1) 148 } 149 150 var c Config 151 err := cmd.ReadConfigFile(*configFile, &c) 152 cmd.FailOnError(err, "Reading JSON config file into config structure") 153 154 features.Set(c.RA.Features) 155 156 if *grpcAddr != "" { 157 c.RA.GRPC.Address = *grpcAddr 158 } 159 if *debugAddr != "" { 160 c.RA.DebugAddr = *debugAddr 161 } 162 163 scope, logger, oTelShutdown := cmd.StatsAndLogging(c.Syslog, c.OpenTelemetry, c.RA.DebugAddr) 164 defer oTelShutdown(context.Background()) 165 logger.Info(cmd.VersionString()) 166 167 // Validate PA config and set defaults if needed 168 cmd.FailOnError(c.PA.CheckChallenges(), "Invalid PA configuration") 169 cmd.FailOnError(c.PA.CheckIdentifiers(), "Invalid PA configuration") 170 171 pa, err := policy.New(c.PA.Identifiers, c.PA.Challenges, logger) 172 cmd.FailOnError(err, "Couldn't create PA") 173 174 if c.RA.HostnamePolicyFile == "" { 175 cmd.Fail("HostnamePolicyFile must be provided.") 176 } 177 err = pa.LoadIdentPolicyFile(c.RA.HostnamePolicyFile) 178 cmd.FailOnError(err, "Couldn't load identifier policy file") 179 180 tlsConfig, err := c.RA.TLS.Load(scope) 181 cmd.FailOnError(err, "TLS config") 182 183 clk := clock.New() 184 185 vaConn, err := bgrpc.ClientSetup(c.RA.VAService, tlsConfig, scope, clk) 186 cmd.FailOnError(err, "Unable to create VA client") 187 vac := vapb.NewVAClient(vaConn) 188 caaClient := vapb.NewCAAClient(vaConn) 189 190 caConn, err := bgrpc.ClientSetup(c.RA.CAService, tlsConfig, scope, clk) 191 cmd.FailOnError(err, "Unable to create CA client") 192 cac := capb.NewCertificateAuthorityClient(caConn) 193 194 saConn, err := bgrpc.ClientSetup(c.RA.SAService, tlsConfig, scope, clk) 195 cmd.FailOnError(err, "Failed to load credentials and create gRPC connection to SA") 196 sac := sapb.NewStorageAuthorityClient(saConn) 197 198 conn, err := bgrpc.ClientSetup(c.RA.PublisherService, tlsConfig, scope, clk) 199 cmd.FailOnError(err, "Failed to load credentials and create gRPC connection to Publisher") 200 pubc := pubpb.NewPublisherClient(conn) 201 202 issuerCertPaths := c.RA.IssuerCerts 203 issuerCerts := make([]*issuance.Certificate, len(issuerCertPaths)) 204 for i, issuerCertPath := range issuerCertPaths { 205 issuerCerts[i], err = issuance.LoadCertificate(issuerCertPath) 206 cmd.FailOnError(err, "Failed to load issuer certificate") 207 } 208 209 // Boulder's components assume that there will always be CT logs configured. 210 // Issuing a certificate without SCTs embedded is a misissuance event as per 211 // our CPS 4.4.2, which declares we will always include at least two SCTs. 212 // Exit early if no groups are configured. 213 var ctp *ctpolicy.CTPolicy 214 if len(c.RA.CTLogs.SCTLogs) <= 0 { 215 cmd.Fail("Must configure CTLogs") 216 } 217 218 allLogs, err := loglist.New(c.RA.CTLogs.LogListFile) 219 cmd.FailOnError(err, "Failed to parse log list") 220 221 sctLogs, err := allLogs.SubsetForPurpose(c.RA.CTLogs.SCTLogs, loglist.Issuance, c.RA.CTLogs.SubmitToTestLogs) 222 cmd.FailOnError(err, "Failed to load SCT logs") 223 224 infoLogs, err := allLogs.SubsetForPurpose(c.RA.CTLogs.InfoLogs, loglist.Informational, true) 225 cmd.FailOnError(err, "Failed to load informational logs") 226 227 finalLogs, err := allLogs.SubsetForPurpose(c.RA.CTLogs.FinalLogs, loglist.Informational, true) 228 cmd.FailOnError(err, "Failed to load final logs") 229 230 ctp = ctpolicy.New(pubc, sctLogs, infoLogs, finalLogs, c.RA.CTLogs.Stagger.Duration, logger, scope) 231 232 if len(c.RA.ValidationProfiles) == 0 { 233 cmd.Fail("At least one profile must be configured") 234 } 235 236 // TODO(#7993): Remove this fallback and make ValidationProfile.MaxNames a 237 // required config field. We don't do any validation on the value of this 238 // top-level MaxNames because that happens inside the call to 239 // NewValidationProfiles below. 240 for _, pc := range c.RA.ValidationProfiles { 241 if pc.MaxNames == 0 { 242 pc.MaxNames = c.RA.MaxNames 243 } 244 } 245 246 validationProfiles, err := ra.NewValidationProfiles(c.RA.DefaultProfileName, c.RA.ValidationProfiles) 247 cmd.FailOnError(err, "Failed to load validation profiles") 248 249 if features.Get().AsyncFinalize && c.RA.FinalizeTimeout.Duration == 0 { 250 cmd.Fail("finalizeTimeout must be supplied when AsyncFinalize feature is enabled") 251 } 252 253 kp, err := sagoodkey.NewPolicy(&c.RA.GoodKey, sac.KeyBlocked) 254 cmd.FailOnError(err, "Unable to create key policy") 255 256 var limiter *ratelimits.Limiter 257 var txnBuilder *ratelimits.TransactionBuilder 258 var limiterRedis *bredis.Ring 259 if c.RA.Limiter.Defaults != "" { 260 // Setup rate limiting. 261 limiterRedis, err = bredis.NewRingFromConfig(*c.RA.Limiter.Redis, scope, logger) 262 cmd.FailOnError(err, "Failed to create Redis ring") 263 264 source := ratelimits.NewRedisSource(limiterRedis.Ring, clk, scope) 265 limiter, err = ratelimits.NewLimiter(clk, source, scope) 266 cmd.FailOnError(err, "Failed to create rate limiter") 267 if c.RA.Limiter.OverridesFromDB { 268 if c.RA.Limiter.Overrides != "" { 269 cmd.Fail("OverridesFromDB and an overrides file were both defined, but are mutually exclusive") 270 } 271 saroc := sapb.NewStorageAuthorityReadOnlyClient(saConn) 272 txnBuilder, err = ratelimits.NewTransactionBuilderFromDatabase(c.RA.Limiter.Defaults, saroc.GetEnabledRateLimitOverrides, scope, logger) 273 } else { 274 txnBuilder, err = ratelimits.NewTransactionBuilderFromFiles(c.RA.Limiter.Defaults, c.RA.Limiter.Overrides, scope, logger) 275 } 276 cmd.FailOnError(err, "Failed to create rate limits transaction builder") 277 278 // The 30 minute period here must be kept in sync with the promise 279 // (successCommentBody) made to requesters in sfe/overridesimporter.go 280 overrideRefresherShutdown := txnBuilder.NewRefresher(30 * time.Minute) 281 defer overrideRefresherShutdown() 282 } 283 284 rai := ra.NewRegistrationAuthorityImpl( 285 clk, 286 logger, 287 scope, 288 c.RA.MaxContactsPerRegistration, 289 kp, 290 limiter, 291 txnBuilder, 292 c.RA.MaxNames, 293 validationProfiles, 294 pubc, 295 c.RA.FinalizeTimeout.Duration, 296 ctp, 297 issuerCerts, 298 ) 299 defer rai.Drain() 300 301 rai.PA = pa 302 303 rai.VA = va.RemoteClients{ 304 VAClient: vac, 305 CAAClient: caaClient, 306 } 307 rai.CA = cac 308 rai.SA = sac 309 310 start, err := bgrpc.NewServer(c.RA.GRPC, logger).Add( 311 &rapb.RegistrationAuthority_ServiceDesc, rai).Add( 312 &rapb.SCTProvider_ServiceDesc, rai). 313 Build(tlsConfig, scope, clk) 314 cmd.FailOnError(err, "Unable to setup RA gRPC server") 315 316 cmd.FailOnError(start(), "RA gRPC service failed") 317 } 318 319 func init() { 320 cmd.RegisterCommand("boulder-ra", main, &cmd.ConfigValidator{Config: &Config{}}) 321 }