为了账号安全,请及时绑定邮箱和手机立即绑定

使用 Go 进行 IAM 身份验证的 API 网关 HTTP 客户端请求

使用 Go 进行 IAM 身份验证的 API 网关 HTTP 客户端请求

Go
函数式编程 2023-06-19 15:19:25
我正在使用来自 spf13 的优秀 cobra/viper 包实现 CLI 。我们有一个以 API 网关端点为前端的 Athena 数据库,它使用 IAM 进行身份验证。也就是说,为了使用 Postman 与其端点进行交互,我必须定义AWS Signature为授权方法,定义相应的 AWS id/secret,然后在 Headers 中将有X-Amz-Security-Token和其他。没有异常,按预期工作。由于我是 Go 的新手,我有点震惊地看到没有示例来执行这个简单的 HTTP GET 请求本身aws-sdk-go......我正在尝试使用共享凭证提供程序(~/.aws/credentials),如来自 re:Invent 2015 的S3 客户端Go 代码片段:req := request.New(nil)我怎样才能在 2019 年完成这个看似简单的壮举,而不必诉诸自煮,net/http因此不必手动阅读~/.aws/credentials或更糟糕的是,使用os.Getenv和其他丑陋的技巧?任何作为客户端交互的 Go 代码示例 都会非常有帮助。拜托,没有 Golang Lambda/服务器示例,那里有很多。
查看完整描述

4 回答

?
繁星coding

TA贡献1797条经验 获得超4个赞

不幸的是,自从编写了接受的答案以来,该库似乎已经更新,并且解决方案不再相同。经过反复试验,这似乎是处理签名的最新方法:


import (

    "context"

    "net/http"

    "time"


    "github.com/aws/aws-sdk-go-v2/config"

    "github.com/aws/aws-sdk-go-v2/aws/signer/v4"

)


func main() {

    // Context is not being used in this example.

    cfg, err := config.LoadDefaultConfig(context.TODO())


    if err != nil {

        // Handle error.

    }


    credentials, err := cfg.Credentials.Retrieve(context.TODO())


    if err != nil {

        // Handle error.

    }


    // The signer requires a payload hash. This hash is for an empty payload.

    hash := "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"

    req, _ := http.NewRequest(http.MethodGet, "api-gw-url", nil)

    signer := v4.NewSigner()

    err = signer.SignHTTP(context.TODO(), credentials, req, hash, "execute-api", cfg.Region, time.Now())


    if err != nil {

        // Handle error.

    }


    // Use `req`

}


查看完整回答
反对 回复 2023-06-19
?
森栏

TA贡献1810条经验 获得超5个赞

下面的解决方案使用 aws-sdk-go-v2 https://github.com/aws/aws-sdk-go-v2

// A AWS SDK session is created because the HTTP API is secured using a

// IAM authorizer. As such, we need AWS client credentials and a

// session to properly sign the request.

cfg, err := external.LoadDefaultAWSConfig(

    external.WithSharedConfigProfile(profile),

)

if err != nil {

    fmt.Println("unable to create an AWS session for the provided profile")

    return

}



req, _ := http.NewRequest(http.MethodGet, "", nil)

req = req.WithContext(ctx)

signer := v4.NewSigner(cfg.Credentials)

_, err = signer.Sign(req, nil, "execute-api", cfg.Region, time.Now())

if err != nil {

    fmt.Printf("failed to sign request: (%v)\n", err)

    return

}


res, err := http.DefaultClient.Do(req)

if err != nil {

    fmt.Printf("failed to call remote service: (%v)\n", err)

    return

}


defer res.Body.Close()

if res.StatusCode != 200 {

    fmt.Printf("service returned a status not 200: (%d)\n", res.StatusCode)

    return

}



查看完整回答
反对 回复 2023-06-19
?
鸿蒙传说

TA贡献1865条经验 获得超7个赞

第一个参数request.Newaws.Config,您可以在其中发送凭据。


例如使用静态值:

creds:= credentials.NewStaticCredentials("AKID", "SECRET_KEY", "TOKEN")
req := request.New(aws.Config{Credentials: creds}, ...)


查看完整回答
反对 回复 2023-06-19
?
元芳怎么了

TA贡献1798条经验 获得超7个赞

如果您查看 s3.New() 函数的代码aws-sdk-go/service/s3/service.go

func New(p client.ConfigProvider, cfgs ...*aws.Config) *S3 {
c := p.ClientConfig(EndpointsID, cfgs...)
return newClient(*c.Config, c.Handlers, c.Endpoint, c.SigningRegion, .SigningName) }

相对于 request.New() 函数aws-sdk-go/aws/request/request.go

func New(cfg aws.Config, clientInfo metadata.ClientInfo, handlers Handlers,
retryer Retryer, operation *Operation, params interface{}, data interface{}) *Request { ...

正如您在 s3 场景中看到的,*aws.Config 结构是一个指针,因此可能在其他地方初始化/填充。与 aws.Config 是参数的请求函数相反。所以我猜请求模块可能是一个非常低级的模块,它不会自动获取共享凭证。

func New(p client.ConfigProvider, cfgs ...*aws.Config) *APIGateway {
c := p.ClientConfig(EndpointsID, cfgs...)
return newClient(*c.Config, c.Handlers, c.Endpoint, c.SigningRegion, c.SigningName) }...

它看起来与 s3 客户端几乎相同,所以也许尝试使用它看看你如何去?


查看完整回答
反对 回复 2023-06-19
  • 4 回答
  • 0 关注
  • 196 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信