+func makeTLSConfig(cluster *arvados.Cluster, logger logrus.FieldLogger) (*tls.Config, error) {
+ if cluster.TLS.ACME.Server != "" {
+ return makeAutocertConfig(cluster, logger)
+ } else {
+ return makeFileLoaderConfig(cluster, logger)
+ }
+}
+
+var errCertUnavailable = errors.New("certificate unavailable, waiting for supervisor to update cache")
+
+type readonlyDirCache autocert.DirCache
+
+func (c readonlyDirCache) Get(ctx context.Context, name string) ([]byte, error) {
+ data, err := autocert.DirCache(c).Get(ctx, name)
+ if err != nil {
+ // Returning an error other than autocert.ErrCacheMiss
+ // causes GetCertificate() to fail early instead of
+ // trying to obtain a certificate itself (which
+ // wouldn't work because we're not in a position to
+ // answer challenges).
+ return nil, errCertUnavailable
+ }
+ return data, nil
+}
+
+func (c readonlyDirCache) Put(ctx context.Context, name string, data []byte) error {
+ return fmt.Errorf("(bug?) (readonlyDirCache)Put(%s) called", name)
+}
+
+func (c readonlyDirCache) Delete(ctx context.Context, name string) error {
+ return nil
+}
+
+func makeAutocertConfig(cluster *arvados.Cluster, logger logrus.FieldLogger) (*tls.Config, error) {
+ mgr := &autocert.Manager{
+ Cache: readonlyDirCache("/var/lib/arvados/tmp/autocert"),
+ Prompt: autocert.AcceptTOS,
+ // HostPolicy accepts all names because this Manager
+ // doesn't request certs. Whoever writes certs to our
+ // cache is effectively responsible for HostPolicy.
+ HostPolicy: func(ctx context.Context, host string) error { return nil },
+ // Keep using whatever's in the cache as long as
+ // possible. Assume some other process (see lib/boot)
+ // handles renewals.
+ RenewBefore: time.Second,
+ }
+ return mgr.TLSConfig(), nil
+}
+
+func makeFileLoaderConfig(cluster *arvados.Cluster, logger logrus.FieldLogger) (*tls.Config, error) {