github.com/letsencrypt/boulder@v0.20251208.0/cmd/boulder-ca/main.go (about) 1 package notmain 2 3 import ( 4 "context" 5 "flag" 6 "fmt" 7 "os" 8 "strconv" 9 10 "github.com/jmhodges/clock" 11 12 "github.com/letsencrypt/boulder/ca" 13 capb "github.com/letsencrypt/boulder/ca/proto" 14 "github.com/letsencrypt/boulder/cmd" 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 rapb "github.com/letsencrypt/boulder/ra/proto" 23 sapb "github.com/letsencrypt/boulder/sa/proto" 24 ) 25 26 type Config struct { 27 CA struct { 28 cmd.ServiceConfig 29 30 cmd.HostnamePolicyConfig 31 32 GRPCCA *cmd.GRPCServerConfig 33 34 SAService *cmd.GRPCClientConfig 35 36 SCTService *cmd.GRPCClientConfig 37 38 // Issuance contains all information necessary to load and initialize issuers. 39 Issuance struct { 40 // The name of the certificate profile to use if one wasn't provided 41 // by the RA during NewOrder and Finalize requests. Must match a 42 // configured certificate profile or boulder-ca will fail to start. 43 // 44 // Deprecated: set the defaultProfileName in the RA config instead. 45 DefaultCertificateProfileName string `validate:"omitempty,alphanum,min=1,max=32"` 46 47 // One of the profile names must match the value of ra.defaultProfileName 48 // or large amounts of issuance will fail. 49 CertProfiles map[string]issuance.ProfileConfig `validate:"required,dive,keys,alphanum,min=1,max=32,endkeys"` 50 51 // TODO(#7159): Make this required once all live configs are using it. 52 CRLProfile issuance.CRLProfileConfig `validate:"-"` 53 Issuers []issuance.IssuerConfig `validate:"min=1,dive"` 54 } 55 56 // What digits we should prepend to serials after randomly generating them. 57 // Deprecated: Use SerialPrefixHex instead. 58 SerialPrefix int `validate:"required_without=SerialPrefixHex,omitempty,min=1,max=127"` 59 60 // SerialPrefixHex is the hex string to prepend to serials after randomly 61 // generating them. The minimum value is "01" to ensure that at least 62 // one bit in the prefix byte is set. The maximum value is "7f" to 63 // ensure that the first bit in the prefix byte is not set. The validate 64 // library cannot enforce mix/max values on strings, so that is done in 65 // NewCertificateAuthorityImpl. 66 // 67 // TODO(#7213): Replace `required_without` with `required` when SerialPrefix is removed. 68 SerialPrefixHex string `validate:"required_without=SerialPrefix,omitempty,hexadecimal,len=2"` 69 70 // MaxNames is the maximum number of subjectAltNames in a single cert. 71 // The value supplied MUST be greater than 0 and no more than 100. These 72 // limits are per section 7.1 of our combined CP/CPS, under "DV-SSL 73 // Subscriber Certificate". The value must match the RA and WFE 74 // configurations. 75 MaxNames int `validate:"required,min=1,max=100"` 76 77 // GoodKey is an embedded config stanza for the goodkey library. 78 GoodKey goodkey.Config 79 80 // Maximum length (in bytes) of a line documenting the signing of a CRL. 81 // The name is a carryover from when this config was shared between both 82 // OCSP and CRL audit log emission. Recommended to be around 4000. 83 OCSPLogMaxLength int 84 85 // CTLogListFile is the path to a JSON file on disk containing the set of 86 // all logs trusted by Chrome. The file must match the v3 log list schema: 87 // https://www.gstatic.com/ct/log_list/v3/log_list_schema.json 88 CTLogListFile string 89 90 // DisableCertService causes the CertificateAuthority gRPC service to not 91 // start, preventing any certificates or precertificates from being issued. 92 DisableCertService bool 93 94 // DisableCRLService causes the CRLGenerator gRPC service to not start, 95 // preventing any CRLs from being issued. 96 DisableCRLService bool 97 98 Features features.Config 99 } 100 101 PA cmd.PAConfig 102 103 Syslog cmd.SyslogConfig 104 OpenTelemetry cmd.OpenTelemetryConfig 105 } 106 107 func main() { 108 grpcAddr := flag.String("addr", "", "gRPC listen address override") 109 debugAddr := flag.String("debug-addr", "", "Debug server address override") 110 configFile := flag.String("config", "", "File path to the configuration file for this service") 111 flag.Parse() 112 if *configFile == "" { 113 flag.Usage() 114 os.Exit(1) 115 } 116 117 var c Config 118 err := cmd.ReadConfigFile(*configFile, &c) 119 cmd.FailOnError(err, "Reading JSON config file into config structure") 120 121 features.Set(c.CA.Features) 122 123 if *grpcAddr != "" { 124 c.CA.GRPCCA.Address = *grpcAddr 125 } 126 if *debugAddr != "" { 127 c.CA.DebugAddr = *debugAddr 128 } 129 130 serialPrefix := byte(c.CA.SerialPrefix) 131 if c.CA.SerialPrefixHex != "" { 132 parsedSerialPrefix, err := strconv.ParseUint(c.CA.SerialPrefixHex, 16, 8) 133 cmd.FailOnError(err, "Couldn't convert SerialPrefixHex to int") 134 serialPrefix = byte(parsedSerialPrefix) 135 } 136 137 if c.CA.MaxNames == 0 { 138 cmd.Fail("Error in CA config: MaxNames must not be 0") 139 } 140 141 scope, logger, oTelShutdown := cmd.StatsAndLogging(c.Syslog, c.OpenTelemetry, c.CA.DebugAddr) 142 defer oTelShutdown(context.Background()) 143 logger.Info(cmd.VersionString()) 144 145 metrics := ca.NewCAMetrics(scope) 146 147 cmd.FailOnError(c.PA.CheckChallenges(), "Invalid PA configuration") 148 cmd.FailOnError(c.PA.CheckIdentifiers(), "Invalid PA configuration") 149 150 pa, err := policy.New(c.PA.Identifiers, c.PA.Challenges, logger) 151 cmd.FailOnError(err, "Couldn't create PA") 152 153 if c.CA.HostnamePolicyFile == "" { 154 cmd.Fail("HostnamePolicyFile was empty") 155 } 156 err = pa.LoadIdentPolicyFile(c.CA.HostnamePolicyFile) 157 cmd.FailOnError(err, "Couldn't load identifier policy file") 158 159 // Do this before creating the issuers to ensure the log list is loaded before 160 // the linters are initialized. 161 if c.CA.CTLogListFile != "" { 162 err = loglist.InitLintList(c.CA.CTLogListFile) 163 cmd.FailOnError(err, "Failed to load CT Log List") 164 } 165 166 profiles := make(map[string]*issuance.Profile) 167 for name, profileConfig := range c.CA.Issuance.CertProfiles { 168 profile, err := issuance.NewProfile(profileConfig) 169 cmd.FailOnError(err, "Loading profile") 170 profiles[name] = profile 171 } 172 173 clk := clock.New() 174 var crlShards int 175 issuers := make([]*issuance.Issuer, 0, len(c.CA.Issuance.Issuers)) 176 for i, issuerConfig := range c.CA.Issuance.Issuers { 177 // Double check that all issuers have the same number of CRL shards, because 178 // crl-updater relies upon that invariant. 179 if issuerConfig.CRLShards != 0 && crlShards == 0 { 180 crlShards = issuerConfig.CRLShards 181 } 182 if issuerConfig.CRLShards != crlShards { 183 cmd.Fail(fmt.Sprintf("issuer %d has %d shards, want %d", i, issuerConfig.CRLShards, crlShards)) 184 } 185 // Also check that all the profiles they list actually exist. 186 for _, profile := range issuerConfig.Profiles { 187 _, found := profiles[profile] 188 if !found { 189 cmd.Fail(fmt.Sprintf("issuer %d lists unrecognized profile %q", i, profile)) 190 } 191 } 192 193 issuer, err := issuance.LoadIssuer(issuerConfig, clk) 194 cmd.FailOnError(err, "Loading issuer") 195 issuers = append(issuers, issuer) 196 } 197 198 if len(c.CA.Issuance.CertProfiles) == 0 { 199 cmd.Fail("At least one profile must be configured") 200 } 201 202 tlsConfig, err := c.CA.TLS.Load(scope) 203 cmd.FailOnError(err, "TLS config") 204 205 saConn, err := bgrpc.ClientSetup(c.CA.SAService, tlsConfig, scope, clk) 206 cmd.FailOnError(err, "Failed to load credentials and create gRPC connection to SA") 207 sa := sapb.NewStorageAuthorityClient(saConn) 208 209 var sctService rapb.SCTProviderClient 210 if c.CA.SCTService != nil { 211 sctConn, err := bgrpc.ClientSetup(c.CA.SCTService, tlsConfig, scope, clk) 212 cmd.FailOnError(err, "Failed to load credentials and create gRPC connection to RA for SCTs") 213 sctService = rapb.NewSCTProviderClient(sctConn) 214 } 215 216 kp, err := sagoodkey.NewPolicy(&c.CA.GoodKey, sa.KeyBlocked) 217 cmd.FailOnError(err, "Unable to create key policy") 218 219 srv := bgrpc.NewServer(c.CA.GRPCCA, logger) 220 221 if !c.CA.DisableCRLService { 222 crli, err := ca.NewCRLImpl( 223 issuers, 224 c.CA.Issuance.CRLProfile, 225 c.CA.OCSPLogMaxLength, 226 logger, 227 metrics, 228 ) 229 cmd.FailOnError(err, "Failed to create CRL impl") 230 231 srv = srv.Add(&capb.CRLGenerator_ServiceDesc, crli) 232 } 233 234 if !c.CA.DisableCertService { 235 cai, err := ca.NewCertificateAuthorityImpl( 236 sa, 237 sctService, 238 pa, 239 issuers, 240 profiles, 241 serialPrefix, 242 c.CA.MaxNames, 243 kp, 244 logger, 245 metrics, 246 clk) 247 cmd.FailOnError(err, "Failed to create CA impl") 248 249 srv = srv.Add(&capb.CertificateAuthority_ServiceDesc, cai) 250 } 251 252 start, err := srv.Build(tlsConfig, scope, clk) 253 cmd.FailOnError(err, "Unable to setup CA gRPC server") 254 255 cmd.FailOnError(start(), "CA gRPC service failed") 256 } 257 258 func init() { 259 cmd.RegisterCommand("boulder-ca", main, &cmd.ConfigValidator{Config: &Config{}}) 260 }