mirror of
https://github.com/pgsty/minio.git
synced 2026-07-19 12:10:24 +03:00
Add support of user self signed certificates
Additionally add documentation about how to configure TLS with Minio
This commit is contained in:
committed by
Harshavardhana
parent
e216201901
commit
6512d9978e
+24
-1
@@ -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
|
||||
|
||||
+14
-4
@@ -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)
|
||||
|
||||
+155
-52
@@ -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
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user