2018-03-29 15:25:11 +00:00
|
|
|
// certgen: a tool for generating test certificates on disk for use as
|
|
|
|
// test-fixtures and for end-to-end testing and local development.
|
|
|
|
//
|
|
|
|
// Example usage:
|
|
|
|
//
|
2022-10-21 19:58:06 +00:00
|
|
|
// $ go run connect/certgen/certgen.go -out-dir /tmp/connect-certs
|
2018-03-29 15:25:11 +00:00
|
|
|
//
|
|
|
|
// You can verify a given leaf with a given root using:
|
|
|
|
//
|
2022-10-21 19:58:06 +00:00
|
|
|
// $ openssl verify -verbose -CAfile ca1-ca.cert.pem ca1-svc-db.cert.pem
|
2018-03-29 15:25:11 +00:00
|
|
|
//
|
|
|
|
// Note that to verify via the cross-signed intermediate, openssl requires it to
|
|
|
|
// be bundled with the _root_ CA bundle and will ignore the cert if it's passed
|
|
|
|
// with the subject. You can do that with:
|
|
|
|
//
|
2022-10-21 19:58:06 +00:00
|
|
|
// $ openssl verify -verbose -CAfile \
|
|
|
|
// <(cat ca1-ca.cert.pem ca2-xc-by-ca1.cert.pem) \
|
|
|
|
// ca2-svc-db.cert.pem
|
|
|
|
// ca2-svc-db.cert.pem: OK
|
2018-03-29 15:25:11 +00:00
|
|
|
//
|
|
|
|
// Note that the same leaf and root without the intermediate should fail:
|
|
|
|
//
|
2022-10-21 19:58:06 +00:00
|
|
|
// $ openssl verify -verbose -CAfile ca1-ca.cert.pem ca2-svc-db.cert.pem
|
|
|
|
// ca2-svc-db.cert.pem: CN = db
|
|
|
|
// error 20 at 0 depth lookup:unable to get local issuer certificate
|
2018-03-29 15:25:11 +00:00
|
|
|
//
|
|
|
|
// NOTE: THIS IS A QUIRK OF OPENSSL; in Connect we distribute the roots alone
|
|
|
|
// and stable intermediates like the XC cert to the _leaf_.
|
|
|
|
package main // import "github.com/hashicorp/consul/connect/certgen"
|
2018-04-03 18:10:59 +00:00
|
|
|
|
2018-03-29 15:25:11 +00:00
|
|
|
import (
|
|
|
|
"flag"
|
|
|
|
"fmt"
|
|
|
|
"log"
|
|
|
|
"os"
|
|
|
|
|
2022-10-21 19:58:06 +00:00
|
|
|
"github.com/mitchellh/go-testing-interface"
|
|
|
|
|
2018-03-29 15:25:11 +00:00
|
|
|
"github.com/hashicorp/consul/agent/connect"
|
|
|
|
"github.com/hashicorp/consul/agent/structs"
|
|
|
|
)
|
|
|
|
|
|
|
|
func main() {
|
|
|
|
var numCAs = 2
|
|
|
|
var services = []string{"web", "db", "cache"}
|
|
|
|
var outDir string
|
2019-07-30 21:47:39 +00:00
|
|
|
var keyType string = "ec"
|
|
|
|
var keyBits int = 256
|
2018-03-29 15:25:11 +00:00
|
|
|
|
|
|
|
flag.StringVar(&outDir, "out-dir", "",
|
|
|
|
"REQUIRED: the dir to write certificates to")
|
2019-07-30 21:47:39 +00:00
|
|
|
flag.StringVar(&keyType, "key-type", "ec",
|
|
|
|
"Type of private key to create (ec, rsa)")
|
|
|
|
flag.IntVar(&keyBits, "key-bits", 256,
|
|
|
|
"Size of private key to create, in bits")
|
2018-03-29 15:25:11 +00:00
|
|
|
flag.Parse()
|
|
|
|
|
|
|
|
if outDir == "" {
|
|
|
|
flag.PrintDefaults()
|
|
|
|
os.Exit(1)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create CA certs
|
|
|
|
var prevCA *structs.CARoot
|
|
|
|
for i := 1; i <= numCAs; i++ {
|
2019-07-30 21:47:39 +00:00
|
|
|
ca := connect.TestCAWithKeyType(&testing.RuntimeT{}, prevCA, keyType, keyBits)
|
2018-03-29 15:25:11 +00:00
|
|
|
prefix := fmt.Sprintf("%s/ca%d-ca", outDir, i)
|
|
|
|
writeFile(prefix+".cert.pem", ca.RootCert)
|
|
|
|
writeFile(prefix+".key.pem", ca.SigningKey)
|
|
|
|
if prevCA != nil {
|
|
|
|
fname := fmt.Sprintf("%s/ca%d-xc-by-ca%d.cert.pem", outDir, i, i-1)
|
|
|
|
writeFile(fname, ca.SigningCert)
|
|
|
|
}
|
|
|
|
prevCA = ca
|
|
|
|
|
|
|
|
// Create service certs for each CA
|
|
|
|
for _, svc := range services {
|
|
|
|
certPEM, keyPEM := connect.TestLeaf(&testing.RuntimeT{}, svc, ca)
|
|
|
|
prefix := fmt.Sprintf("%s/ca%d-svc-%s", outDir, i, svc)
|
|
|
|
writeFile(prefix+".cert.pem", certPEM)
|
|
|
|
writeFile(prefix+".key.pem", keyPEM)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func writeFile(name, content string) {
|
|
|
|
fmt.Println("Writing ", name)
|
2022-11-10 16:26:01 +00:00
|
|
|
err := os.WriteFile(name, []byte(content), 0600)
|
2018-03-29 15:25:11 +00:00
|
|
|
if err != nil {
|
|
|
|
log.Fatalf("failed writing file: %s", err)
|
|
|
|
}
|
|
|
|
}
|