mirror of
https://github.com/minio/minio.git
synced 2024-12-23 21:55:53 -05:00
Add support of user self signed certificates
Additionally add documentation about how to configure TLS with Minio
This commit is contained in:
parent
e216201901
commit
6512d9978e
25
cmd/certs.go
25
cmd/certs.go
@ -31,7 +31,11 @@ func createCertsPath() error {
|
||||
if err != nil {
|
||||
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.
|
||||
@ -62,6 +66,25 @@ func mustGetKeyFile() string {
|
||||
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
|
||||
// found, false otherwise.
|
||||
func isCertFileExists() bool {
|
||||
|
@ -17,6 +17,7 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"crypto/x509"
|
||||
"time"
|
||||
|
||||
"github.com/fatih/color"
|
||||
@ -33,6 +34,7 @@ const (
|
||||
globalMinioConfigVersion = "9"
|
||||
globalMinioConfigDir = ".minio"
|
||||
globalMinioCertsDir = "certs"
|
||||
globalMinioCertsCADir = "CAs"
|
||||
globalMinioCertFile = "public.crt"
|
||||
globalMinioKeyFile = "private.key"
|
||||
globalMinioConfigFile = "config.json"
|
||||
@ -59,6 +61,9 @@ var (
|
||||
// Peer communication struct
|
||||
globalS3Peers = s3Peers{}
|
||||
|
||||
// CA root certificates, a nil value means system certs pool will be used
|
||||
globalRootCAs *x509.CertPool
|
||||
|
||||
// Add new variable global values here.
|
||||
)
|
||||
|
||||
|
@ -81,9 +81,10 @@ func (rpcClient *RPCClient) dialRPCClient() (*rpc.Client, error) {
|
||||
hostname, _, splitErr := net.SplitHostPort(rpcClient.node)
|
||||
if splitErr != nil {
|
||||
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
|
||||
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 {
|
||||
// Have a dial timeout with 3 secs.
|
||||
conn, err = net.DialTimeout("tcp", rpcClient.node, 3*time.Second)
|
||||
|
@ -18,6 +18,7 @@ package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
@ -170,12 +171,34 @@ func finalizeEndpoints(tls bool, apiServer *http.Server) (endPoints []string) {
|
||||
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.
|
||||
func initServerConfig(c *cli.Context) {
|
||||
// Create certs path.
|
||||
err := createCertsPath()
|
||||
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
|
||||
if os.Getenv("MINIO_ACCESS_KEY") != "" && os.Getenv("MINIO_SECRET_KEY") != "" {
|
||||
// Env credentials are already loaded in serverConfig, just save in the disk
|
||||
|
@ -20,6 +20,7 @@ import (
|
||||
"bytes"
|
||||
"crypto/md5"
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"encoding/base64"
|
||||
"encoding/hex"
|
||||
"encoding/xml"
|
||||
@ -64,11 +65,20 @@ var _ = Suite(&TestSuiteCommon{serverType: "XL", signer: signerV4})
|
||||
// Starting the Test server with temporary FS backend.
|
||||
func (s *TestSuiteCommon) SetUpSuite(c *C) {
|
||||
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{
|
||||
TLSClientConfig: &tls.Config{
|
||||
InsecureSkipVerify: true,
|
||||
},
|
||||
TLSClientConfig: tlsConfig,
|
||||
}
|
||||
} else {
|
||||
s.testServer = StartTestServer(c, s.serverType)
|
||||
|
@ -19,16 +19,23 @@ package cmd
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"crypto/ecdsa"
|
||||
"crypto/hmac"
|
||||
crand "crypto/rand"
|
||||
"crypto/rsa"
|
||||
"crypto/sha1"
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"crypto/x509/pkix"
|
||||
"encoding/base64"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"encoding/pem"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"math/big"
|
||||
"math/rand"
|
||||
"net"
|
||||
"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.
|
||||
func StartTestTLSServer(t TestErrHandler, instanceType string) TestServer {
|
||||
serverKey := []byte(`-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIEpAIBAAKCAQEAwD0kEmvtaHx+M0qJAY8zFEn6UpCIbZshNIoXOOr2S3XBEar9
|
||||
gtvTGpL73rPJroVcaTJxavsQJx6iD8E38t85rTsrlxEomAk5eKVK3WyplcUuqBgm
|
||||
+KMYyyWxMXgYA3+AumEHiDg1SMIgrWFka2x+dSsqRb64tzWtD3LLy/Amq4cdiO1v
|
||||
/v1rNEdqj+9G7G8leZSd8TNWZqebOwBPA4JiVtDDubemk4Qr4qYt3ChwNQiwq7Bt
|
||||
RFR7EokO2an9XfT1NS71evikmGduhBLz3T+3QinxZDwb6SmNouYJkdqy6oPcWt0z
|
||||
OXDgSPmY1NVlrujJ5JhtQTQxOs6mFVZ/82mn7wIDAQABAoIBAQCWiIoRntAGLM5J
|
||||
7cjBHthZv+Az/RfH9F0ZHjU3Dc6VonzwD9x6NxbkzUpLxq9caPPHMIfdxQGOEI/J
|
||||
FH1yQtiQTTBCGF6YR0jor06jey6EqCZz3I3Pzy9gDIDnguoS+ynbSJW0VodrFRCv
|
||||
k/8lm4yexZFRkhpk5LRCz5rEdKZjU4kBgTBzeD6P1JbYKfAs49A99x9L42hExwfv
|
||||
ppX/7ECbdMTQRVgDytOJpQR+mrrEHq30lxNZg0XngGm/4Rby8Ga6cfxmQbUrj5of
|
||||
uA9TsQ6CAmTy6OqagLK4Rr9tSd4cjbBm2MCs2bDMYhzkhsveoFidsF1A9S3zSo/z
|
||||
VJlqFtXpAoGBAP2ewImNRpaa0D1TWk/559XZJ64MMd4J0VK4cGzXPeBZ8WGVJxqF
|
||||
PLl74AXG7/Iu18EWMHqTuMxlrkTKpF6KF9G5RCmAFi+UzVVspj9uvAk8SrFUA5P7
|
||||
c7Ahnmz44isD7OJ6sHUOP1d88dehODQdRAp5hX0h+rsTH3L6g3QRnEEdAoGBAMIK
|
||||
8DJMsl2dmuuV4WPrgoqdnDnSmuC5YqxibJPJnZpgp19IxlIYRYtuUZjHIYx7OM/r
|
||||
1X/dIvNqpFbvTnT9XFHWSyYMqal1+OY1Sg9i9E6YKuPAW2wccf3svhzehc98vJ0j
|
||||
d7S81UpfKKWY+uD/wvOJdV1Pw7SoSvs5pmbFuKt7AoGAUY7ClblDsNy6CG6MhVl0
|
||||
7zT06KhtRNzdXn+HT8jr0gC6ecnwGDwuaetnABSYRsY/hY0wK8rjS3+LSf3sW6aG
|
||||
wF+Whs301HpCiaz1zUI737BuyJWezPC4pDQ7cQmcGX8apz4TDqF1Rxob316t5zxe
|
||||
DAxGHBZYPd6JZ30d1q5vFBUCgYEAvnaOHlE6Irm4ftW3TqS0lerulbMrYrmVKS/S
|
||||
851KnWWR4+1C/QHmAV5fqV6Mh5/LvAr4nXEqBVP/y3VJxXuLSqjVSpvTTQsHLK/R
|
||||
6hhvRVYHg1YkZpHlMiFW2m9xWKBPYs6ViUpw8XdGJoVqe7+QVAvwr47DwmgOcVm9
|
||||
A9O/2FECgYAgttnwo3gBxY0DJdfXBuqZCAa1MMErIxCaKw2Gm9JccnQW0fcuUcb3
|
||||
WSHJPyJ74ktk/QZGEmtKzAxVZ73t14dwHNNDid5CN2FyTIMCeWG5b2vM5NJe8KuQ
|
||||
6cJePZj7ZkSvm2tkREdR37Oh2eZqGtaIbj6VTplvKUByWa/TEozMpQ==
|
||||
// testServerCertPEM and testServerKeyPEM are generated by
|
||||
// https://golang.org/src/crypto/tls/generate_cert.go
|
||||
// $ go run generate_cert.go -ca --host 127.0.0.1
|
||||
// The generated certificate contains IP SAN, that way we don't need
|
||||
// to enable InsecureSkipVerify in TLS config
|
||||
|
||||
var testServerCertPEM = []byte(`-----BEGIN CERTIFICATE-----
|
||||
MIIC9zCCAd+gAwIBAgIQV9ukx5ZahXeFygLXnR1WJTANBgkqhkiG9w0BAQsFADAS
|
||||
MRAwDgYDVQQKEwdBY21lIENvMB4XDTE2MTExNTE1MDQxNFoXDTE3MTExNTE1MDQx
|
||||
NFowEjEQMA4GA1UEChMHQWNtZSBDbzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC
|
||||
AQoCggEBALLDXunOVIipgtvPVpQxIBTzUpceUtLYrNKTCtYfLtvFCNSPAa2W2EAi
|
||||
mW2WgtU+Wd+jFN2leG+lvyEp2n1YzBN12oOzAZMf39K2j05aO6vN68Pf/3w/h2qz
|
||||
PDYFWbWBMS1vC6RosfaQc4VFZCkz89M1aonwj0K8FjOHG4pu7rKnVkluC0c4+Xpu
|
||||
8rB652chx/h6wFZwscVqFZIarTte8Z1tcbRhbvpdkOV749Wn5i2umlrKpBgsBv22
|
||||
8jn115BK7E2mN0rlCYPuN312bFFSSE85NaSdOp06TjD+2Rv9jPKizvnFN+2ADEje
|
||||
nlCaYe3VRybKPZLrxPcqFQoCQsO+8ZsCAwEAAaNJMEcwDgYDVR0PAQH/BAQDAgKk
|
||||
MBMGA1UdJQQMMAoGCCsGAQUFBwMBMA8GA1UdEwEB/wQFMAMBAf8wDwYDVR0RBAgw
|
||||
BocEfwAAATANBgkqhkiG9w0BAQsFAAOCAQEAsmNCixmx+srB93+Jz5t90zzCJN4O
|
||||
5RDWh7X7D54xtRRZ/t9HLLLFKW9EqhAM17xee3C4eNCicOqHP/htEvLwt3BWFmya
|
||||
djvIUQYfymx4GtBTfMH4eC5vYGdxSuTVNe7JGHMpJjArNe4vIlUHyj2n12aGDHUf
|
||||
NKEiTR2m+6hiKEyym74vhxGnl208OFa4tAMv3J7BjEObE37oy/vH/getE0HwG/EL
|
||||
feE4D2Pp9XqeMCg/sPZPoQgBuq3QsL2RdL8DQywb/HrApdLyfmN0avV5tmbrm0cL
|
||||
/0NUqCWjJIIKF0XxZbqlkQsYK5zpDJ36MFXO65aF3QGOMP1rlBD3d0S6kw==
|
||||
-----END CERTIFICATE-----`)
|
||||
|
||||
var testServerKeyPEM = []byte(`-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIEowIBAAKCAQEAssNe6c5UiKmC289WlDEgFPNSlx5S0tis0pMK1h8u28UI1I8B
|
||||
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-----`)
|
||||
|
||||
serverPem := []byte(`-----BEGIN CERTIFICATE-----
|
||||
MIID2zCCAsOgAwIBAgIJALPniQGEq3KtMA0GCSqGSIb3DQEBCwUAMIGDMQswCQYD
|
||||
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-----`)
|
||||
// Starts the test server and returns the TestServer with TLS configured instance.
|
||||
func StartTestTLSServer(t TestErrHandler, instanceType string, cert, key []byte) TestServer {
|
||||
// Fetch TLS key and pem files from test-data/ directory.
|
||||
// dir, _ := os.Getwd()
|
||||
// testDataDir := filepath.Join(filepath.Dir(dir), "test-data")
|
||||
//
|
||||
// pemFile := filepath.Join(testDataDir, "server.pem")
|
||||
// keyFile := filepath.Join(testDataDir, "server.key")
|
||||
cer, err := tls.X509KeyPair(serverPem, serverKey)
|
||||
cer, err := tls.X509KeyPair(cert, key)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to load certificate: %v", err)
|
||||
}
|
||||
@ -2115,3 +2124,97 @@ func StartTestS3PeerRPCServer(t TestErrHandler) (TestServer, []string) {
|
||||
testRPCServer.Server = httptest.NewServer(muxRouter)
|
||||
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
|
||||
}
|
||||
|
50
docs/configure-minio-with-tls.md
Normal file
50
docs/configure-minio-with-tls.md
Normal file
@ -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…
Reference in New Issue
Block a user