go-cert-gen/cmd/main.go

172 lines
4.8 KiB
Go

package cmd
import (
"crypto/x509"
"fmt"
"log"
"math/big"
"os"
"github.com/joho/godotenv"
"github.com/kelseyhightower/envconfig"
"github.com/spf13/cobra"
"github.com/spf13/viper"
"gitlab.com/urkob/go-cert-gen/internal/cert"
"gitlab.com/urkob/go-cert-gen/internal/io"
"gitlab.com/urkob/go-cert-gen/pkg/ca"
"gitlab.com/urkob/go-cert-gen/pkg/client"
pkgio "gitlab.com/urkob/go-cert-gen/pkg/io"
"gitlab.com/urkob/go-cert-gen/pkg/util"
)
var envConfig struct {
ViperConfig string `required:"true" split_words:"true"`
ViperConfigType string `required:"true" split_words:"true"`
Env string `required:"true" split_words:"true"`
}
var writer pkgio.WriterIface
func intEnvConfig(envFilePath string) {
if envFilePath != "" {
err := godotenv.Load(envFilePath)
if err != nil {
log.Fatalf("environment variable ENV is empty and an error occurred while loading the .env file: %s\n", err)
}
}
err := envconfig.Process("", &envConfig)
if err != nil {
log.Fatalf("envconfig.Process: %s\n", err)
}
}
var rootCmd = &cobra.Command{
Use: "go-gen-cert",
Short: "go-gen-cert is a CLI tool to generate TLS certificates for your gRPC client/server communication",
Run: func(cmd *cobra.Command, args []string) {
caCfg := &ca.CaConfig{
SerialNumber: big.NewInt(viper.GetInt64("ca.serial_number")),
Subject: ca.CaSubject{
Organization: viper.GetString("ca.subject.organization"),
CommonName: viper.GetString("ca.subject.common_name"),
},
KeyUsage: x509.KeyUsage(viper.GetInt("ca.key_usage")),
ExtKeyUsage: getExtKeyUsage(viper.GetIntSlice("ca.ext_key_usage")),
Duration: viper.GetDuration("ca.duration"),
}
rootCA, err := cert.NewRootCA(caCfg)
if err != nil {
log.Fatalf("cert.NewRootCA: %s", err)
}
subjectKeyId, err := util.GetBytes(viper.Get("client.subject_key_id"))
if err != nil {
log.Fatalf("cert.NewRootCA: %s", err)
}
clientCfg := &client.ClientCertConfig{
Serial: &big.Int{},
Subject: client.Subject{
Organization: viper.GetString("client.subject.organization"),
Country: viper.GetString("client.subject.country"),
Province: viper.GetString("client.subject.province"),
Locality: viper.GetString("client.subject.locality"),
StreetAddress: viper.GetString("client.subject.street_address"),
PostalCode: viper.GetString("client.subject.postal_code"),
},
Duration: viper.GetDuration("client.duration"),
SubjectKeyId: subjectKeyId,
ExtKeyUsage: getExtKeyUsage(viper.GetIntSlice("client.ext_key_usage")),
KeyUsage: x509.KeyUsage(viper.GetInt("client.key_usage")),
}
clientCert, err := rootCA.WithClientCert(clientCfg)
if err != nil {
log.Fatalf("rootCA.WithClientCert: %s", err)
}
outputPath, err := exportPem("root-ca.pem", rootCA.PEM())
if err != nil {
log.Fatalf("exportPem: %s\n", err)
}
log.Printf("file created successfully: %s\n", outputPath)
outputPath, err = exportPem("root-key.pem", rootCA.Key())
if err != nil {
log.Fatalf("exportPem: %s\n", err)
}
log.Printf("file created successfully: %s\n", outputPath)
outputPath, err = exportPem("client-cert.pem", clientCert.PEM())
if err != nil {
log.Fatalf("exportPem: %s\n", err)
}
log.Printf("file created successfully: %s\n", outputPath)
outputPath, err = exportPem("client-key.pem", clientCert.Key())
if err != nil {
log.Fatalf("exportPem: %s\n", err)
}
log.Printf("file created successfully: %s\n", outputPath)
},
}
func getExtKeyUsage(intKeyUsageSlice []int) []x509.ExtKeyUsage {
if intKeyUsageSlice == nil || len(intKeyUsageSlice) <= 0 {
return []x509.ExtKeyUsage{}
}
extKeyUsage := make([]x509.ExtKeyUsage, 0, len(intKeyUsageSlice))
for _, v := range intKeyUsageSlice {
extKeyUsage = append(extKeyUsage, x509.ExtKeyUsage(v))
}
return extKeyUsage
}
func exportPem(filename string, data []byte) (string, error) {
outputPath, err := writer.WriteFile(filename, data)
if err != nil {
return "", fmt.Errorf("rootCA.WithClientCert: %s", err)
}
return outputPath, nil
}
func init() {
envFile := ""
if os.Getenv("ENV") != "prod" {
envFile = "./.env"
}
intEnvConfig(envFile)
cobra.OnInitialize(initConfig)
}
func initConfig() {
if envConfig.ViperConfig != "" {
viper.AddConfigPath(util.RootDir())
viper.SetConfigName(envConfig.ViperConfig)
viper.SetConfigType(envConfig.ViperConfigType)
} else {
home, err := os.UserHomeDir()
cobra.CheckErr(err)
viper.AddConfigPath(home)
viper.SetConfigType("yaml")
viper.SetConfigName(".cobra")
}
if err := viper.ReadInConfig(); err != nil {
log.Fatalf("viper.ReadInConfig: %s", err)
}
log.Println("viper.GetString('export_dir)", viper.GetString("export_dir"))
writer = io.NewWriter(viper.GetString("export_dir"))
}
func Execute() {
if err := rootCmd.Execute(); err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
}