Skip to content

Commit

Permalink
Add cmd/aws-sign-request tool (#5)
Browse files Browse the repository at this point in the history
* snapshot: block out cmd/aws-sign-request, untested

* Make aws-sign-request work, docs

---------

Co-authored-by: sfomuseumbot <sfomuseumbot@localhost>
Co-authored-by: thisisaaronland <thisisaaronland@localhost>
  • Loading branch information
3 people committed Mar 27, 2024
1 parent 3e55b50 commit 9d61aa9
Show file tree
Hide file tree
Showing 3 changed files with 209 additions and 3 deletions.
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@ cli:
go build -mod $(GOMOD) -ldflags="$(LDFLAGS)" -o bin/aws-get-credentials cmd/aws-get-credentials/main.go
go build -mod $(GOMOD) -ldflags="$(LDFLAGS)" -o bin/aws-cognito-credentials cmd/aws-cognito-credentials/main.go
go build -mod $(GOMOD) -ldflags="$(LDFLAGS)" -o bin/aws-set-env cmd/aws-set-env/main.go
go build -mod $(GOMOD) -ldflags="$(LDFLAGS)" -o bin/aws-sign-request cmd/aws-sign-request/main.go
go build -mod $(GOMOD) -ldflags="$(LDFLAGS)" -o bin/aws-credentials-json-to-ini cmd/aws-credentials-json-to-ini/main.go
77 changes: 74 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,12 @@ This package targets [aws-sdk-go-v2](https://github.com/aws/aws-sdk-go-v2/). For

```
$> make cli
go build -mod vendor -o bin/aws-mfa-session cmd/aws-mfa-session/main.go
go build -mod vendor -o bin/aws-get-credentials cmd/aws-get-credentials/main.go
go build -mod vendor -o bin/aws-set-env cmd/aws-set-env/main.go
go build -mod vendor -ldflags="-s -w" -o bin/aws-mfa-session cmd/aws-mfa-session/main.go
go build -mod vendor -ldflags="-s -w" -o bin/aws-get-credentials cmd/aws-get-credentials/main.go
go build -mod vendor -ldflags="-s -w" -o bin/aws-cognito-credentials cmd/aws-cognito-credentials/main.go
go build -mod vendor -ldflags="-s -w" -o bin/aws-set-env cmd/aws-set-env/main.go
go build -mod vendor -ldflags="-s -w" -o bin/aws-sign-request cmd/aws-sign-request/main.go
go build -mod vendor -ldflags="-s -w" -o bin/aws-credentials-json-to-ini cmd/aws-credentials-json-to-ini/main.go
```

## aws-cognito-credentials
Expand Down Expand Up @@ -141,6 +144,74 @@ Usage of ./bin/aws-set-env:
Require AWS_SESSION_TOKEN environment variable (default true)
```

### aws-sign-request

`aws-sign-request` signs a HTTP request with an AWS "v4" signature, optionally executing the request and emitting the output to STDOUT or writing the request itself to STDOUT.

```
$> ./bin/aws-sign-request -h
Usage of ./bin/aws-sign-request:
-api-signing-name string
The name the API uses to identify the service the request is scoped to.
-api-signing-region string
If empty then the value of the region associated with the AWS config/credentials will be used.
-credentials-uri string
A valid aaronland/go-aws-auth config URI.
-do
If true then execute the signed request and output the response to STDOUT.
-header value
Zero or more HTTP headers to assign to the request in the form of key=value.
-method string
A valid HTTP method. (default "GET")
-uri string
The URI you are trying to sign.
```

For example, to call a Lambda Function URL:

```
$> bin/aws-sign-request \
-credentials-uri 'aws://{REGION}?credentials=iam:' \
-api-signing-name 'lambda' \
-uri https://{GIBBERISH}.lambda-url.{REGION}.on.aws/api/point-in-polygon \
-method POST \
-do \
'{"latitude": 25.0, "longitude": -45.6 }' \
| jq
{
"places": [
{
"wof:id": "404528709",
"wof:parent_id": "-1",
"wof:name": "North Atlantic Ocean",
"wof:country": "",
"wof:placetype": "ocean",
"mz:latitude": 0,
"mz:longitude": 0,
"mz:min_latitude": 24.965357,
"mz:min_longitude": 0,
"mz:max_latitude": -45.616087,
"mz:max_longitude": -45.570425,
"mz:is_current": 1,
"mz:is_deprecated": -1,
"mz:is_ceased": -1,
"mz:is_superseded": 0,
"mz:is_superseding": 0,
"edtf:inception": "",
"edtf:cessation": "",
"wof:supersedes": [],
"wof:superseded_by": [],
"wof:belongsto": [],
"wof:path": "404/528/709/404528709.geojson",
"wof:repo": "whosonfirst-data-admin-xy",
"wof:lastmodified": 1690923898
}
]
}
```

## See also:

* https://github.com/aws/aws-sdk-go-v2/
134 changes: 134 additions & 0 deletions cmd/aws-sign-request/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
// aws-sign-request signs a HTTP request with an AWS "v4" signature, optionally executing the
// request and emitting the output to STDOUT or writing the request itself to STDOUT.
package main

import (
"context"
"crypto/sha256"
"flag"
"fmt"
"io"
"log"
"net/http"
"os"
"strings"
"time"

"github.com/aaronland/go-aws-auth"
"github.com/aws/aws-sdk-go-v2/aws/signer/v4"
"github.com/sfomuseum/go-flags/multi"
)

func main() {

var headers multi.KeyValueString

var api_signing_name string
var api_signing_region string

var credentials_uri string
var method string
var uri string
var do bool

flag.StringVar(&api_signing_name, "api-signing-name", "", "The name the API uses to identify the service the request is scoped to.")
flag.StringVar(&api_signing_region, "api-signing-region", "", "If empty then the value of the region associated with the AWS config/credentials will be used.")

flag.StringVar(&method, "method", "GET", "A valid HTTP method.")
flag.StringVar(&uri, "uri", "", "The URI you are trying to sign.")
flag.StringVar(&credentials_uri, "credentials-uri", "", "A valid aaronland/go-aws-auth config URI.")
flag.BoolVar(&do, "do", false, "If true then execute the signed request and output the response to STDOUT.")
flag.Var(&headers, "header", "Zero or more HTTP headers to assign to the request in the form of key=value.")

flag.Parse()

ctx := context.Background()

body_r := strings.NewReader(strings.Join(flag.Args(), " "))

//

cfg, err := auth.NewConfig(ctx, credentials_uri)

if err != nil {
log.Fatalf("Failed to create new config, %v", err)
}

creds, err := cfg.Credentials.Retrieve(ctx)

if err != nil {
log.Fatalf("Failed to derive credentials from config, %v", err)
}

if api_signing_region == "" {
api_signing_region = cfg.Region
}

// https://github.com/aws/aws-sdk-go-v2/blob/main/aws/signer/v4/v4.go#L287

body_sha256 := ""

if body_r.Len() > 0 {

h := sha256.New()

_, err := io.Copy(h, body_r)

if err != nil {
log.Fatalf("Failed to hash request body, %v", err)
}

body_sha256 = fmt.Sprintf("%x", h.Sum(nil))

_, err = body_r.Seek(0, 0)

if err != nil {
log.Fatalf("Failed to rewind message body, %v", err)
}
}

req, err := http.NewRequest(method, uri, body_r)

if err != nil {
log.Fatalf("Failed to create new HTTP request, %v", err)
}

for _, h := range headers {
req.Header.Set(h.Key(), h.Value().(string))
}

signer := v4.NewSigner()

err = signer.SignHTTP(ctx, creds, req, body_sha256, api_signing_name, api_signing_region, time.Now())

if err != nil {
log.Fatalf("Failed to sign request, %v", err)
}

if !do {

err = req.Write(os.Stdout)

if err != nil {
log.Fatalf("Failed to write request, %v", err)
}

return
}

cl := http.Client{}
rsp, err := cl.Do(req)

if err != nil {
log.Fatalf("Failed to execute request, %v", err)
}

defer rsp.Body.Close()

_, err = io.Copy(os.Stdout, rsp.Body)

if err != nil {
log.Fatalf("Failed to read response, %v", err)
}

}

0 comments on commit 9d61aa9

Please sign in to comment.