Beispiel #1
0
// StatsAndLogging constructs a Statter and an AuditLogger based on its config
// parameters, and return them both. Crashes if any setup fails.
// Also sets the constructed AuditLogger as the default logger.
func StatsAndLogging(statConf StatsdConfig, logConf SyslogConfig) (metrics.Statter, blog.Logger) {
	stats, err := metrics.NewStatter(statConf.Server, statConf.Prefix)
	FailOnError(err, "Couldn't connect to statsd")

	tag := path.Base(os.Args[0])
	syslogger, err := syslog.Dial(
		"",
		"",
		syslog.LOG_INFO|syslog.LOG_LOCAL0, // default, overridden by log calls
		tag)
	FailOnError(err, "Could not connect to Syslog")
	stdoutLoglevel := int(syslog.LOG_DEBUG)
	if logConf.StdoutLevel != nil {
		stdoutLoglevel = *logConf.StdoutLevel
	}
	syslogLogLevel := int(syslog.LOG_DEBUG)
	if logConf.SyslogLevel != nil {
		syslogLogLevel = *logConf.SyslogLevel
	}
	logger, err := blog.New(syslogger, stdoutLoglevel, syslogLogLevel)
	FailOnError(err, "Could not connect to Syslog")

	_ = blog.Set(logger)
	cfsslLog.SetLogger(cfsslLogger{logger})
	_ = mysql.SetLogger(mysqlLogger{logger})

	return stats, logger
}
Beispiel #2
0
// StatsAndLogging constructs a Statter and an AuditLogger based on its config
// parameters, and return them both. Crashes if any setup fails.
// Also sets the constructed AuditLogger as the default logger, and configures
// the cfssl, mysql, and grpc packages to use our logger.
// This must be called before any gRPC code is called, because gRPC's SetLogger
// doesn't use any locking.
func StatsAndLogging(statConf StatsdConfig, logConf SyslogConfig) (metrics.Statter, blog.Logger) {
	stats, err := metrics.NewStatter(statConf.Server, statConf.Prefix)
	FailOnError(err, "Couldn't connect to statsd")

	tag := path.Base(os.Args[0])
	syslogger, err := syslog.Dial(
		"",
		"",
		syslog.LOG_INFO, // default, not actually used
		tag)
	FailOnError(err, "Could not connect to Syslog")
	syslogLevel := int(syslog.LOG_INFO)
	if logConf.SyslogLevel != 0 {
		syslogLevel = logConf.SyslogLevel
	}
	logger, err := blog.New(syslogger, logConf.StdoutLevel, syslogLevel)
	FailOnError(err, "Could not connect to Syslog")

	_ = blog.Set(logger)
	cfsslLog.SetLogger(cfsslLogger{logger})
	_ = mysql.SetLogger(mysqlLogger{logger})
	grpclog.SetLogger(grpcLogger{logger})

	return stats, logger
}
func main() {
	app := cli.NewApp()
	app.Name = "cert-checker"
	app.Usage = "Checks validity of issued certificates stored in the database"
	app.Version = cmd.Version()
	app.Author = "Boulder contributors"
	app.Email = "*****@*****.**"

	app.Flags = []cli.Flag{
		cli.IntFlag{
			Name:  "workers",
			Value: runtime.NumCPU(),
			Usage: "The number of concurrent workers used to process certificates",
		},
		cli.BoolFlag{
			Name:  "unexpired-only",
			Usage: "Only check currently unexpired certificates",
		},
		cli.BoolFlag{
			Name:  "bad-results-only",
			Usage: "Only collect and display bad results",
		},
		cli.StringFlag{
			Name:  "db-connect",
			Usage: "SQL URI if not provided in the configuration file",
		},
		cli.StringFlag{
			Name:  "check-period",
			Value: "2160h",
			Usage: "How far back to check",
		},
		cli.StringFlag{
			Name:  "config",
			Value: "config.json",
			Usage: "Path to configuration file",
		},
	}

	app.Action = func(c *cli.Context) {
		configPath := c.GlobalString("config")
		if configPath == "" {
			fmt.Fprintln(os.Stderr, "--config is required")
			os.Exit(1)
		}
		configBytes, err := ioutil.ReadFile(configPath)
		cmd.FailOnError(err, "Failed to read config file")
		var config cmd.Config
		err = json.Unmarshal(configBytes, &config)
		cmd.FailOnError(err, "Failed to parse config file")

		stats, err := metrics.NewStatter(config.Statsd.Server, config.Statsd.Prefix)
		cmd.FailOnError(err, "Failed to create StatsD client")
		syslogger, err := syslog.Dial("", "", syslog.LOG_INFO|syslog.LOG_LOCAL0, "")
		cmd.FailOnError(err, "Failed to dial syslog")
		logger, err := blog.New(syslogger, 0, 0)
		cmd.FailOnError(err, "Failed to construct logger")
		err = blog.Set(logger)
		cmd.FailOnError(err, "Failed to set audit logger")

		if connect := c.GlobalString("db-connect"); connect != "" {
			config.CertChecker.DBConnect = connect
		}
		if workers := c.GlobalInt("workers"); workers != 0 {
			config.CertChecker.Workers = workers
		}
		config.CertChecker.UnexpiredOnly = c.GlobalBool("valid-only")
		config.CertChecker.BadResultsOnly = c.GlobalBool("bad-results-only")
		if cp := c.GlobalString("check-period"); cp != "" {
			config.CertChecker.CheckPeriod.Duration, err = time.ParseDuration(cp)
			cmd.FailOnError(err, "Failed to parse check period")
		}

		// Validate PA config and set defaults if needed
		cmd.FailOnError(config.PA.CheckChallenges(), "Invalid PA configuration")

		saDbURL, err := config.CertChecker.DBConfig.URL()
		cmd.FailOnError(err, "Couldn't load DB URL")
		saDbMap, err := sa.NewDbMap(saDbURL, config.CertChecker.DBConfig.MaxDBConns)
		cmd.FailOnError(err, "Could not connect to database")
		go sa.ReportDbConnCount(saDbMap, metrics.NewStatsdScope(stats, "CertChecker"))

		pa, err := policy.New(config.PA.Challenges)
		cmd.FailOnError(err, "Failed to create PA")
		err = pa.SetHostnamePolicyFile(config.CertChecker.HostnamePolicyFile)
		cmd.FailOnError(err, "Failed to load HostnamePolicyFile")

		checker := newChecker(
			saDbMap,
			clock.Default(),
			pa,
			config.CertChecker.CheckPeriod.Duration,
		)
		fmt.Fprintf(os.Stderr, "# Getting certificates issued in the last %s\n", config.CertChecker.CheckPeriod)

		// Since we grab certificates in batches we don't want this to block, when it
		// is finished it will close the certificate channel which allows the range
		// loops in checker.processCerts to break
		go func() {
			err = checker.getCerts(config.CertChecker.UnexpiredOnly)
			cmd.FailOnError(err, "Batch retrieval of certificates failed")
		}()

		fmt.Fprintf(os.Stderr, "# Processing certificates using %d workers\n", config.CertChecker.Workers)
		wg := new(sync.WaitGroup)
		for i := 0; i < config.CertChecker.Workers; i++ {
			wg.Add(1)
			go func() {
				s := checker.clock.Now()
				checker.processCerts(wg, config.CertChecker.BadResultsOnly)
				stats.TimingDuration("certChecker.processingLatency", time.Since(s), 1.0)
			}()
		}
		wg.Wait()
		fmt.Fprintf(
			os.Stderr,
			"# Finished processing certificates, sample: %d, good: %d, bad: %d\n",
			len(checker.issuedReport.Entries),
			checker.issuedReport.GoodCerts,
			checker.issuedReport.BadCerts,
		)
		err = checker.issuedReport.dump()
		cmd.FailOnError(err, "Failed to dump results: %s\n")
	}

	err := app.Run(os.Args)
	cmd.FailOnError(err, "Failed to run application")
}
Beispiel #4
0
func main() {
	configFile := flag.String("config", "", "File path to the configuration file for this service")
	workers := flag.Int("workers", runtime.NumCPU(), "The number of concurrent workers used to process certificates")
	badResultsOnly := flag.Bool("bad-results-only", false, "Only collect and display bad results")
	connect := flag.String("db-connect", "", "SQL URI if not provided in the configuration file")
	cp := flag.Duration("check-period", time.Hour*2160, "How far back to check")
	unexpiredOnly := flag.Bool("unexpired-only", false, "Only check currently unexpired certificates")

	flag.Parse()
	if *configFile == "" {
		flag.Usage()
		os.Exit(1)
	}

	var config config
	err := cmd.ReadConfigFile(*configFile, &config)
	cmd.FailOnError(err, "Reading JSON config file into config structure")

	err = features.Set(config.CertChecker.Features)
	cmd.FailOnError(err, "Failed to set feature flags")

	stats, err := metrics.NewStatter(config.Statsd.Server, config.Statsd.Prefix)
	cmd.FailOnError(err, "Failed to create StatsD client")
	syslogger, err := syslog.Dial("", "", syslog.LOG_INFO|syslog.LOG_LOCAL0, "")
	cmd.FailOnError(err, "Failed to dial syslog")
	logger, err := blog.New(syslogger, 0, 0)
	cmd.FailOnError(err, "Failed to construct logger")
	err = blog.Set(logger)
	cmd.FailOnError(err, "Failed to set audit logger")

	if *connect != "" {
		config.CertChecker.DBConnect = *connect
	}
	if *workers != 0 {
		config.CertChecker.Workers = *workers
	}
	config.CertChecker.UnexpiredOnly = *unexpiredOnly
	config.CertChecker.BadResultsOnly = *badResultsOnly
	config.CertChecker.CheckPeriod.Duration = *cp

	// Validate PA config and set defaults if needed
	cmd.FailOnError(config.PA.CheckChallenges(), "Invalid PA configuration")

	saDbURL, err := config.CertChecker.DBConfig.URL()
	cmd.FailOnError(err, "Couldn't load DB URL")
	saDbMap, err := sa.NewDbMap(saDbURL, config.CertChecker.DBConfig.MaxDBConns)
	cmd.FailOnError(err, "Could not connect to database")
	go sa.ReportDbConnCount(saDbMap, metrics.NewStatsdScope(stats, "CertChecker"))

	pa, err := policy.New(config.PA.Challenges)
	cmd.FailOnError(err, "Failed to create PA")
	err = pa.SetHostnamePolicyFile(config.CertChecker.HostnamePolicyFile)
	cmd.FailOnError(err, "Failed to load HostnamePolicyFile")

	checker := newChecker(
		saDbMap,
		clock.Default(),
		pa,
		config.CertChecker.CheckPeriod.Duration,
	)
	fmt.Fprintf(os.Stderr, "# Getting certificates issued in the last %s\n", config.CertChecker.CheckPeriod)

	// Since we grab certificates in batches we don't want this to block, when it
	// is finished it will close the certificate channel which allows the range
	// loops in checker.processCerts to break
	go func() {
		err = checker.getCerts(config.CertChecker.UnexpiredOnly)
		cmd.FailOnError(err, "Batch retrieval of certificates failed")
	}()

	fmt.Fprintf(os.Stderr, "# Processing certificates using %d workers\n", config.CertChecker.Workers)
	wg := new(sync.WaitGroup)
	for i := 0; i < config.CertChecker.Workers; i++ {
		wg.Add(1)
		go func() {
			s := checker.clock.Now()
			checker.processCerts(wg, config.CertChecker.BadResultsOnly)
			stats.TimingDuration("certChecker.processingLatency", time.Since(s), 1.0)
		}()
	}
	wg.Wait()
	fmt.Fprintf(
		os.Stderr,
		"# Finished processing certificates, sample: %d, good: %d, bad: %d\n",
		len(checker.issuedReport.Entries),
		checker.issuedReport.GoodCerts,
		checker.issuedReport.BadCerts,
	)
	err = checker.issuedReport.dump()
	cmd.FailOnError(err, "Failed to dump results: %s\n")

}