@@ -0,0 +1,69 @@
+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.
+
+```golang
+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
+
+* [RFC-8555](https://datatracker.ietf.org/doc/html/rfc8555)
+* [$STEPPATH](https://smallstep.com/docs/step-cli/reference/path/#examples)
+
+# Tasks
+
+* [ ] TBD
+
+# Acceptance Criteria
+
+* [ ] TBD