1.前言
雲計算是當下非常流行的技術,各互聯網公司基本上都在使用着不同雲廠商的資源。我們要查看或者操作購買的雲計算資源,一般都通過控制檯登錄直接操作。但是如果我們要批量操作資源,或者是開發自己的平臺調用資源,那麼我們該怎麼辦呢?其實各雲計算廠家都提供了資源操作的接口,api和sdk。其中,api接口需要我們自行實現接口的簽名認證,再調用廠商的各種方法,然後二次開發;sdk是廠商已經封裝好的操作接口,我們可以直接調用,再在此基礎上做開發。
2.代碼實現
本文主要用go語言實現了金山雲的api簽名,並使用生成的簽名調用金山雲提供的DescribeInstance查看雲主機的詳細信息。
package main
import (
"bytes"
"crypto/hmac"
"crypto/sha256"
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"net/url"
"strings"
"time"
)
func sign(key []byte, msg string) []byte {
h := hmac.New(sha256.New, key)
h.Write([]byte(msg))
return h.Sum(nil)
}
func get_signature_key(key string, dateStamp string, regionName string, serviceName string) []byte {
kDate := sign([]byte("AWS4"+key), dateStamp)
kRegion := sign(kDate, regionName)
kService := sign(kRegion, serviceName)
kSigning := sign(kService, "aws4_request")
return kSigning
}
func get_auth(access_key, secret_key, action, version, host, method, region, service string,
req_params map[string]interface{}) (int, string, string) {
var request_parameters string
endpoint := "http://" + host
params := url.Values{}
params.Add("Action", action)
params.Add("Version", version)
if req_params != nil {
for key := range req_params {
v := fmt.Sprintf("%v", req_params[key])
params.Add(key, v)
}
}
request_parameters += params.Encode()
if access_key == "" || secret_key == "" {
fmt.Println("No access key is available.")
return 400, "", ""
}
t := time.Now().UTC()
amzdate := t.Format("20060102T150405Z")
datestamp := t.Format("20060102")
canonical_uri := "/"
canonical_querystring := request_parameters
canonical_headers := "content-type:application/json" + "\n" + "host:" + host + "\n" + "x-amz-date:" + amzdate + "\n"
signed_headers := "content-type;host;x-amz-date"
h := sha256.New()
h.Write([]byte(""))
payload_hash := fmt.Sprintf("%x", h.Sum(nil))
canonical_request := method + "\n" + canonical_uri + "\n" + canonical_querystring + "\n" + canonical_headers + "\n" + signed_headers + "\n" + payload_hash
algorithm := "AWS4-HMAC-SHA256"
credential_scope := datestamp + "/" + region + "/" + service + "/" + "aws4_request"
ha := sha256.New()
ha.Write([]byte(canonical_request))
hash := fmt.Sprintf("%x", ha.Sum(nil))
string_to_sign := algorithm + "\n" + amzdate + "\n" + credential_scope + "\n" + hash
signing_key := get_signature_key(secret_key, datestamp, region, service)
s := hmac.New(sha256.New, signing_key)
s.Write([]byte(string_to_sign))
signature := fmt.Sprintf("%x", s.Sum(nil))
authorization_header := algorithm + " " + "Credential=" + access_key + "/" + credential_scope + ", " + "SignedHeaders=" + signed_headers + ", " + "Signature=" + signature
request_url := endpoint + "?" + canonical_querystring
return 200, authorization_header, request_url
}
func Request(access_key, secret_key, action, version, host, method, region, service string,
req_params map[string]interface{}) (int, string) {
t := time.Now().UTC()
amzdate := t.Format("20060102T150405Z")
code, authorization_header, request_url := get_auth(access_key, secret_key, action, version, host, method, region, service,
req_params)
if code != 200 {
fmt.Println("auth error!")
return code, ""
}
client := &http.Client{}
req, _ := http.NewRequest(method, request_url, strings.NewReader(""))
req.Header.Set("Content-Type", "application/json")
req.Header.Set("X-Amz-Date", amzdate)
req.Header.Set("Authorization", authorization_header)
req.Header.Set("Accept", "application/json")
resp, _ := client.Do(req)
defer resp.Body.Close()
body, _ := ioutil.ReadAll(resp.Body)
code = resp.StatusCode
return code, string(body)
}
func main() {
ak := "your ak"
sk := "your sk"
region := "cn-beijing-6"
action := "DescribeInstances"
version := "2016-03-04"
host := "kec.api.ksyun.com"
methods := "GET"
service := "kec"
var req_params map[string]interface{}
code, text := Request(ak, sk, action, version, host, methods, region, service, req_params)
if code != 200 {
fmt.Println("describe kec error!")
}
var str bytes.Buffer
json.Indent(&str, []byte(text), "", " ")
fmt.Println(str.String())
}