Skip to content

Instantly share code, notes, and snippets.

@Coutlaw
Last active April 9, 2020 18:49
Show Gist options
  • Save Coutlaw/14f3f56221e8cce723f0e9715bc01d29 to your computer and use it in GitHub Desktop.
Save Coutlaw/14f3f56221e8cce723f0e9715bc01d29 to your computer and use it in GitHub Desktop.
S3 Credential File Key Generator in Go

Key Generation With S3 Credential Files in Go

This script can be used to generate unique keys from credential files in an AWS S3 bucket. If we needed a key that was a hash of the ClientID and Client Secret, then we can use the below script to find a key for every file in a given S3 bucket. This script will use the .aws credential file on the machine that it is running on.

My Script

package main

import (
	"crypto/sha256"
	"encoding/hex"
	"encoding/json"
	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/awserr"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/s3"
	"github.com/aws/aws-sdk-go/service/s3/s3manager"
	"io/ioutil"
	"log"
	"os"

	"fmt"
)

// Downloads an item from an S3 Bucket in the region configured in the shared config
// or AWS_REGION environment variable.
//
func main() {
	if len(os.Args) != 2 {
		exitErrorf("Bucket name required\nUsage: %s bucket_name",
			os.Args[0])
	}

	bucket := os.Args[1]

	// Initialize a session in us-east-1
	// credentials from the shared credentials file ~/.aws/credentials.
	sess, _ := session.NewSession(&aws.Config{
		Region: aws.String("us-east-1")},
	)

	// gather arguments for the ListObjects() function
	input := &s3.ListObjectsInput{
		Bucket:  aws.String(bucket),
		MaxKeys: aws.Int64(20),
	}

	// S3 service
	svc := s3.New(sess)

	// List all the objects in the bucket
	results, err := svc.ListObjects(input)
	if err != nil {
		if aerr, ok := err.(awserr.Error); ok {
			switch aerr.Code() {
			case s3.ErrCodeNoSuchBucket:
				fmt.Println(s3.ErrCodeNoSuchBucket, aerr.Error())
			default:
				fmt.Println(aerr.Error())
			}
		} else {
			fmt.Println(err.Error())
		}
		return
	}

	// Log list results if needed
	//fmt.Println(results)

	// Downloader for S3
	downloader := s3manager.NewDownloader(sess)

	// Temp file from ioutil
	tmpFile, err := ioutil.TempFile("", "tmp")
	if err != nil {
		log.Fatal(err)
	}

	// Create API key for every file in S3
	for _, file := range results.Contents  {

		// Get file from s3 and put in tmp file
		// replace _ with numBytes for logging below to work
		_, err = downloader.Download(tmpFile,
			&s3.GetObjectInput{
				Bucket: aws.String(bucket),
				Key:    aws.String(*file.Key),
			})
		if err != nil {
			exitErrorf("Unable to download item %q, %v", file.Key, err)
		}

		//Logging if needed
		//fmt.Println("Downloaded", *file.Key, numBytes, "bytes")

		// Output the API key
		byteValue, _ := ioutil.ReadAll(tmpFile)
		var client Client
		_ = json.Unmarshal([]byte(byteValue), &client)

		fmt.Println("API key for: ", *file.Key, "\n", client.generateKey())
	}
	defer os.Remove(tmpFile.Name()) // clean up
}

func exitErrorf(msg string, args ...interface{}) {
	_, _ = fmt.Fprintf(os.Stderr, msg+"\n", args...)
	os.Exit(1)
}

// Client : Struct to represent the client files in S3
type Client struct {
	ClientSecret string `json:"clientSecret"`
	RedirectUrls string `json:"redirectUrls"`
	Name         string `json:"name"`
	ClientId     string `json:"clientId"`
	Description  string `json:"description"`
}

// Function to calculate a clients API Key
func (c Client) generateKey() string {
	// like PrintF but returns the string without printing
	comb := fmt.Sprintf("%v%v", c.ClientId, c.ClientSecret)
	myBytes := sha256.Sum256([]byte(comb))
	return hex.EncodeToString(myBytes[:])
}

Usage:

go run {scriptName}.go {bucketName}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment