Files
cloudpods/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/certificate.go
2025-07-14 16:06:11 +08:00

398 lines
10 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// Copyright 2019 Yunion
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package qcloud
import (
"crypto/sha1"
"fmt"
"strconv"
"strings"
"time"
"yunion.io/x/jsonutils"
"yunion.io/x/pkg/errors"
"yunion.io/x/cloudmux/pkg/apis"
"yunion.io/x/cloudmux/pkg/cloudprovider"
"yunion.io/x/cloudmux/pkg/multicloud"
)
var CERT_STATUS_MAP = map[int]string{
0: "pending",
1: "normal",
2: "deleted",
3: "expired",
4: "normal",
5: "pending",
6: "deleted",
7: "deleted",
8: "pending",
}
type projectInfo struct {
ProjectID string `json:"projectId"`
OwnerUin int64 `json:"ownerUin"`
Name string `json:"name"`
CreatorUin int64 `json:"creatorUin"`
CreateTime string `json:"createTime"`
Info string `json:"info"`
}
// https://cloud.tencent.com/document/api/400/13675
type SCertificate struct {
multicloud.SCertificateBase
QcloudTags
client *SQcloudClient
CertificateID string `json:"CertificateId"`
CertificateType string `json:"CertificateType"`
Deployable bool `json:"Deployable"`
RenewAble bool `json:"RenewAble"`
OwnerUin string `json:"ownerUin"`
ProjectID string `json:"projectId"`
From string `json:"from"`
ProductZhName string `json:"productZhName"`
Domain string `json:"domain"`
Alias string `json:"alias"`
Status int `json:"status"`
VulnerabilityStatus string `json:"vulnerability_status"`
CERTBeginTime time.Time `json:"certBeginTime"`
CERTEndTime time.Time `json:"certEndTime"`
ValidityPeriod string `json:"validityPeriod"`
InsertTime string `json:"insertTime"`
ProjectInfo projectInfo `json:"projectInfo"`
StatusName string `json:"status_name"`
IsVip bool `json:"is_vip"`
IsDv bool `json:"is_dv"`
IsWildcard bool `json:"is_wildcard"`
IsVulnerability bool `json:"is_vulnerability"`
// certificate details
detailsInitd bool `json:"details_initd"`
SubjectAltName []string `json:"subjectAltName"`
CertificatePrivateKey string `json:"CertificatePrivateKey"`
CertificatePublicKey string `json:"CertificatePublicKey"`
CertFingerprint string `json:"CertFingerprint"`
}
func (self *SCertificate) GetDetails() (*SCertificate, error) {
if !self.detailsInitd {
var (
cert *SCertificate
err error
)
cert, err = self.client.GetCertificate(self.GetId())
if err != nil {
return nil, err
}
self.detailsInitd = true
self.SubjectAltName = cert.SubjectAltName
self.CertificatePrivateKey = cert.CertificatePrivateKey
self.CertificatePublicKey = cert.CertificatePublicKey
self.CertFingerprint = cert.CertFingerprint
}
return self, nil
}
func (self *SCertificate) GetPublickKey() string {
self.GetDetails()
return self.CertificatePublicKey
}
func (self *SCertificate) GetPrivateKey() string {
self.GetDetails()
return self.CertificatePrivateKey
}
func (self *SCertificate) GetCert() string {
self.GetDetails()
return self.CertificatePublicKey
}
func (self *SCertificate) GetKey() string {
self.GetDetails()
return self.CertificatePrivateKey
}
func (self *SCertificate) Delete() error {
return self.client.DeleteCertificate(self.GetId())
}
func (self *SCertificate) GetId() string {
return self.CertificateID
}
func (self *SCertificate) GetName() string {
if len(self.Alias) > 0 {
return self.Alias
} else {
return self.Domain
}
}
func (self *SCertificate) GetGlobalId() string {
return self.CertificateID
}
func (self *SCertificate) GetStatus() string {
status, ok := CERT_STATUS_MAP[self.Status]
if !ok {
return apis.STATUS_UNKNOWN
}
switch status {
case "normal":
return apis.STATUS_AVAILABLE
case "deleted":
return apis.STATUS_DELETING
case "pending":
return apis.STATUS_CREATING
default:
return status
}
}
func (self *SCertificate) Refresh() error {
cert, err := self.client.GetCertificate(self.GetId())
if err != nil {
return errors.Wrap(err, "GetCertificate")
}
return jsonutils.Update(self, cert)
}
func (self *SCertificate) GetCommonName() string {
return self.Domain
}
func (self *SCertificate) GetSubjectAlternativeNames() string {
self.GetDetails()
return self.CertFingerprint
}
func (self *SCertificate) GetFingerprint() string {
self.GetDetails()
_fp := sha1.Sum([]byte(self.CertificatePublicKey))
fp := fmt.Sprintf("sha1:% x", _fp)
return strings.Replace(fp, " ", ":", -1)
}
func (self *SCertificate) GetExpireTime() time.Time {
return self.CERTEndTime
}
func (self *SCertificate) GetProjectId() string {
return self.ProjectID
}
func (self *SCertificate) GetSans() string {
return strings.Join(self.SubjectAltName, ",")
}
func (self *SCertificate) GetStartDate() time.Time {
return self.CERTBeginTime
}
func (self *SCertificate) GetProvince() string {
return ""
}
func (self *SCertificate) GetCommon() string {
return self.Domain
}
func (self *SCertificate) GetCountry() string {
return ""
}
func (self *SCertificate) GetIssuer() string {
return self.ProductZhName
}
func (self *SCertificate) GetEndDate() time.Time {
return self.CERTEndTime
}
func (self *SCertificate) GetCity() string {
return ""
}
func (self *SCertificate) GetOrgName() string {
return ""
}
func (self *SCertificate) GetIsUpload() bool {
if self.From == "upload" {
return true
}
return false
}
// https://cloud.tencent.com/document/product/400/41674
func (self *SQcloudClient) GetCertificate(certId string) (*SCertificate, error) {
params := map[string]string{
"CertificateId": certId,
}
resp, err := self.sslRequest("DescribeCertificateDetail", params)
if err != nil {
return nil, errors.Wrap(err, "DescribeCertificateDetail")
}
cert := &SCertificate{client: self}
err = resp.Unmarshal(cert)
if err != nil {
return nil, errors.Wrap(err, "Unmarshal")
}
return cert, nil
}
// https://cloud.tencent.com/document/product/400/41665
// 返回证书ID
func (self *SQcloudClient) CreateCertificate(projectId, publicKey, privateKey, certType, desc string) (string, error) {
params := map[string]string{
"CertificatePublicKey": publicKey,
"CertificateType": certType,
"Alias": desc,
}
if len(privateKey) > 0 {
params["CertificatePrivateKey"] = privateKey
} else {
if certType == "SVR" {
return "", fmt.Errorf("certificate private key required while certificate type is SVR")
}
}
if len(projectId) > 0 {
params["ProjectId"] = projectId
}
resp, err := self.sslRequest("UploadCertificate", params)
if err != nil {
return "", err
}
return resp.GetString("CertificateId")
}
// https://cloud.tencent.com/document/product/400/41675
func (self *SQcloudClient) DeleteCertificate(id string) error {
if len(id) == 0 {
return fmt.Errorf("DelteCertificate certificate id should not be empty")
}
params := map[string]string{"CertificateId": id}
resp, err := self.sslRequest("DeleteCertificate", params)
if err != nil {
return errors.Wrap(err, "DeleteCertificate")
}
if deleted, _ := resp.Bool("DeleteResult"); deleted {
return nil
}
return fmt.Errorf("DeleteCertificate %s", resp)
}
func (self *SRegion) GetILoadBalancerCertificates() ([]cloudprovider.ICloudLoadbalancerCertificate, error) {
if self.Region != QCLOUD_DEFAULT_REGION {
return []cloudprovider.ICloudLoadbalancerCertificate{}, nil
}
certs, err := self.client.GetCertificates("", "", "")
if err != nil {
return nil, errors.Wrap(err, "GetCertificates")
}
icerts := make([]cloudprovider.ICloudLoadbalancerCertificate, len(certs))
for i := range certs {
certs[i].client = self.client
icerts[i] = &certs[i]
}
return icerts, nil
}
func (self *SRegion) GetILoadBalancerCertificateById(certId string) (cloudprovider.ICloudLoadbalancerCertificate, error) {
cert, err := self.client.GetCertificate(certId)
if err != nil {
return nil, errors.Wrap(err, "GetCertificate")
}
return cert, nil
}
// todo:目前onecloud端只能指定服务器端证书。需要兼容客户端证书
// todo:支持指定Project。
// todo: 已过期的证书不能上传也不能关联资源
func (self *SRegion) CreateILoadBalancerCertificate(input *cloudprovider.SLoadbalancerCertificate) (cloudprovider.ICloudLoadbalancerCertificate, error) {
certId, err := self.client.CreateCertificate("", input.Certificate, input.PrivateKey, "SVR", input.Name)
if err != nil {
return nil, err
}
cert, err := self.client.GetCertificate(certId)
if err != nil {
return nil, errors.Wrapf(err, "GetCertificate")
}
return cert, nil
}
func (self *SQcloudClient) GetCertificates(projectId, certificateStatus, searchKey string) ([]SCertificate, error) {
params := map[string]string{}
params["Limit"] = "100"
if len(projectId) > 0 {
params["ProjectId"] = projectId
}
if len(certificateStatus) > 0 {
params["CertificateStatus.0"] = certificateStatus
}
if len(searchKey) > 0 {
params["SearchKey"] = searchKey
}
certs := []SCertificate{}
offset := 0
total := 100
for total > offset {
params["Offset"] = strconv.Itoa(offset)
resp, err := self.sslRequest("DescribeCertificates", params)
if err != nil {
return nil, errors.Wrap(err, "DescribeCertificates")
}
_certs := []SCertificate{}
err = resp.Unmarshal(&certs, "Certificates")
if err != nil {
return nil, errors.Wrap(err, "Unmarshal.Certificates")
}
err = resp.Unmarshal(&total, "TotalCount")
if err != nil {
return nil, errors.Wrap(err, "Unmarshal.TotalCount")
}
for i := range _certs {
_certs[i].client = self
certs = append(certs, _certs[i])
}
offset += 100
}
return certs, nil
}