common/apiserver/hybrid.go (114 lines of code) (raw):
package apiserver
import (
"crypto"
"crypto/md5"
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"encoding/base64"
"encoding/pem"
"io"
"strconv"
"github.com/aliyun/aliyun_assist_client/thirdparty/sirupsen/logrus"
"github.com/google/uuid"
"github.com/aliyun/aliyun_assist_client/agent/hybrid/instance"
"github.com/aliyun/aliyun_assist_client/agent/util/osutil"
"github.com/aliyun/aliyun_assist_client/agent/util/timetool"
"github.com/aliyun/aliyun_assist_client/common/networkcategory"
"github.com/aliyun/aliyun_assist_client/common/requester"
)
const (
// In hybrid instance scenario, domain name <region-id>-axt.aliyuncs.com is used
// first. If it fails, try domain name <region-id>.axt.aliyuncs.com
HybridDomainFirst = "-axt.aliyuncs.com"
HybridDomain = ".axt.aliyuncs.com"
)
type HybridModeProvider struct{}
type HybridModeHTTPHeadersProvider struct {}
var (
hybridModeHTTPHeadersProvider = HybridModeHTTPHeadersProvider{}
)
func (*HybridModeProvider) Name() string {
return "HybridModeProvider"
}
func (p *HybridModeProvider) ServerDomain(logger logrus.FieldLogger) (string, error) {
regionId, err := p.RegionId(logger)
if regionId == "" || err != nil {
return "", requester.ErrNotProvided
}
// Since region id is determined via hybrid cloud-related function,
// network category is set to NetworkHybrid
networkcategory.Set(networkcategory.NetworkHybrid)
if getNetworkTypeInHybrid() == "vpc" {
return regionId + IntranetDomain, nil
} else {
// Try domain region-axt.aliyuncs.com first,
// if not success use region.axt.aliyuncs.com
domain := regionId + HybridDomainFirst
if err := ConnectionDetect(logger, domain); err == nil {
return domain, nil
}
return regionId + HybridDomain, nil
}
}
func (*HybridModeProvider) ExtraHTTPHeaders(logger logrus.FieldLogger) (map[string]string, error) {
return hybridModeHTTPHeadersProvider.ExtraHTTPHeaders(logger)
}
func (*HybridModeProvider) RegionId(logger logrus.FieldLogger) (string, error) {
if !instance.IsHybrid() {
return "", requester.ErrNotProvided
}
if regionId := instance.ReadRegionId(); regionId != "" {
return regionId, nil
}
return "", requester.ErrNotProvided
}
func (*HybridModeHTTPHeadersProvider) ExtraHTTPHeaders(logger logrus.FieldLogger) (map[string]string, error) {
if !instance.IsHybrid() {
return nil, requester.ErrNotProvided
}
u4 := uuid.New()
str_request_id := u4.String()
timestamp := timetool.GetAccurateTime()
str_timestamp := strconv.FormatInt(timestamp, 10)
instanceId := instance.ReadInstanceId()
fingerprint := instance.ReadFingerprint()
priKey := instance.ReadPriKey()
input := instanceId + fingerprint + str_timestamp + str_request_id
output := rsaSign(logger, input, priKey)
logger.Infoln("Hybrid request:", input, output)
extraHeaders := map[string]string{
"x-acs-instance-id": instanceId,
"x-acs-timestamp": str_timestamp,
"x-acs-request-id": str_request_id,
"x-acs-signature": output,
}
internal_ip, err := osutil.ExternalIP()
if err == nil {
extraHeaders["X-Client-IP"] = internal_ip.String()
}
return extraHeaders, nil
}
func getNetworkTypeInHybrid() string {
return instance.ReadNetworkMode()
}
func rsaSign(logger logrus.FieldLogger, data string, keyBytes string) string {
w := md5.New()
io.WriteString(w, data)
md5_byte := w.Sum(nil)
value := rsaSignWithMD5(logger, md5_byte, []byte(keyBytes))
encodeString := base64.StdEncoding.EncodeToString(value)
return encodeString
}
func rsaSignWithMD5(logger logrus.FieldLogger, data []byte, keyBytes []byte) []byte {
block, _ := pem.Decode(keyBytes)
if block == nil {
logger.Errorln("private key error")
return []byte{}
}
privateKey, err := x509.ParsePKCS1PrivateKey(block.Bytes)
if err != nil {
logger.Errorln("ParsePKCS8PrivateKey err")
return []byte{}
}
signature, err := rsa.SignPKCS1v15(rand.Reader, privateKey, crypto.MD5, data)
if err != nil {
logger.Errorln("Error from signing")
return []byte{}
}
return signature
}