Chun Han 69f3aab229
feat: milvus support huawei cloud iam verification(#45298) (#45457)
related: #45298

Signed-off-by: MrPresent-Han <chun.han@gmail.com>
Co-authored-by: MrPresent-Han <chun.han@gmail.com>
2025-11-11 14:41:41 +08:00

148 lines
4.3 KiB
Go

// Licensed to the LF AI & Data foundation under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you 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 huawei
import (
"fmt"
"os"
"sync"
"time"
"github.com/cockroachdb/errors"
"github.com/huaweicloud/huaweicloud-sdk-go-v3/core/auth"
"github.com/huaweicloud/huaweicloud-sdk-go-v3/core/auth/provider"
"github.com/huaweicloud/huaweicloud-sdk-go-v3/core/config"
"github.com/huaweicloud/huaweicloud-sdk-go-v3/core/region"
iam "github.com/huaweicloud/huaweicloud-sdk-go-v3/services/iam/v3"
"github.com/huaweicloud/huaweicloud-sdk-go-v3/services/iam/v3/model"
iamRegion "github.com/huaweicloud/huaweicloud-sdk-go-v3/services/iam/v3/region"
"github.com/minio/minio-go/v7"
minioCred "github.com/minio/minio-go/v7/pkg/credentials"
)
func NewMinioClient(address string, opts *minio.Options) (*minio.Client, error) {
if opts == nil {
opts = &minio.Options{}
}
if opts.Creds == nil {
credProvider := NewCredentialProvider()
opts.Creds = minioCred.New(credProvider)
}
if address == "" {
address = fmt.Sprintf("obs.%s.myhuaweicloud.com", opts.Region)
opts.Secure = true
}
return minio.New(address, opts)
}
func NewCredentialProvider() minioCred.Provider {
return &HuaweiCredentialProvider{}
}
type HuaweiCredentialProvider struct {
credentials minioCred.Value
expiration time.Time
basicCred auth.ICredential
regionObj *region.Region
iamClient *iam.IamClient
initOnce sync.Once
initErr error
}
func (p *HuaweiCredentialProvider) initClients() {
p.initOnce.Do(func() {
basicChain := provider.BasicCredentialProviderChain()
basicCred, err := basicChain.GetCredentials()
if err != nil {
p.initErr = errors.Wrap(err, "failed to get basic credentials")
return
}
p.basicCred = basicCred
regionName := os.Getenv("HUAWEICLOUD_SDK_REGION")
if regionName == "" {
regionName = "cn-east-3"
}
regionObj, err := iamRegion.SafeValueOf(regionName)
if err != nil {
regionObj, _ = iamRegion.SafeValueOf("cn-east-3")
}
p.regionObj = regionObj
hcClient, err := iam.IamClientBuilder().
WithRegion(p.regionObj).
WithCredential(p.basicCred).
WithHttpConfig(config.DefaultHttpConfig()).
SafeBuild()
if err != nil {
p.initErr = errors.Wrap(err, "failed to build IAM client")
return
}
p.iamClient = iam.NewIamClient(hcClient)
})
}
func (p *HuaweiCredentialProvider) Retrieve() (minioCred.Value, error) {
p.initClients()
if p.initErr != nil {
return minioCred.Value{}, p.initErr
}
request := &model.CreateTemporaryAccessKeyByTokenRequest{
Body: &model.CreateTemporaryAccessKeyByTokenRequestBody{
Auth: &model.TokenAuth{
Identity: &model.TokenAuthIdentity{
Methods: []model.TokenAuthIdentityMethods{model.GetTokenAuthIdentityMethodsEnum().TOKEN},
},
},
},
}
response, err := p.iamClient.CreateTemporaryAccessKeyByToken(request)
if err != nil {
return minioCred.Value{}, errors.Wrap(err, "failed to create temporary access key")
}
if response.Credential == nil {
return minioCred.Value{}, errors.New("no credential returned from Huawei Cloud")
}
expiration, err := time.Parse("2006-01-02T15:04:05Z", response.Credential.ExpiresAt)
if err != nil {
return minioCred.Value{}, errors.Wrap(err, "failed to parse expiration time")
}
credentials := minioCred.Value{
AccessKeyID: response.Credential.Access,
SecretAccessKey: response.Credential.Secret,
SessionToken: response.Credential.Securitytoken,
SignerType: minioCred.SignatureV4,
}
p.credentials = credentials
p.expiration = expiration
return credentials, nil
}
func (p *HuaweiCredentialProvider) IsExpired() bool {
return time.Now().UTC().After(p.expiration.Add(-5 * time.Minute))
}