1 // Copyright (C) The Arvados Authors. All rights reserved.
3 // SPDX-License-Identifier: AGPL-3.0
18 "git.arvados.org/arvados.git/sdk/go/arvados"
19 "github.com/sirupsen/logrus"
20 "golang.org/x/crypto/acme/autocert"
23 func makeTLSConfig(cluster *arvados.Cluster, logger logrus.FieldLogger) (*tls.Config, error) {
24 if cluster.TLS.ACME.Server != "" {
25 return makeAutocertConfig(cluster, logger)
27 return makeFileLoaderConfig(cluster, logger)
31 var errCertUnavailable = errors.New("certificate unavailable, waiting for supervisor to update cache")
33 type readonlyDirCache autocert.DirCache
35 func (c readonlyDirCache) Get(ctx context.Context, name string) ([]byte, error) {
36 data, err := autocert.DirCache(c).Get(ctx, name)
38 // Returning an error other than autocert.ErrCacheMiss
39 // causes GetCertificate() to fail early instead of
40 // trying to obtain a certificate itself (which
41 // wouldn't work because we're not in a position to
42 // answer challenges).
43 return nil, errCertUnavailable
48 func (c readonlyDirCache) Put(ctx context.Context, name string, data []byte) error {
49 return fmt.Errorf("(bug?) (readonlyDirCache)Put(%s) called", name)
52 func (c readonlyDirCache) Delete(ctx context.Context, name string) error {
56 func makeAutocertConfig(cluster *arvados.Cluster, logger logrus.FieldLogger) (*tls.Config, error) {
57 mgr := &autocert.Manager{
58 Cache: readonlyDirCache("/var/lib/arvados/tmp/autocert"),
59 Prompt: autocert.AcceptTOS,
60 // HostPolicy accepts all names because this Manager
61 // doesn't request certs. Whoever writes certs to our
62 // cache is effectively responsible for HostPolicy.
63 HostPolicy: func(ctx context.Context, host string) error { return nil },
64 // Keep using whatever's in the cache as long as
65 // possible. Assume some other process (see lib/boot)
67 RenewBefore: time.Second,
69 return mgr.TLSConfig(), nil
72 func makeFileLoaderConfig(cluster *arvados.Cluster, logger logrus.FieldLogger) (*tls.Config, error) {
73 currentCert := make(chan *tls.Certificate, 1)
76 key := strings.TrimPrefix(cluster.TLS.Key, "file://")
77 cert := strings.TrimPrefix(cluster.TLS.Certificate, "file://")
79 update := func() error {
80 cert, err := tls.LoadX509KeyPair(cert, key)
82 return fmt.Errorf("error loading X509 key pair: %s", err)
85 // Throw away old cert
97 reload := make(chan os.Signal, 1)
98 signal.Notify(reload, syscall.SIGHUP)
100 for range time.NewTicker(time.Hour).C {
108 logger.WithError(err).Warn("error updating TLS certificate")
113 // https://blog.gopheracademy.com/advent-2016/exposing-go-on-the-internet/
115 PreferServerCipherSuites: true,
116 CurvePreferences: []tls.CurveID{
120 MinVersion: tls.VersionTLS12,
121 CipherSuites: []uint16{
122 tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
123 tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
124 tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,
125 tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
126 tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
127 tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
129 GetCertificate: func(*tls.ClientHelloInfo) (*tls.Certificate, error) {
130 cert := <-currentCert