Automatic merge from release/2.2.0 -> release/2.3.0

* commit 'a72b479bdb8bf848b48a315fb667ec4ee38142fc':
  改进:允许climc指定tls证书,允许服务指定tls证书
This commit is contained in:
邱剑
2018-10-18 16:01:19 +08:00
9 changed files with 159 additions and 17 deletions
+12 -6
View File
@@ -23,11 +23,15 @@ import (
)
type BaseOptions struct {
Help bool `help:"Show help" short-token:"h"`
Debug bool `help:"Show debug information"`
Version bool `help:"Show version"`
Timeout int `default:"600" help:"Number of seconds to wait for a response"`
Insecure bool `default:"false" help:"Allow skip server cert verification if URL is https" short-token:"k"`
Help bool `help:"Show help" short-token:"h"`
Debug bool `help:"Show debug information"`
Version bool `help:"Show version"`
Timeout int `default:"600" help:"Number of seconds to wait for a response"`
Insecure bool `default:"false" help:"Allow skip server cert verification if URL is https" short-token:"k"`
CertFile string `default:"$YUNION_CERT_FILE" help:"certificate file"`
KeyFile string `default:"$YUNION_KEY_FILE" help:"private key file"`
UseCachedToken bool `default:"$YUNION_USE_CACHED_TOKEN|false" help:"Use cached token"`
OsUsername string `default:"$OS_USERNAME" help:"Username, defaults to env[OS_USERNAME]"`
OsPassword string `default:"$OS_PASSWORD" help:"Password, defaults to env[OS_PASSWORD]"`
@@ -124,7 +128,9 @@ func newClientSession(options *BaseOptions) (*mcclient.ClientSession, error) {
client := mcclient.NewClient(options.OsAuthURL,
options.Timeout,
options.Debug,
options.Insecure)
options.Insecure,
options.CertFile,
options.KeyFile)
var cacheToken mcclient.TokenCredential
authUrlAlter := strings.Replace(options.OsAuthURL, "/", "", -1)
+14 -1
View File
@@ -309,7 +309,7 @@ func timeoutHandle(h http.Handler) http.HandlerFunc {
}
}
func (app *Application) ListenAndServe(addr string) {
func (app *Application) initServer(addr string) *http.Server {
db := AppContextDB(app.context)
if db != nil {
db.SetMaxIdleConns(app.connMax + 1)
@@ -325,8 +325,21 @@ func (app *Application) ListenAndServe(addr string) {
WriteTimeout: app.writeTimeout,
MaxHeaderBytes: 1 << 20,
}
return s
}
func (app *Application) ListenAndServe(addr string) {
s := app.initServer(addr)
err := s.ListenAndServe()
if err != nil {
log.Fatalf("ListAndServer fail: %s", err)
}
}
func (app *Application) ListenAndServeTLS(addr string, certFile, keyFile string) {
s := app.initServer(addr)
err := s.ListenAndServeTLS(certFile, keyFile)
if err != nil && err != http.ErrServerClosed {
log.Fatalf("ListAndServer fail: %s", err)
}
}
+10 -2
View File
@@ -22,6 +22,14 @@ func InitApp(options *Options) *appsrv.Application {
func ServeForever(app *appsrv.Application, options *Options) {
addr := net.JoinHostPort(options.Address, strconv.Itoa(options.Port))
log.Infof("Start listen on %s", addr)
app.ListenAndServe(addr)
proto := "http"
if options.EnableSsl {
proto = "https"
}
log.Infof("Start listen on %s://%s", proto, addr)
if options.EnableSsl {
app.ListenAndServeTLS(addr, options.SslCertfile, options.SslKeyfile)
} else {
app.ListenAndServe(addr)
}
}
+1 -1
View File
@@ -36,7 +36,7 @@ func InitAuth(options *Options, authComplete auth.AuthCompletedCallback) {
// debug := options.LogLevel == "debug"
auth.Init(a, false, true) // , authComplete)
auth.Init(a, false, true, options.SslCertfile, options.SslKeyfile) // , authComplete)
authComplete()
}
+4
View File
@@ -36,6 +36,10 @@ type Options struct {
GlobalVirtualResourceNamespace bool `help:"Per project namespace or global namespace for virtual resources"`
DebugSqlchemy bool `default:"False" help:"Print SQL executed by sqlchemy"`
EnableSsl bool `help:"Enable https"`
SslCertfile string `help:"ssl certification file"`
SslKeyfile string `help:"ssl certification key file"`
structarg.BaseOptions
}
+4 -4
View File
@@ -239,8 +239,8 @@ func (callback *AuthCompletedCallback) Run() {
}
}
func AsyncInit(info *AuthInfo, debug, insecure bool, callback AuthCompletedCallback) {
cli := mcclient.NewClient(info.AuthUrl, defaultTimeout, debug, insecure)
func AsyncInit(info *AuthInfo, debug, insecure bool, certFile, keyFile string, callback AuthCompletedCallback) {
cli := mcclient.NewClient(info.AuthUrl, defaultTimeout, debug, insecure, certFile, keyFile)
manager = newAuthManager(cli, info)
go manager.init()
if callback != nil {
@@ -248,12 +248,12 @@ func AsyncInit(info *AuthInfo, debug, insecure bool, callback AuthCompletedCallb
}
}
func Init(info *AuthInfo, debug, insecure bool) {
func Init(info *AuthInfo, debug, insecure bool, certFile, keyFile string) {
done := make(chan bool, 1)
f := func() {
done <- true
}
AsyncInit(info, debug, insecure, f)
AsyncInit(info, debug, insecure, certFile, keyFile, f)
<-done
}
+21 -3
View File
@@ -11,6 +11,8 @@ import (
"yunion.io/x/jsonutils"
"yunion.io/x/log"
"yunion.io/x/onecloud/pkg/util/httputils"
"yunion.io/x/onecloud/pkg/util/seclib2"
"yunion.io/yunioncloud/pkg/gotypes"
)
type Client struct {
@@ -22,10 +24,26 @@ type Client struct {
serviceCatalog IServiceCatalog
}
func NewClient(authUrl string, timeout int, debug bool, insecure bool) *Client {
tr := &http.Transport{
TLSClientConfig: &tls.Config{InsecureSkipVerify: insecure},
func NewClient(authUrl string, timeout int, debug bool, insecure bool, certFile, keyFile string) *Client {
var tlsConf *tls.Config
if len(certFile) > 0 && len(keyFile) > 0 {
var err error
tlsConf, err = seclib2.InitTLSConfig(certFile, keyFile)
if err != nil {
log.Errorf("load TLS failed %s", err)
}
}
if tlsConf == nil || gotypes.IsNil(tlsConf) {
tlsConf = &tls.Config{}
}
tlsConf.InsecureSkipVerify = insecure
tr := &http.Transport{
TLSClientConfig: tlsConf,
}
client := Client{authUrl: authUrl,
timeout: timeout,
debug: debug,
+74
View File
@@ -0,0 +1,74 @@
package seclib2
import (
"io/ioutil"
"crypto/tls"
"crypto/x509"
"bytes"
"yunion.io/x/log"
)
var CERT_SEP = []byte("-END CERTIFICATE-")
func findCertEndIndex(certBytes []byte) int {
endpos := bytes.Index(certBytes, CERT_SEP)
if endpos < 0 {
return endpos
}
endpos += len(CERT_SEP)
for endpos < len(certBytes) && certBytes[endpos] != '\n' {
endpos += 1
}
return endpos
}
func splitCert(certBytes []byte) [][]byte {
ret := make([][]byte, 0)
for {
endpos := findCertEndIndex(certBytes)
if endpos > 0 {
ret = append(ret, certBytes[:endpos])
for endpos < len(certBytes) && certBytes[endpos] != '-' {
endpos += 1
}
if endpos < len(certBytes) {
certBytes = certBytes[endpos:]
} else {
break
}
}
}
return ret
}
func InitTLSConfig(certFile, keyFile string) (*tls.Config, error) {
allCertPEM, err := ioutil.ReadFile(certFile)
if err != nil {
log.Errorf("read tls certfile fail %s", err)
return nil, err
}
certPEMs := splitCert(allCertPEM)
keyPEM, err := ioutil.ReadFile(keyFile)
if err != nil {
log.Errorf("read tls keyfile fail %s", err)
return nil, err
}
cert, err := tls.X509KeyPair(certPEMs[0], keyPEM)
if err != nil {
return nil, err
}
caCertPool := x509.NewCertPool()
for i := 1; i < len(certPEMs); i += 1 {
caCertPool.AppendCertsFromPEM(certPEMs[i])
}
tlsConfig := &tls.Config{
Certificates: []tls.Certificate{cert},
RootCAs: caCertPool,
}
// tlsConfig.ServerName = "CN=*"
tlsConfig.BuildNameToCertificate()
return tlsConfig, nil
}
+19
View File
@@ -0,0 +1,19 @@
package seclib2
import "testing"
func TestSplitCert(t *testing.T) {
PEM := `-----BEGIN CERTIFICATE-----
MIIFADCCA+igAwIBAgIRAOMlOS6MEmLdT29AN1e8XfgwDQYJKoZIhvcNAQELBQAw
6vetSmRT35g6Tf/bZyPtPLnBOw4bpZtN/9KWJ5pJtKN80hgc
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIE2jCCA8KgAwIBAgIJAJlb8KChCsV+MA0GCSqGSIb3DQEBCwUAMIGfMQswCQYD
Fc5CzfQAhw57y6LmnPVoKAE/TFHvvSFNxjwSaBCGQ46FfnZMjs48a2xwHaqwAw==
-----END CERTIFICATE-----
`
pems := splitCert([]byte(PEM))
for i := 0; i < len(pems); i += 1 {
t.Logf("\n%s\n", string(pems[i]))
}
}