[ARVADOS] created: 1.1.4-244-gb4a283a
Git user
git at public.curoverse.com
Wed May 9 15:57:11 EDT 2018
at b4a283a9f142209b22fabda98ea2573cf0dbe281 (commit)
commit b4a283a9f142209b22fabda98ea2573cf0dbe281
Author: Tom Clegg <tclegg at veritasgenetics.com>
Date: Wed May 9 15:56:20 2018 -0400
13446: Enable TLS if given TLSCertificateFile and TLSKeyFile.
Arvados-DCO-1.1-Signed-off-by: Tom Clegg <tclegg at veritasgenetics.com>
diff --git a/services/keepstore/config.go b/services/keepstore/config.go
index 19dc7f6..c9c9ae1 100644
--- a/services/keepstore/config.go
+++ b/services/keepstore/config.go
@@ -43,6 +43,8 @@ type Config struct {
PullWorkers int
TrashWorkers int
EmptyTrashWorkers int
+ TLSCertificateFile string
+ TLSKeyFile string
Volumes VolumeList
diff --git a/services/keepstore/keepstore.go b/services/keepstore/keepstore.go
index c742752..79e3017 100644
--- a/services/keepstore/keepstore.go
+++ b/services/keepstore/keepstore.go
@@ -8,7 +8,6 @@ import (
"flag"
"fmt"
"net"
- "net/http"
"os"
"os/signal"
"syscall"
@@ -203,7 +202,8 @@ func main() {
log.Printf("Error notifying init daemon: %v", err)
}
log.Println("listening at", listener.Addr())
- srv := &http.Server{Handler: router}
+ srv := &server{}
+ srv.Handler = router
srv.Serve(listener)
}
diff --git a/services/keepstore/server.go b/services/keepstore/server.go
new file mode 100644
index 0000000..3f67277
--- /dev/null
+++ b/services/keepstore/server.go
@@ -0,0 +1,78 @@
+// Copyright (C) The Arvados Authors. All rights reserved.
+//
+// SPDX-License-Identifier: AGPL-3.0
+
+package main
+
+import (
+ "crypto/tls"
+ "net"
+ "net/http"
+ "os"
+ "os/signal"
+ "syscall"
+)
+
+type server struct {
+ http.Server
+
+ // channel (size=1) with the current keypair
+ currentCert chan *tls.Certificate
+}
+
+func (srv *server) Serve(l net.Listener) error {
+ if theConfig.TLSCertificateFile == "" && theConfig.TLSKeyFile == "" {
+ return srv.Server.Serve(l)
+ }
+ // https://blog.gopheracademy.com/advent-2016/exposing-go-on-the-internet/
+ srv.TLSConfig = &tls.Config{
+ GetCertificate: srv.getCertificate,
+ PreferServerCipherSuites: true,
+ CurvePreferences: []tls.CurveID{
+ tls.CurveP256,
+ tls.X25519,
+ },
+ MinVersion: tls.VersionTLS12,
+ CipherSuites: []uint16{
+ tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
+ tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
+ tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,
+ tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
+ tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
+ tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
+ },
+ }
+ srv.currentCert = make(chan *tls.Certificate, 1)
+ go srv.refreshCertificate(theConfig.TLSCertificateFile, theConfig.TLSKeyFile)
+ return srv.Server.ServeTLS(l, "", "")
+}
+
+func (srv *server) refreshCertificate(certfile, keyfile string) {
+ cert, err := tls.LoadX509KeyPair(certfile, keyfile)
+ if err != nil {
+ log.WithError(err).Fatal("error loading X509 key pair")
+ }
+ srv.currentCert <- &cert
+
+ reload := make(chan os.Signal, 1)
+ signal.Notify(reload, syscall.SIGHUP)
+ for range reload {
+ cert, err := tls.LoadX509KeyPair(certfile, keyfile)
+ if err != nil {
+ log.WithError(err).Warn("error loading X509 key pair")
+ continue
+ }
+ // Throw away old cert and start using new one
+ <-srv.currentCert
+ srv.currentCert <- &cert
+ }
+}
+
+func (srv *server) getCertificate(*tls.ClientHelloInfo) (*tls.Certificate, error) {
+ if srv.currentCert == nil {
+ panic("srv.currentCert not initialized")
+ }
+ cert := <-srv.currentCert
+ srv.currentCert <- cert
+ return cert, nil
+}
diff --git a/services/keepstore/server_test.go b/services/keepstore/server_test.go
new file mode 100644
index 0000000..84adf36
--- /dev/null
+++ b/services/keepstore/server_test.go
@@ -0,0 +1,47 @@
+// Copyright (C) The Arvados Authors. All rights reserved.
+//
+// SPDX-License-Identifier: AGPL-3.0
+
+package main
+
+import (
+ "bytes"
+ "context"
+ "crypto/tls"
+ "io/ioutil"
+ "net"
+ "net/http"
+ "testing"
+)
+
+func TestTLS(t *testing.T) {
+ defer func() {
+ theConfig.TLSKeyFile = ""
+ theConfig.TLSCertificateFile = ""
+ }()
+ theConfig.TLSKeyFile = "../api/tmp/self-signed.key"
+ theConfig.TLSCertificateFile = "../api/tmp/self-signed.pem"
+ srv := &server{}
+ srv.Handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ w.Write([]byte("OK"))
+ })
+ l, err := net.Listen("tcp", ":")
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer l.Close()
+ go srv.Serve(l)
+ defer srv.Shutdown(context.Background())
+ c := &http.Client{Transport: &http.Transport{TLSClientConfig: &tls.Config{InsecureSkipVerify: true}}}
+ resp, err := c.Get("https://" + l.Addr().String() + "/")
+ if err != nil {
+ t.Fatal(err)
+ }
+ body, err := ioutil.ReadAll(resp.Body)
+ if err != nil {
+ t.Error(err)
+ }
+ if !bytes.Equal(body, []byte("OK")) {
+ t.Errorf("expected OK, got %q", body)
+ }
+}
diff --git a/services/keepstore/usage.go b/services/keepstore/usage.go
index 672d7cf..8e83f6c 100644
--- a/services/keepstore/usage.go
+++ b/services/keepstore/usage.go
@@ -133,6 +133,21 @@ PullWorkers:
Maximum number of concurrent pull operations. Default is 1, i.e.,
pull lists are processed serially.
+TLSCertificateFile:
+
+ Path to server certificate file in X509 format. Enables TLS mode.
+
+ Example: /var/lib/acme/live/keep0.example.com/fullchain
+
+TLSKeyFile:
+
+ Path to server key file in X509 format. Enables TLS mode.
+
+ The key pair is read from disk during startup, and whenever SIGHUP
+ is received.
+
+ Example: /var/lib/acme/live/keep0.example.com/privkey
+
Volumes:
List of storage volumes. If omitted or empty, the default is to
-----------------------------------------------------------------------
hooks/post-receive
--
More information about the arvados-commits
mailing list