Skip to content

Instantly share code, notes, and snippets.

@salrashid123
Last active June 24, 2024 15:52
Show Gist options
  • Save salrashid123/295079ac9a7452e774051b0e1a192b1d to your computer and use it in GitHub Desktop.
Save salrashid123/295079ac9a7452e774051b0e1a192b1d to your computer and use it in GitHub Desktop.
[golang] using AWS_WEB_IDENTITY_TOKEN_FILE with google workload identity federation

using:

golang custom credential provider which allows for arbitrary aws source credential usage (eg AWS_WEB_IDENTITY_TOKEN_FILE)

AwsSecurityCredentialsSupplier

also see in python here

to use this, you may have en-vars setup like so

export AWS_WEB_IDENTITY_TOKEN_FILE=/tmp/aws.txt
export AWS_ROLE_ARN="arn:aws:iam::291738886548:role/cicps3role"
export AWS_ROLE_SESSION_NAME=mysession

and a gcp workload identity provider as shown below along with an iam binding which authorizes a session (eg, for gcs)

gcloud storage buckets add-iam-policy-binding  gs://$PROJECT_ID-bucket \
   --member="principal://iam.googleapis.com/projects/995081019036/locations/global/workloadIdentityPools/aws-pool-1/subject/arn:aws:sts::291738886548:assumed-role/cicps3role/mysession" \
    --role="roles/storage.objectViewer"
package main

import (
	"context"
	"flag"
	"log"

	"cloud.google.com/go/storage"
	"golang.org/x/oauth2/google/externalaccount"

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

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

	"google.golang.org/api/iterator"
	"google.golang.org/api/option"
)

/*
export AWS_WEB_IDENTITY_TOKEN_FILE=/tmp/aws.txt
export AWS_ROLE_ARN="arn:aws:iam::291738886548:role/cicps3role"
export AWS_ROLE_SESSION_NAME=mysession

$ aws s3  ls s3://

$ aws sts assume-role-with-web-identity \
 --role-arn $AWS_ROLE_ARN \
 --role-session-name $AWS_ROLE_SESSION_NAME \
 --web-identity-token file:///$AWS_WEB_IDENTITY_TOKEN_FILE \
 --duration-seconds 1000


gcloud storage buckets add-iam-policy-binding  gs://$PROJECT_ID-bucket \
   --member="principal://iam.googleapis.com/projects/995081019036/locations/global/workloadIdentityPools/aws-pool-1/subject/arn:aws:sts::291738886548:assumed-role/cicps3role/mysession" \
    --role="roles/storage.objectViewer"
*/

var (
	projectId = flag.String("projectId", "core-eso", "ProjectID")
)

type awsSupplier struct {
	awsRegion             string
	awsCredentialProvider aws.CredentialsProvider
}

func NewAWSCredProvider(c aws.CredentialsProvider, r string) (awsSupplier, error) {
	return awsSupplier{
		awsCredentialProvider: c,
		awsRegion:             r,
	}, nil
}

func (supp awsSupplier) AwsRegion(ctx context.Context, options externalaccount.SupplierOptions) (string, error) {
	return supp.awsRegion, nil
}

func (supp awsSupplier) AwsSecurityCredentials(ctx context.Context, options externalaccount.SupplierOptions) (*externalaccount.AwsSecurityCredentials, error) {

	c, err := supp.awsCredentialProvider.Retrieve(ctx)
	if err != nil {
		return nil, err
	}
	return &externalaccount.AwsSecurityCredentials{
		AccessKeyID:     c.AccessKeyID,
		SecretAccessKey: c.SecretAccessKey,
		SessionToken:    c.SessionToken,
	}, nil
}

func main() {

	flag.Parse()

	log.Printf("======= Init  ========")

	ctx := context.Background()

	cfg, err := ac.LoadDefaultConfig(ctx, ac.WithRegion("us-east-1"))
	if err != nil {
		log.Fatal(err)
	}

	ac, err := NewAWSCredProvider(cfg.Credentials, "us-east-1")
	if err != nil {
		log.Fatal(err)
	}
	ts, err := externalaccount.NewTokenSource(ctx, externalaccount.Config{
		Audience:                       "//iam.googleapis.com/projects/995081019036/locations/global/workloadIdentityPools/aws-pool-1/providers/aws-provider-1",
		SubjectTokenType:               "urn:ietf:params:aws:token-type:aws4_request",
		Scopes:                         []string{"https://www.googleapis.com/auth/cloud-platform"},
		AwsSecurityCredentialsSupplier: ac,
	})

	if err != nil {
		log.Fatal(err)
	}

	storageClient, err := storage.NewClient(ctx, option.WithTokenSource(ts))
	if err != nil {
		log.Fatal(err)
	}
	sit := storageClient.Buckets(ctx, *projectId)
	for {
		battrs, err := sit.Next()
		if err == iterator.Done {
			break
		}
		if err != nil {
			log.Fatal(err)
		}
		log.Printf(battrs.Name)
	}

}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment