1// Copyright (c) The Thanos Authors.
2// Licensed under the Apache License 2.0.
3
4package tls
5
6import (
7	"crypto/tls"
8	"crypto/x509"
9	"io/ioutil"
10
11	"github.com/go-kit/kit/log"
12	"github.com/go-kit/kit/log/level"
13	"github.com/pkg/errors"
14)
15
16// NewServerConfig provides new server TLS configuration.
17func NewServerConfig(logger log.Logger, cert, key, clientCA string) (*tls.Config, error) {
18	if key == "" && cert == "" {
19		if clientCA != "" {
20			return nil, errors.New("when a client CA is used a server key and certificate must also be provided")
21		}
22
23		level.Info(logger).Log("msg", "disabled TLS, key and cert must be set to enable")
24		return nil, nil
25	}
26
27	level.Info(logger).Log("msg", "enabling server side TLS")
28
29	if key == "" || cert == "" {
30		return nil, errors.New("both server key and certificate must be provided")
31	}
32
33	tlsCfg := &tls.Config{
34		MinVersion: tls.VersionTLS12,
35	}
36
37	tlsCert, err := tls.LoadX509KeyPair(cert, key)
38	if err != nil {
39		return nil, errors.Wrap(err, "server credentials")
40	}
41
42	tlsCfg.Certificates = []tls.Certificate{tlsCert}
43
44	if clientCA != "" {
45		caPEM, err := ioutil.ReadFile(clientCA)
46		if err != nil {
47			return nil, errors.Wrap(err, "reading client CA")
48		}
49
50		certPool := x509.NewCertPool()
51		if !certPool.AppendCertsFromPEM(caPEM) {
52			return nil, errors.Wrap(err, "building client CA")
53		}
54		tlsCfg.ClientCAs = certPool
55		tlsCfg.ClientAuth = tls.RequireAndVerifyClientCert
56
57		level.Info(logger).Log("msg", "server TLS client verification enabled")
58	}
59
60	return tlsCfg, nil
61}
62
63// NewClientConfig provides new client TLS configuration.
64func NewClientConfig(logger log.Logger, cert, key, caCert, serverName string) (*tls.Config, error) {
65	var certPool *x509.CertPool
66	if caCert != "" {
67		caPEM, err := ioutil.ReadFile(caCert)
68		if err != nil {
69			return nil, errors.Wrap(err, "reading client CA")
70		}
71
72		certPool = x509.NewCertPool()
73		if !certPool.AppendCertsFromPEM(caPEM) {
74			return nil, errors.Wrap(err, "building client CA")
75		}
76		level.Info(logger).Log("msg", "TLS client using provided certificate pool")
77	} else {
78		var err error
79		certPool, err = x509.SystemCertPool()
80		if err != nil {
81			return nil, errors.Wrap(err, "reading system certificate pool")
82		}
83		level.Info(logger).Log("msg", "TLS client using system certificate pool")
84	}
85
86	tlsCfg := &tls.Config{
87		RootCAs: certPool,
88	}
89
90	if serverName != "" {
91		tlsCfg.ServerName = serverName
92	}
93
94	if (key != "") != (cert != "") {
95		return nil, errors.New("both client key and certificate must be provided")
96	}
97
98	if cert != "" {
99		cert, err := tls.LoadX509KeyPair(cert, key)
100		if err != nil {
101			return nil, errors.Wrap(err, "client credentials")
102		}
103		tlsCfg.Certificates = []tls.Certificate{cert}
104		level.Info(logger).Log("msg", "TLS client authentication enabled")
105	}
106	return tlsCfg, nil
107}
108