main

As an Operator, I want to use the ACME protocol, so that I have a standards based way to manage PKI.

SYNOPSIS

Use the ACME protocol to generate TLS PKI.

DESCRIPTION

Below is an example startup configuration for using the ACME protocol in golang and distributing the key material using file storage. The file storage should be replaced with a distributed blob storage that is locked down. This also uses the STEPPATH environment variable to access an internal root certificate authority.

func WithAcmeTLS(ctx context.Context, directoryURL string, cacheDir string) cfg.Option {
	storageFor := func(config *cfg.Config) certmagic.Storage {
		return &certmagic.FileStorage{Path: cacheDir}
	}
	return func(config *cfg.Config) {
		host := os.Getenv("HOST")
		tls := srv.NewTLS(ctx, host, storageFor(config), []certmagic.ACMEIssuer{
			{
				Agreed:               true,
				CA:                   directoryURL,
				DisableHTTPChallenge: true,
				Email:                "everyone@example.com",
				TestCA:               directoryURL,
				TrustedRoots:         newCertPool(),
				AltTLSALPNPort:       bindingPort(),
			},
		})
		config.TLS = x.Must(tls.Config())
	}
}

func newCertPool() *x509.CertPool {
	certPool := x.Must(x509.SystemCertPool())
  certPool.AddCert(func() *x509.Certificate {
    block, _ := pem.Decode(x.Must(ioutil.ReadFile(
      filepath.Join(os.ExpandEnv("$STEPPATH"), "/certs/root_ca.crt"),
    )))
    return x.Must(x509.ParseCertificate(block.Bytes))
  }())
	return certPool
}

func bindingPort() int {
	parts := strings.SplitN(os.Getenv("BIND_ADDR"), ":", 2)
	bindPort, err := strconv.Atoi(parts[1])
	if err != nil {
		bindPort = 0
	}
	return bindPort
}

SEE ALSO

Tasks

  • TBD

Acceptance Criteria

  • TBD