[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