mirror of
https://github.com/featurebasedb/featurebase.git
synced 2026-08-28 10:54:59 +00:00
Merge pull request #2069 from codysoyland/tls-autoreload
Auto-reload TLS certificates on SIGHUP
This commit is contained in:
commit
61dace4527
7 changed files with 190 additions and 43 deletions
34
NOTICE
34
NOTICE
|
|
@ -55,8 +55,8 @@ The file /pilosa/lru/lru.go contains a redistribution of lru
|
|||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
The files /enterprise/b/btree.go and /roaring/btree.go contain a modified
|
||||
redistribution of b (https://github.com/cznic/b); the license follows:
|
||||
The file /roaring/btree.go contains a modified redistribution of b
|
||||
(https://github.com/cznic/b); the license follows:
|
||||
|
||||
Copyright (c) 2014 The b Authors. All rights reserved.
|
||||
|
||||
|
|
@ -85,3 +85,33 @@ redistribution of b (https://github.com/cznic/b); the license follows:
|
|||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
The file /server/tlsconfig.go contains a modified redistribution of bridge
|
||||
(https://github.com/robustirc/bridge); the license follows:
|
||||
|
||||
Copyright © 2014-2015 The RobustIRC Authors. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the name of RobustIRC nor the names of contributors may be used
|
||||
to endorse or promote products derived from this software without
|
||||
specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
|
|
|||
11
cmd.go
11
cmd.go
|
|
@ -14,13 +14,17 @@
|
|||
|
||||
package pilosa
|
||||
|
||||
import "io"
|
||||
import (
|
||||
"io"
|
||||
"log"
|
||||
)
|
||||
|
||||
// CmdIO holds standard unix inputs and outputs.
|
||||
type CmdIO struct {
|
||||
Stdin io.Reader
|
||||
Stdout io.Writer
|
||||
Stderr io.Writer
|
||||
logger *log.Logger
|
||||
}
|
||||
|
||||
// NewCmdIO returns a new instance of CmdIO with inputs and outputs set to the
|
||||
|
|
@ -30,5 +34,10 @@ func NewCmdIO(stdin io.Reader, stdout, stderr io.Writer) *CmdIO {
|
|||
Stdin: stdin,
|
||||
Stdout: stdout,
|
||||
Stderr: stderr,
|
||||
logger: log.New(stderr, "", log.LstdFlags),
|
||||
}
|
||||
}
|
||||
|
||||
func (c *CmdIO) Logger() *log.Logger {
|
||||
return c.logger
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,6 +15,8 @@
|
|||
package ctl
|
||||
|
||||
import (
|
||||
"log"
|
||||
|
||||
"github.com/pilosa/pilosa/http"
|
||||
"github.com/pilosa/pilosa/server"
|
||||
"github.com/pkg/errors"
|
||||
|
|
@ -25,6 +27,7 @@ import (
|
|||
type CommandWithTLSSupport interface {
|
||||
TLSHost() string
|
||||
TLSConfiguration() server.TLSConfig
|
||||
Logger() *log.Logger
|
||||
}
|
||||
|
||||
// SetTLSConfig creates common TLS flags
|
||||
|
|
@ -39,7 +42,7 @@ func SetTLSConfig(flags *pflag.FlagSet, certificatePath *string, certificateKeyP
|
|||
// commandClient returns a pilosa.InternalHTTPClient for the command
|
||||
func commandClient(cmd CommandWithTLSSupport) (*http.InternalClient, error) {
|
||||
tls := cmd.TLSConfiguration()
|
||||
tlsConfig, err := server.GetTLSConfig(&tls)
|
||||
tlsConfig, err := server.GetTLSConfig(&tls, cmd.Logger())
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "getting tls config")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,7 +17,6 @@ package ctl
|
|||
import (
|
||||
"context"
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
|
||||
"github.com/pilosa/pilosa"
|
||||
|
|
@ -52,7 +51,7 @@ func NewExportCommand(stdin io.Reader, stdout, stderr io.Writer) *ExportCommand
|
|||
|
||||
// Run executes the export.
|
||||
func (cmd *ExportCommand) Run(ctx context.Context) error {
|
||||
logger := log.New(cmd.Stderr, "", log.LstdFlags)
|
||||
logger := cmd.Logger()
|
||||
|
||||
// Validate arguments.
|
||||
if cmd.Index == "" {
|
||||
|
|
|
|||
|
|
@ -80,7 +80,7 @@ func NewImportCommand(stdin io.Reader, stdout, stderr io.Writer) *ImportCommand
|
|||
|
||||
// Run executes the main program execution.
|
||||
func (cmd *ImportCommand) Run(ctx context.Context) error {
|
||||
logger := log.New(cmd.Stderr, "", log.LstdFlags)
|
||||
logger := cmd.Logger()
|
||||
|
||||
// Validate arguments.
|
||||
// Index and field are validated early before the files are parsed.
|
||||
|
|
|
|||
|
|
@ -23,9 +23,7 @@ import (
|
|||
"bytes"
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"math/rand"
|
||||
"net"
|
||||
|
|
@ -249,7 +247,7 @@ func (m *Command) SetupServer() error {
|
|||
// Setup TLS
|
||||
var TLSConfig *tls.Config
|
||||
if uri.Scheme == "https" {
|
||||
TLSConfig, err = GetTLSConfig(&m.Config.TLS)
|
||||
TLSConfig, err = GetTLSConfig(&m.Config.TLS, m.logger.Logger())
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "get tls config")
|
||||
}
|
||||
|
|
@ -474,36 +472,3 @@ func (f *filteredWriter) Write(p []byte) (n int, err error) {
|
|||
}
|
||||
return len(p), nil
|
||||
}
|
||||
|
||||
func GetTLSConfig(tlsConfig *TLSConfig) (TLSConfig *tls.Config, err error) {
|
||||
if tlsConfig.CertificatePath != "" && tlsConfig.CertificateKeyPath != "" {
|
||||
cert, err := tls.LoadX509KeyPair(tlsConfig.CertificatePath, tlsConfig.CertificateKeyPath)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "loading keypair")
|
||||
}
|
||||
TLSConfig = &tls.Config{
|
||||
Certificates: []tls.Certificate{cert},
|
||||
InsecureSkipVerify: tlsConfig.SkipVerify,
|
||||
PreferServerCipherSuites: true,
|
||||
MinVersion: tls.VersionTLS12,
|
||||
}
|
||||
if tlsConfig.CACertPath != "" {
|
||||
b, err := ioutil.ReadFile(tlsConfig.CACertPath)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "loading tls ca key")
|
||||
}
|
||||
certPool := x509.NewCertPool()
|
||||
|
||||
ok := certPool.AppendCertsFromPEM(b)
|
||||
if !ok {
|
||||
return nil, errors.New("error parsing CA certificate")
|
||||
}
|
||||
TLSConfig.ClientCAs = certPool
|
||||
TLSConfig.RootCAs = certPool
|
||||
}
|
||||
if tlsConfig.EnableClientVerification {
|
||||
TLSConfig.ClientAuth = tls.RequireAndVerifyClientCert
|
||||
}
|
||||
}
|
||||
return TLSConfig, nil
|
||||
}
|
||||
|
|
|
|||
141
server/tlsconfig.go
Normal file
141
server/tlsconfig.go
Normal file
|
|
@ -0,0 +1,141 @@
|
|||
// Copyright 2017 Pilosa Corp.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
// This file contains source code from bridge
|
||||
// (https://github.com/robustirc/bridge); which is governed by the following
|
||||
// license notice:
|
||||
//
|
||||
// Copyright © 2014-2015 The RobustIRC Authors. All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
//
|
||||
// * Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
//
|
||||
// * Neither the name of RobustIRC nor the names of contributors may be used
|
||||
// to endorse or promote products derived from this software without
|
||||
// specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE
|
||||
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
package server
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"os/signal"
|
||||
"sync"
|
||||
"syscall"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
type keypairReloader struct {
|
||||
certMu sync.RWMutex
|
||||
cert *tls.Certificate
|
||||
certPath string
|
||||
keyPath string
|
||||
}
|
||||
|
||||
func NewKeypairReloader(certPath, keyPath string, logger *log.Logger) (*keypairReloader, error) {
|
||||
result := &keypairReloader{
|
||||
certPath: certPath,
|
||||
keyPath: keyPath,
|
||||
}
|
||||
cert, err := tls.LoadX509KeyPair(certPath, keyPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result.cert = &cert
|
||||
go func() {
|
||||
c := make(chan os.Signal, 1)
|
||||
signal.Notify(c, syscall.SIGHUP)
|
||||
for range c {
|
||||
logger.Printf("Received SIGHUP, reloading TLS certificate and key from %q and %q", certPath, keyPath)
|
||||
if err := result.maybeReload(); err != nil {
|
||||
logger.Printf("Keeping old TLS certificate because the new one could not be loaded: %v", err)
|
||||
}
|
||||
}
|
||||
}()
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (kpr *keypairReloader) maybeReload() error {
|
||||
newCert, err := tls.LoadX509KeyPair(kpr.certPath, kpr.keyPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
kpr.certMu.Lock()
|
||||
defer kpr.certMu.Unlock()
|
||||
kpr.cert = &newCert
|
||||
return nil
|
||||
}
|
||||
|
||||
func (kpr *keypairReloader) GetCertificateFunc() func(*tls.ClientHelloInfo) (*tls.Certificate, error) {
|
||||
return func(clientHello *tls.ClientHelloInfo) (*tls.Certificate, error) {
|
||||
kpr.certMu.RLock()
|
||||
defer kpr.certMu.RUnlock()
|
||||
return kpr.cert, nil
|
||||
}
|
||||
}
|
||||
|
||||
func GetTLSConfig(tlsConfig *TLSConfig, logger *log.Logger) (TLSConfig *tls.Config, err error) {
|
||||
if tlsConfig.CertificatePath != "" && tlsConfig.CertificateKeyPath != "" {
|
||||
kpr, err := NewKeypairReloader(tlsConfig.CertificatePath, tlsConfig.CertificateKeyPath, logger)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "loading keypair")
|
||||
}
|
||||
TLSConfig = &tls.Config{
|
||||
InsecureSkipVerify: tlsConfig.SkipVerify,
|
||||
PreferServerCipherSuites: true,
|
||||
MinVersion: tls.VersionTLS12,
|
||||
GetCertificate: kpr.GetCertificateFunc(),
|
||||
}
|
||||
if tlsConfig.CACertPath != "" {
|
||||
b, err := ioutil.ReadFile(tlsConfig.CACertPath)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "loading tls ca key")
|
||||
}
|
||||
certPool := x509.NewCertPool()
|
||||
|
||||
ok := certPool.AppendCertsFromPEM(b)
|
||||
if !ok {
|
||||
return nil, errors.New("error parsing CA certificate")
|
||||
}
|
||||
TLSConfig.ClientCAs = certPool
|
||||
TLSConfig.RootCAs = certPool
|
||||
}
|
||||
if tlsConfig.EnableClientVerification {
|
||||
TLSConfig.ClientAuth = tls.RequireAndVerifyClientCert
|
||||
}
|
||||
}
|
||||
return TLSConfig, nil
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue