mirror of
https://github.com/yunionio/cloudpods.git
synced 2026-09-24 16:03:43 +08:00
Automatic merge from release/2.2.0 -> release/2.3.0
* commit 'a72b479bdb8bf848b48a315fb667ec4ee38142fc': 改进:允许climc指定tls证书,允许服务指定tls证书
This commit is contained in:
+12
-6
@@ -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
@@ -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
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
}
|
||||
@@ -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]))
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user