Add support of user self signed certificates

Additionally add documentation about how to configure TLS with Minio
master
Anis Elleuch 8 years ago committed by Harshavardhana
parent e216201901
commit 6512d9978e
  1. 25
      cmd/certs.go
  2. 5
      cmd/globals.go
  3. 3
      cmd/net-rpc-client.go
  4. 23
      cmd/server-main.go
  5. 18
      cmd/server_test.go
  6. 207
      cmd/test-utils_test.go
  7. 50
      docs/configure-minio-with-tls.md

@ -31,7 +31,11 @@ func createCertsPath() error {
if err != nil { if err != nil {
return err return err
} }
return os.MkdirAll(certsPath, 0700) if err := os.MkdirAll(certsPath, 0700); err != nil {
return err
}
rootCAsPath := filepath.Join(certsPath, globalMinioCertsCADir)
return os.MkdirAll(rootCAsPath, 0700)
} }
// getCertsPath get certs path. // getCertsPath get certs path.
@ -62,6 +66,25 @@ func mustGetKeyFile() string {
return filepath.Join(mustGetCertsPath(), globalMinioKeyFile) return filepath.Join(mustGetCertsPath(), globalMinioKeyFile)
} }
// mustGetCAFiles must get the list of the CA certificates stored in minio config dir
func mustGetCAFiles() (caCerts []string) {
CAsDir := filepath.Join(mustGetCertsPath(), globalMinioCertsCADir)
caFiles, _ := ioutil.ReadDir(CAsDir)
for _, cert := range caFiles {
caCerts = append(caCerts, filepath.Join(CAsDir, cert.Name()))
}
return
}
// mustGetSystemCertPool returns empty cert pool in case of error (windows)
func mustGetSystemCertPool() *x509.CertPool {
pool, err := x509.SystemCertPool()
if err != nil {
return x509.NewCertPool()
}
return pool
}
// isCertFileExists verifies if cert file exists, returns true if // isCertFileExists verifies if cert file exists, returns true if
// found, false otherwise. // found, false otherwise.
func isCertFileExists() bool { func isCertFileExists() bool {

@ -17,6 +17,7 @@
package cmd package cmd
import ( import (
"crypto/x509"
"time" "time"
"github.com/fatih/color" "github.com/fatih/color"
@ -33,6 +34,7 @@ const (
globalMinioConfigVersion = "9" globalMinioConfigVersion = "9"
globalMinioConfigDir = ".minio" globalMinioConfigDir = ".minio"
globalMinioCertsDir = "certs" globalMinioCertsDir = "certs"
globalMinioCertsCADir = "CAs"
globalMinioCertFile = "public.crt" globalMinioCertFile = "public.crt"
globalMinioKeyFile = "private.key" globalMinioKeyFile = "private.key"
globalMinioConfigFile = "config.json" globalMinioConfigFile = "config.json"
@ -59,6 +61,9 @@ var (
// Peer communication struct // Peer communication struct
globalS3Peers = s3Peers{} globalS3Peers = s3Peers{}
// CA root certificates, a nil value means system certs pool will be used
globalRootCAs *x509.CertPool
// Add new variable global values here. // Add new variable global values here.
) )

@ -81,9 +81,10 @@ func (rpcClient *RPCClient) dialRPCClient() (*rpc.Client, error) {
hostname, _, splitErr := net.SplitHostPort(rpcClient.node) hostname, _, splitErr := net.SplitHostPort(rpcClient.node)
if splitErr != nil { if splitErr != nil {
return nil, errors.New("Unable to parse RPC address <" + rpcClient.node + "> : " + splitErr.Error()) return nil, errors.New("Unable to parse RPC address <" + rpcClient.node + "> : " + splitErr.Error())
} }
// ServerName in tls.Config needs to be specified to support SNI certificates // ServerName in tls.Config needs to be specified to support SNI certificates
conn, err = tls.Dial("tcp", rpcClient.node, &tls.Config{ServerName: hostname}) conn, err = tls.Dial("tcp", rpcClient.node, &tls.Config{ServerName: hostname, RootCAs: globalRootCAs})
} else { } else {
// Have a dial timeout with 3 secs. // Have a dial timeout with 3 secs.
conn, err = net.DialTimeout("tcp", rpcClient.node, 3*time.Second) conn, err = net.DialTimeout("tcp", rpcClient.node, 3*time.Second)

@ -18,6 +18,7 @@ package cmd
import ( import (
"fmt" "fmt"
"io/ioutil"
"net" "net"
"net/http" "net/http"
"net/url" "net/url"
@ -170,12 +171,34 @@ func finalizeEndpoints(tls bool, apiServer *http.Server) (endPoints []string) {
return endPoints return endPoints
} }
// loadRootCAs fetches CA files provided in minio config and adds them to globalRootCAs
// Currently under Windows, there is no way to load system + user CAs at the same time
func loadRootCAs() {
caFiles := mustGetCAFiles()
if len(caFiles) == 0 {
return
}
// Get system cert pool, and empty cert pool under Windows because it is not supported
globalRootCAs = mustGetSystemCertPool()
// Load custom root CAs for client requests
for _, caFile := range mustGetCAFiles() {
caCert, err := ioutil.ReadFile(caFile)
if err != nil {
fatalIf(err, "Unable to load a CA file")
}
globalRootCAs.AppendCertsFromPEM(caCert)
}
}
// initServerConfig initialize server config. // initServerConfig initialize server config.
func initServerConfig(c *cli.Context) { func initServerConfig(c *cli.Context) {
// Create certs path. // Create certs path.
err := createCertsPath() err := createCertsPath()
fatalIf(err, "Unable to create \"certs\" directory.") fatalIf(err, "Unable to create \"certs\" directory.")
// Load user supplied root CAs
loadRootCAs()
// When credentials inherited from the env, server cmd has to save them in the disk // When credentials inherited from the env, server cmd has to save them in the disk
if os.Getenv("MINIO_ACCESS_KEY") != "" && os.Getenv("MINIO_SECRET_KEY") != "" { if os.Getenv("MINIO_ACCESS_KEY") != "" && os.Getenv("MINIO_SECRET_KEY") != "" {
// Env credentials are already loaded in serverConfig, just save in the disk // Env credentials are already loaded in serverConfig, just save in the disk

@ -20,6 +20,7 @@ import (
"bytes" "bytes"
"crypto/md5" "crypto/md5"
"crypto/tls" "crypto/tls"
"crypto/x509"
"encoding/base64" "encoding/base64"
"encoding/hex" "encoding/hex"
"encoding/xml" "encoding/xml"
@ -64,11 +65,20 @@ var _ = Suite(&TestSuiteCommon{serverType: "XL", signer: signerV4})
// Starting the Test server with temporary FS backend. // Starting the Test server with temporary FS backend.
func (s *TestSuiteCommon) SetUpSuite(c *C) { func (s *TestSuiteCommon) SetUpSuite(c *C) {
if s.secure { if s.secure {
s.testServer = StartTestTLSServer(c, s.serverType) cert, key, err := generateTLSCertKey("127.0.0.1")
c.Assert(err, IsNil)
s.testServer = StartTestTLSServer(c, s.serverType, cert, key)
rootCAs := x509.NewCertPool()
rootCAs.AppendCertsFromPEM(cert)
tlsConfig := &tls.Config{
RootCAs: rootCAs,
}
tlsConfig.BuildNameToCertificate()
s.transport = &http.Transport{ s.transport = &http.Transport{
TLSClientConfig: &tls.Config{ TLSClientConfig: tlsConfig,
InsecureSkipVerify: true,
},
} }
} else { } else {
s.testServer = StartTestServer(c, s.serverType) s.testServer = StartTestServer(c, s.serverType)

@ -19,16 +19,23 @@ package cmd
import ( import (
"bufio" "bufio"
"bytes" "bytes"
"crypto/ecdsa"
"crypto/hmac" "crypto/hmac"
crand "crypto/rand"
"crypto/rsa"
"crypto/sha1" "crypto/sha1"
"crypto/tls" "crypto/tls"
"crypto/x509"
"crypto/x509/pkix"
"encoding/base64" "encoding/base64"
"encoding/hex" "encoding/hex"
"encoding/json" "encoding/json"
"encoding/pem"
"errors" "errors"
"fmt" "fmt"
"io" "io"
"io/ioutil" "io/ioutil"
"math/big"
"math/rand" "math/rand"
"net" "net"
"net/http" "net/http"
@ -233,66 +240,68 @@ func UnstartedTestServer(t TestErrHandler, instanceType string) TestServer {
} }
// Starts the test server and returns the TestServer with TLS configured instance. // testServerCertPEM and testServerKeyPEM are generated by
func StartTestTLSServer(t TestErrHandler, instanceType string) TestServer { // https://golang.org/src/crypto/tls/generate_cert.go
serverKey := []byte(`-----BEGIN RSA PRIVATE KEY----- // $ go run generate_cert.go -ca --host 127.0.0.1
MIIEpAIBAAKCAQEAwD0kEmvtaHx+M0qJAY8zFEn6UpCIbZshNIoXOOr2S3XBEar9 // The generated certificate contains IP SAN, that way we don't need
gtvTGpL73rPJroVcaTJxavsQJx6iD8E38t85rTsrlxEomAk5eKVK3WyplcUuqBgm // to enable InsecureSkipVerify in TLS config
+KMYyyWxMXgYA3+AumEHiDg1SMIgrWFka2x+dSsqRb64tzWtD3LLy/Amq4cdiO1v
/v1rNEdqj+9G7G8leZSd8TNWZqebOwBPA4JiVtDDubemk4Qr4qYt3ChwNQiwq7Bt var testServerCertPEM = []byte(`-----BEGIN CERTIFICATE-----
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 -----END CERTIFICATE-----`)
6hhvRVYHg1YkZpHlMiFW2m9xWKBPYs6ViUpw8XdGJoVqe7+QVAvwr47DwmgOcVm9
A9O/2FECgYAgttnwo3gBxY0DJdfXBuqZCAa1MMErIxCaKw2Gm9JccnQW0fcuUcb3 var testServerKeyPEM = []byte(`-----BEGIN RSA PRIVATE KEY-----
WSHJPyJ74ktk/QZGEmtKzAxVZ73t14dwHNNDid5CN2FyTIMCeWG5b2vM5NJe8KuQ MIIEowIBAAKCAQEAssNe6c5UiKmC289WlDEgFPNSlx5S0tis0pMK1h8u28UI1I8B
6cJePZj7ZkSvm2tkREdR37Oh2eZqGtaIbj6VTplvKUByWa/TEozMpQ== rZbYQCKZbZaC1T5Z36MU3aV4b6W/ISnafVjME3Xag7MBkx/f0raPTlo7q83rw9//
fD+HarM8NgVZtYExLW8LpGix9pBzhUVkKTPz0zVqifCPQrwWM4cbim7usqdWSW4L
Rzj5em7ysHrnZyHH+HrAVnCxxWoVkhqtO17xnW1xtGFu+l2Q5Xvj1afmLa6aWsqk
GCwG/bbyOfXXkErsTaY3SuUJg+43fXZsUVJITzk1pJ06nTpOMP7ZG/2M8qLO+cU3
7YAMSN6eUJph7dVHJso9kuvE9yoVCgJCw77xmwIDAQABAoIBAEE6CmLTd4LaHzZn
RBcUibk7Q5KCbQQkLYM0Rgr1G9ry3RL6D0mwtb1JIqSa+6gldROl5NIvM2/Bkajf
JasBAI3FPfM6GMP/KGMxW77iK823eGRjUkyavaWQOtMXRrF0r2X9k8jsrqrh8FTb
if2CyF/zqKkmTo+yI4Ovs7viWFR1IFBUHRwfYTTKnXA2q4S39knExALe1wWUkc4L
oOidewQ5IVCU3OQLWXP/beKoV/jw6+dOs5CYjXFsww6tdOsh+WkA9d3/rKPPtLdP
tDQiZtmI6FCYy/PdYqmzY0xg6dipGTDRfENUEx5SJu6HeSoUQUwEpQqnRxIu0iZl
FJ2ZziECgYEAzpdbIrFltGlSh7DIJfnQG86QeOw/nGluFTED9AweRAIzOYnUQCV3
XCKMhFqmzsNpibEC1Cok92ZJk7bfsmPlx+qzL7BFpynA/gezxgc2wNZlWs8btPHi
s9h8hwL5If1FgAMD4E2iJtNgI/Kn5j8SDo/A5hAP1CXv12JRTB+pzlECgYEA3YQ6
e2MLQYLDIcD5RoCrXOc9qo/l46uzo5laIuCKtd/IoOlip95kdgzpQC0/eenDLV9y
KLqAOZxZe+TVKtSOzVGy58FyD6L1oBJgfwuBku1x5ADRsIblq2uIOumDygRU0hMg
0tM3orIFGLyJU5hv6vC0x1ZdIGit0wP4ULhgKisCgYARJs3BLps0BD5+13V2eawG
cvrZnzuUv8gM6FncrBjjKo+YKlI91R54vsGNx3zr05tyfAixFqKlC4/2PIuL4vFT
zK99uRO/Uh8cuAT73uNz1RjrFiDFwANDTSjhiKSoZr+bZiSvPaLFuGzV7zJzUi8s
mFC6iQDXayLjbd00BbjyUQKBgHJD2R74sj+ywhFRR8S0brDXn5mx7LYKRfnoCvTe
uu6iZw2KFhfdwhibBF7UeF/c048+ItcbjTUqj4Y3PjZ/usHymMSvprSmLOnLUPd3
6fjufsdMHN5gV2ybZYRuHEtC/LX4o//ccGB+T964smXqxiB81ePViuhC1xd4fsi0
svZNAoGBALJOOR8ebtgATqc6jpnFxdqNmlwzAf/dH/jMZ6FZrttqIWiwxKvWaWPK
eHJtMmEPMustw/sv1GhDzwWmvgNFPzwEitPKW31m4EdbUCZFxPZ69/BtHTjXD3q3
dP9W+omFXKQ36bVCB6xKmZH/ZVH5iQW0pdkD2JRnUPsDMNBeqmd6
-----END RSA PRIVATE KEY-----`) -----END RSA PRIVATE KEY-----`)
serverPem := []byte(`-----BEGIN CERTIFICATE----- // Starts the test server and returns the TestServer with TLS configured instance.
MIID2zCCAsOgAwIBAgIJALPniQGEq3KtMA0GCSqGSIb3DQEBCwUAMIGDMQswCQYD func StartTestTLSServer(t TestErrHandler, instanceType string, cert, key []byte) TestServer {
VQQGEwJJTjESMBAGA1UECAwJS2FybmF0YWthMRIwEAYDVQQHDAlCZW5nYWx1cnUx
FzAVBgNVBAoMDk1pbmlvVW5pdFRlc3RzMREwDwYDVQQLDAhTU0xUZXN0czEgMB4G
CSqGSIb3DQEJARYRc3NsdGVzdHNAbWluaW8uaW8wHhcNMTYxMDI0MDk1ODQzWhcN
MjYxMDIyMDk1ODQzWjCBgzELMAkGA1UEBhMCSU4xEjAQBgNVBAgMCUthcm5hdGFr
YTESMBAGA1UEBwwJQmVuZ2FsdXJ1MRcwFQYDVQQKDA5NaW5pb1VuaXRUZXN0czER
MA8GA1UECwwIU1NMVGVzdHMxIDAeBgkqhkiG9w0BCQEWEXNzbHRlc3RzQG1pbmlv
LmlvMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwD0kEmvtaHx+M0qJ
AY8zFEn6UpCIbZshNIoXOOr2S3XBEar9gtvTGpL73rPJroVcaTJxavsQJx6iD8E3
8t85rTsrlxEomAk5eKVK3WyplcUuqBgm+KMYyyWxMXgYA3+AumEHiDg1SMIgrWFk
a2x+dSsqRb64tzWtD3LLy/Amq4cdiO1v/v1rNEdqj+9G7G8leZSd8TNWZqebOwBP
A4JiVtDDubemk4Qr4qYt3ChwNQiwq7BtRFR7EokO2an9XfT1NS71evikmGduhBLz
3T+3QinxZDwb6SmNouYJkdqy6oPcWt0zOXDgSPmY1NVlrujJ5JhtQTQxOs6mFVZ/
82mn7wIDAQABo1AwTjAdBgNVHQ4EFgQUv++gaIEUL0sboDER+4KPpiU27FMwHwYD
VR0jBBgwFoAUv++gaIEUL0sboDER+4KPpiU27FMwDAYDVR0TBAUwAwEB/zANBgkq
hkiG9w0BAQsFAAOCAQEAHumbrFEBhN0EWsjZZB/VkArE/owBg7djvNetYE/rEWSV
/dwysQgkTpGrCyfmzSwhsX++gr5a5qh+HAF0Ygufd5OIk/kn9X3pz66Kaq4TYdFO
hc/DUD7wwY3/Mfi9lhT6lKSfMu69D3FuiI+xtUJ7CU8Fhr2ua6UB7e/2inYzsJDN
WYMzrkLMasQNzNWiz3Tditxj1WuuRe9mgXbbBHT03udUyuLi+4ZiOuw6CiJL4Pfk
PAKMo7QWaxAectHZsxvcfH9uYOIuv1AwDUQBA+jhADvLh55epFq0DdJ057+QKItL
vtKIzIB9HcGDFfBvIq+WlxYlQPSIkeq2z1iZaTl11g==
-----END CERTIFICATE-----`)
// Fetch TLS key and pem files from test-data/ directory. // Fetch TLS key and pem files from test-data/ directory.
// dir, _ := os.Getwd() // dir, _ := os.Getwd()
// testDataDir := filepath.Join(filepath.Dir(dir), "test-data") // testDataDir := filepath.Join(filepath.Dir(dir), "test-data")
// //
// pemFile := filepath.Join(testDataDir, "server.pem") // pemFile := filepath.Join(testDataDir, "server.pem")
// keyFile := filepath.Join(testDataDir, "server.key") // keyFile := filepath.Join(testDataDir, "server.key")
cer, err := tls.X509KeyPair(serverPem, serverKey) cer, err := tls.X509KeyPair(cert, key)
if err != nil { if err != nil {
t.Fatalf("Failed to load certificate: %v", err) t.Fatalf("Failed to load certificate: %v", err)
} }
@ -2115,3 +2124,97 @@ func StartTestS3PeerRPCServer(t TestErrHandler) (TestServer, []string) {
testRPCServer.Server = httptest.NewServer(muxRouter) testRPCServer.Server = httptest.NewServer(muxRouter)
return testRPCServer, fsDirs return testRPCServer, fsDirs
} }
// generateTLSCertKey creates valid key/cert with registered DNS or IP address
// depending on the passed parameter. That way, we can use tls config without
// passing InsecureSkipVerify flag. This code is a simplified version of
// https://golang.org/src/crypto/tls/generate_cert.go
func generateTLSCertKey(host string) ([]byte, []byte, error) {
validFor := 365 * 24 * time.Hour
rsaBits := 2048
if len(host) == 0 {
return nil, nil, fmt.Errorf("Missing host parameter")
}
publicKey := func(priv interface{}) interface{} {
switch k := priv.(type) {
case *rsa.PrivateKey:
return &k.PublicKey
case *ecdsa.PrivateKey:
return &k.PublicKey
default:
return nil
}
}
pemBlockForKey := func(priv interface{}) *pem.Block {
switch k := priv.(type) {
case *rsa.PrivateKey:
return &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(k)}
case *ecdsa.PrivateKey:
b, err := x509.MarshalECPrivateKey(k)
if err != nil {
fmt.Fprintf(os.Stderr, "Unable to marshal ECDSA private key: %v", err)
os.Exit(2)
}
return &pem.Block{Type: "EC PRIVATE KEY", Bytes: b}
default:
return nil
}
}
var priv interface{}
var err error
priv, err = rsa.GenerateKey(crand.Reader, rsaBits)
if err != nil {
return nil, nil, fmt.Errorf("failed to generate private key: %s", err)
}
notBefore := time.Now()
notAfter := notBefore.Add(validFor)
serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128)
serialNumber, err := crand.Int(crand.Reader, serialNumberLimit)
if err != nil {
return nil, nil, fmt.Errorf("failed to generate serial number: %s", err)
}
template := x509.Certificate{
SerialNumber: serialNumber,
Subject: pkix.Name{
Organization: []string{"Acme Co"},
},
NotBefore: notBefore,
NotAfter: notAfter,
KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
BasicConstraintsValid: true,
}
hosts := strings.Split(host, ",")
for _, h := range hosts {
if ip := net.ParseIP(h); ip != nil {
template.IPAddresses = append(template.IPAddresses, ip)
} else {
template.DNSNames = append(template.DNSNames, h)
}
}
template.IsCA = true
template.KeyUsage |= x509.KeyUsageCertSign
derBytes, err := x509.CreateCertificate(crand.Reader, &template, &template, publicKey(priv), priv)
if err != nil {
return nil, nil, fmt.Errorf("Failed to create certificate: %s", err)
}
certOut := bytes.NewBuffer([]byte{})
pem.Encode(certOut, &pem.Block{Type: "CERTIFICATE", Bytes: derBytes})
keyOut := bytes.NewBuffer([]byte{})
pem.Encode(keyOut, pemBlockForKey(priv))
return certOut.Bytes(), keyOut.Bytes(), nil
}

@ -0,0 +1,50 @@
# How to secure access to your Minio server with TLS [![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/minio/minio?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
In this document, we will show how to configure your Minio servers with TLS certificates.
## 1. Prerequisites
* Download Minio server from [here](https://docs.minio.io/docs/minio)
## 2. Generate TLS certificate
Minio supports only key/certificate in PEM format.
### With Letsencrypt
Please explore [here](https://docs.minio.io/docs/generate-let-s-encypt-certificate-using-concert-for-minio)
### With generate_cert.go (self-signed certificate)
You need to download [generate_cert.go](https://golang.org/src/crypto/tls/generate_cert.go?m=text) which is a simple go tool for generating self-signed certificates but works for the most of cases.
`generate_cert.go` already provides SAN certificates with DNS and IP entries:
```sh
go run generate_cert.go -ca --host "10.10.0.3"
```
### With OpenSSL:
Generate the private key:
```sh
openssl genrsa -out private.key 1024
```
Generate the self-signed certificate:
```sh
openssl req -new -x509 -days 3650 -key private.key -out public.crt -subj "/C=country/ST=state/L=location/O=organization/CN=domain"
```
## 3. Configure Minio with the generated certificate
To make Minio aware about your generated key and certificate, you will need to put them under `certs` directory in your Minio config path (usually ~/.minio) using the names of `private.key` and `public.crt` for key and certificate files respectively.
## 4. Install third parties CAs
Minio can be configured to connect to other servers, whether Minio nodes or servers like NATs, Redis... If these servers use certificates that are not registerd in one of the known certificates authorities, you can make your Minio trusts them by putting these certificates under `certs/CAs/` in your Minio config path.
# Explore Further
* [Minio Quickstart Guide](https://docs.minio.io/docs/minio-quickstart-guide)
* [Minio Client Complete Guide](https://docs.minio.io/docs/minio-client-complete-guide)
Loading…
Cancel
Save