Files
cheese/tesseract/genconf/main.go

151 lines
4.6 KiB
Go

package main
import (
"flag"
"fmt"
"log"
"os"
"time"
"gopkg.in/yaml.v3"
)
type Config struct {
Listen []string `yaml:"listen"`
Checkpoints string `yaml:"checkpoints"`
Roots string `yaml:"roots"`
Logs []Log `yaml:"logs"`
}
type Log struct {
ShortName string `yaml:"shortname"`
Domain string `yaml:"domain"`
Inception string `yaml:"inception"`
Period int `yaml:"period"`
PoolSize int `yaml:"poolsize"`
SubmissionPrefix string `yaml:"submissionprefix"`
MonitoringPrefix string `yaml:"monitoringprefix"`
CCadbRoots string `yaml:"ccadbroots"`
ExtraRoots string `yaml:"extraroots"`
Secret string `yaml:"secret"`
Cache string `yaml:"cache"`
LocalDirectory string `yaml:"localdirectory"`
Listen string `yaml:"listen"`
NotAfterStart time.Time `yaml:"notafterstart"`
NotAfterLimit time.Time `yaml:"notafterlimit"`
// Computed fields
LogID string
PublicKeyPEM string
PublicKeyDERB64 string
PublicKeyBase64 string
}
func main() {
configFile := flag.String("c", "./tesseract-staging.yaml", "Path to the YAML configuration file")
flag.Parse()
args := flag.Args()
if len(args) == 0 {
showHelp()
return
}
switch args[0] {
case "gen-html":
generateHTML(*configFile)
case "gen-env":
generateEnv(*configFile)
case "gen-key":
generateKeys(*configFile)
case "gen-nginx":
generateNginx(*configFile)
case "gen-roots":
generateRoots(args[1:])
default:
fmt.Fprintf(os.Stderr, "Unknown command: %s\n", args[0])
showHelp()
os.Exit(1)
}
}
func loadConfig(yamlFile string) Config {
data, err := os.ReadFile(yamlFile)
if err != nil {
log.Fatalf("Failed to read YAML file: %v", err)
}
var config Config
err = yaml.Unmarshal(data, &config)
if err != nil {
log.Fatalf("Failed to parse YAML: %v", err)
}
// Set default listen port if not configured
if len(config.Listen) == 0 {
config.Listen = []string{":8080"}
}
// Set defaults for log entries and check for empty/missing values
for i := range config.Logs {
// Checks are in order of fields of the Log struct
if config.Logs[i].ShortName == "" {
log.Fatalf("Log %d is missing a ShortName", i)
}
if config.Logs[i].Domain == "" {
log.Fatalf("Log %d (%s) is missing a value for Domain", i, config.Logs[i].ShortName)
}
if config.Logs[i].Period == 0 {
config.Logs[i].Period = 200
}
if config.Logs[i].PoolSize == 0 {
config.Logs[i].PoolSize = 750
}
}
return config
}
func writeFileWithStatus(filename string, content []byte) error {
existingContent, err := os.ReadFile(filename)
if os.IsNotExist(err) {
fmt.Printf("Creating %s\n", filename)
} else if err != nil {
return fmt.Errorf("failed to read existing file %s: %v", filename, err)
} else if string(existingContent) == string(content) {
fmt.Printf("Unchanged %s\n", filename)
return nil
} else {
fmt.Printf("Updating %s\n", filename)
}
err = os.WriteFile(filename, content, 0644)
if err != nil {
return fmt.Errorf("failed to write file %s: %v", filename, err)
}
return nil
}
func showHelp() {
fmt.Printf("Usage: %s [options] <command>\n\n", os.Args[0])
fmt.Printf("Options:\n")
fmt.Printf(" -c <file> Path to YAML configuration file (default: ./tesseract-staging.yaml)\n\n")
fmt.Printf("Commands:\n")
fmt.Printf(" gen-html Generate index.html and log.v3.json files in each log's localdirectory.\n")
fmt.Printf(" Creates HTML pages with log information and CT log metadata JSON.\n")
fmt.Printf(" Computes LOG_ID and public keys from private keys.\n\n")
fmt.Printf(" gen-env Generate .env files and combined roots.pem in each log's localdirectory.\n")
fmt.Printf(" Creates TESSERACT_ARGS environment variable with command line flags.\n")
fmt.Printf(" Combines global roots and log-specific extraroots into roots.pem.\n\n")
fmt.Printf(" gen-key Generate prime256v1 private keys for each log (only if they don't exist).\n")
fmt.Printf(" Creates EC private key files at the path specified in log.secret.\n\n")
fmt.Printf(" gen-nginx Generate nginx configuration files for each log's monitoring endpoint.\n")
fmt.Printf(" Creates nginx-<hostname>.conf files in each log's localdirectory.\n\n")
fmt.Printf(" gen-roots Download root certificates from a Certificate Transparency log.\n")
fmt.Printf(" Options: --source <url> (default: https://rennet2027h2.log.ct.ipng.ch/)\n")
fmt.Printf(" --output <file> (default: roots.pem)\n\n")
}