Skip to content

Commit

Permalink
Add code to derive temporary STS credentials for Cognito Identity pro…
Browse files Browse the repository at this point in the history
…vider (#2)

* snapshot: block out tool to derive creds from cognito

* snapshot: derive credentials, not sure anything works though

* rename aws-sts-credentials as aws-cognito-credentials

* snapshot: add cmd/aws-credentials-json-to-ini

* add docs for cognito and credentials json-to-ini stuff

---------

Co-authored-by: sfomuseumbot <sfomuseumbot@localhost>
  • Loading branch information
thisisaaronland and sfomuseumbot committed Jan 23, 2024
1 parent 975f1dc commit 9e77da2
Show file tree
Hide file tree
Showing 62 changed files with 16,511 additions and 129 deletions.
2 changes: 2 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,6 @@ LDFLAGS=-s -w
cli:
go build -mod $(GOMOD) -ldflags="$(LDFLAGS)" -o bin/aws-mfa-session cmd/aws-mfa-session/main.go
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-credentials-json-to-ini cmd/aws-credentials-json-to-ini/main.go
75 changes: 75 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,81 @@ 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
```

## aws-cognito-credentials

`aws-cognito-credentials` generates temporary STS credentials for a given user in a Cognito identity pool.

```
$> ./bin/aws-cognito-credentials -h
Usage of ./bin/aws-cognito-credentials:
-aws-config-uri string
A valid github.com/aaronland/go-aws-auth.Config URI.
-duration int
The duration, in seconds, of the role session. Can not be less than 900. (default 900)
-identity-pool-id string
A valid AWS Cognito Identity Pool ID.
-login value
One or more key=value strings mapping to AWS Cognito authentication providers.
-role-arn string
A valid AWS IAM role ARN to assign to STS credentials.
-role-session-name string
An identifier for the assumed role session.
```

For example:

```
$> go bin/aws-cognito-credentials \
-aws-config-uri 'aws://us-east-1?credentials=session' \
-identity-pool-id us-east-1:{GUID} \
-login org.sfomuseum=bob
-role-session-name bob -role-arn 'arn:aws:iam::{ACCOUNT_ID}:role/{ROLE}' \
| jq
{
"AccessKeyId": "...",
"Expiration": "...",
"SecretAccessKey": "...",
"SessionToken": "..."
}
```

### aws-credentials-json-to-ini

`aws-credentials-json-to-ini` reads JSON-encoded AWS credentials information and generates an AWS ini-style configuration file with those data.

```
$> ./bin/aws-credentials-json-to-ini -h
Usage of ./bin/aws-credentials-json-to-ini:
-ini string
Path to the ini-style file where AWS credentials should be written. If "-" then data will be written to STDOUT.
-json string
Path to the JSON file containing AWS credentials. If "-" then data will be read from STDIN.
-name string
The name of the ini section where AWS credentials should be written. (default "default")
-region string
The AWS region for the AWS credentials. (default "us-east-1")
```

For example:

```
$> go bin/aws-cognito-credentials \
-aws-config-uri 'aws://us-east-1?credentials=session' \
-identity-pool-id us-east-1:{GUID} \
-login org.sfomuseum=bob
-role-session-name bob -role-arn 'arn:aws:iam::{ACCOUNT_ID}:role/{ROLE}' \
| ./bin/aws-credentials-json-to-ini -json - -ini -
[default]
region = us-east-1
aws_access_key_id = ...
aws_secret_access_key = ...
aws_session_token = ...
```

### aws-get-credentials

`aws-get-credentials` is a command line tool to emit one or more keys from a given profile in an AWS .credentials file.
Expand Down
70 changes: 70 additions & 0 deletions cmd/aws-cognito-credentials/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
// aws-cognito-credentials generates temporary STS credentials for a given user in a Cognito identity pool.
package main

import (
"context"
"encoding/json"
"flag"
"log"
"os"

"github.com/aaronland/go-aws-auth"
"github.com/sfomuseum/go-flags/multi"
)

func main() {

var aws_config_uri string

var identity_pool_id string
var role_arn string
var role_session_name string
var duration int

var kv_logins multi.KeyValueString

flag.StringVar(&aws_config_uri, "aws-config-uri", "", "A valid github.com/aaronland/go-aws-auth.Config URI.")

flag.StringVar(&identity_pool_id, "identity-pool-id", "", "A valid AWS Cognito Identity Pool ID.")
flag.StringVar(&role_arn, "role-arn", "", "A valid AWS IAM role ARN to assign to STS credentials.")
flag.StringVar(&role_session_name, "role-session-name", "", "An identifier for the assumed role session.")
flag.IntVar(&duration, "duration", 900, "The duration, in seconds, of the role session. Can not be less than 900.") // Note: Can not be less than 900
flag.Var(&kv_logins, "login", "One or more key=value strings mapping to AWS Cognito authentication providers.")

flag.Parse()

ctx := context.Background()

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

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

logins := make(map[string]string, 0)

for _, kv := range kv_logins {
logins[kv.Key()] = kv.Value().(string)
}

opts := &auth.STSCredentialsForDeveloperIdentityOptions{
RoleArn: role_arn,
RoleSessionName: role_session_name,
Duration: int32(duration),
IdentityPoolId: identity_pool_id,
Logins: logins,
}

creds, err := auth.STSCredentialsForDeveloperIdentity(ctx, cfg, opts)

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

enc := json.NewEncoder(os.Stdout)
err = enc.Encode(creds)

if err != nil {
log.Fatalf("Failed to encode credentials, %v", err)
}
}
5 changes: 5 additions & 0 deletions cmd/aws-credentials-json-to-ini/credentials.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
[{{.Name}}]
region = {{ .Region }}
aws_access_key_id = {{ .KeyId }}
aws_secret_access_key = {{ .KeySecret }}
aws_session_token = {{ .SessionToken }}
124 changes: 124 additions & 0 deletions cmd/aws-credentials-json-to-ini/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
// aws-credentials-json-to-ini reads JSON-encoded AWS credentials information and generates an AWS ini-style configuration file with those data.
package main

import (
"bufio"
_ "embed"
"encoding/json"
"flag"
"fmt"
"io"
"log"
"os"
"text/template"

"github.com/aws/aws-sdk-go-v2/service/sts/types"
)

//go:embed credentials.ini
var credentials_t string

type CredentialsVars struct {
Name string
Region string
KeyId string
KeySecret string
SessionToken string
}

func main() {

var infile string
var outfile string

var name string
var region string

flag.StringVar(&infile, "json", "", "Path to the JSON file containing AWS credentials. If \"-\" then data will be read from STDIN.")
flag.StringVar(&outfile, "ini", "", "Path to the ini-style file where AWS credentials should be written. If \"-\" then data will be written to STDOUT.")

flag.StringVar(&name, "name", "default", "The name of the ini section where AWS credentials should be written.")
flag.StringVar(&region, "region", "us-east-1", "The AWS region for the AWS credentials.")

flag.Parse()

var r io.ReadCloser
var wr io.WriteCloser

switch infile {
case "-":
br := bufio.NewReader(os.Stdin)
r = io.NopCloser(br)
default:

_r, err := os.Open(infile)

if err != nil {
log.Fatalf("Failed to open %s for reading, %v", infile, err)
}

r = _r
}

defer r.Close()

switch outfile {
case "-":
wr = os.Stdout
default:
_wr, err := os.OpenFile(outfile, os.O_RDWR|os.O_CREATE, 0600)

if err != nil {
log.Fatalf("Failed to open %s for writing, %v", outfile, err)
}

wr = _wr
}

err := Convert(r, wr, name, region)

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

err = wr.Close()

if err != nil {
log.Fatalf("Failed to close %s after writing, %v", outfile, err)
}

}

func Convert(r io.Reader, wr io.Writer, name string, region string) error {

t, err := template.New("credentials").Parse(credentials_t)

if err != nil {
return fmt.Errorf("Failed to parse credentials template, %w", err)
}

var creds *types.Credentials

dec := json.NewDecoder(r)
err = dec.Decode(&creds)

if err != nil {
return fmt.Errorf("Failed to decode credentials reader, %w", err)
}

vars := CredentialsVars{
Name: name,
Region: region,
KeyId: *creds.AccessKeyId,
KeySecret: *creds.SecretAccessKey,
SessionToken: *creds.SessionToken,
}

err = t.Execute(wr, vars)

if err != nil {
return fmt.Errorf("Failed to write credentials template, %w", err)
}

return nil
}
2 changes: 1 addition & 1 deletion cmd/aws-get-credentials/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import (
"os"

"github.com/aaronland/go-aws-auth"
"github.com/go-ini/ini"
"github.com/go-ini/ini"
)

func main() {
Expand Down
3 changes: 2 additions & 1 deletion cmd/aws-mfa-session/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// a given profile and multi-factor authentication (MFA) token and then writing that key and secret
// back to a "credentials" file in a specific profile section. For example, when used in a Makefile with
// https://github.com/Yubico/yubikey-manager/tree/master/ykman
//
// $(eval CODE := $(shell ykman oath code sfomuseum:aws | awk '{ print $$2 }'))
// bin/$aws-mfa-session -code $(CODE) -duration PT8H
package main
Expand All @@ -15,7 +16,7 @@ import (
"time"

"github.com/aaronland/go-aws-auth"
"github.com/sfomuseum/iso8601duration"
"github.com/sfomuseum/iso8601duration"
)

func readline(prompt string) string {
Expand Down
4 changes: 2 additions & 2 deletions cmd/aws-set-env/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ import (
"flag"
"log"
"os"

"github.com/aaronland/go-aws-auth"
"github.com/go-ini/ini"
"github.com/go-ini/ini"
)

func main() {
Expand Down
36 changes: 0 additions & 36 deletions cmd/aws-sign/main.go

This file was deleted.

0 comments on commit 9e77da2

Please sign in to comment.