{"id":21354935,"url":"https://github.com/salrashid123/gcpcompat-aws","last_synced_at":"2025-07-12T22:32:27.102Z","repository":{"id":91309887,"uuid":"306419725","full_name":"salrashid123/gcpcompat-aws","owner":"salrashid123","description":"Exchange AWS Credentials for GCP Credentials using GCP STS Service","archived":false,"fork":false,"pushed_at":"2023-10-23T15:25:36.000Z","size":1136,"stargazers_count":9,"open_issues_count":1,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2023-10-23T16:33:16.858Z","etag":null,"topics":["aws","federation","gcp","google-cloud-platform","iam"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/salrashid123.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null}},"created_at":"2020-10-22T18:01:41.000Z","updated_at":"2023-10-05T14:30:13.000Z","dependencies_parsed_at":null,"dependency_job_id":"8cba6bbf-d5a8-4a03-ad45-a6265a617ed0","html_url":"https://github.com/salrashid123/gcpcompat-aws","commit_stats":null,"previous_names":[],"tags_count":0,"template":null,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/salrashid123%2Fgcpcompat-aws","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/salrashid123%2Fgcpcompat-aws/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/salrashid123%2Fgcpcompat-aws/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/salrashid123%2Fgcpcompat-aws/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/salrashid123","download_url":"https://codeload.github.com/salrashid123/gcpcompat-aws/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":225839601,"owners_count":17532308,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["aws","federation","gcp","google-cloud-platform","iam"],"created_at":"2024-11-22T04:15:21.583Z","updated_at":"2024-11-22T04:15:22.323Z","avatar_url":"https://github.com/salrashid123.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"## GCP Workload Identity Federation using AWS Credentials\n\nThis is a sample procedure that will exchange a long term or short term AWS credential for a GCP credential.\n\nYou can use the GCP credential  to access any service the mapped principal has GCP IAM permissions on.\n\nThis article and repo is the first part that explores how to use the [workload identity federation](https://cloud.google.com/iam/docs/access-resources-aws) capability of GCP which allows for external principals (AWS,Azure or arbitrary OIDC provider) to map to a GCP credential.\n\nThe two variations described in this repo will acquire a Google Credential as described here:\n - [https://cloud.google.com/iam/docs/access-resources-aws#generate](https://cloud.google.com/iam/docs/access-resources-aws#generate)\n\nThe \"Automatic\" way is recommended and is supported by Google\n\nThe \"Manual\" way is also covered in this repo but I decided to wrap the steps for that into my own library here [github.com/salrashid123/oauth2/google](https://github.com/salrashid123/oauth2#usage-aws) which surfaces the credential as an [oauth2.TokenSource](https://godoc.org/golang.org/x/oauth2#TokenSource) for use in any GCP cloud library.  \n\n\u003e\u003e NOTE: the library i'm using for the \"manual\" way is just there as an unsupported demo of a wrapped oauth2 TokenSource! \n\nYou can certainly use either procedure but the Automatic way is included with the *supported, standard* GCP Client library.\n\n\u003e\u003e This repository is not supported by Google\n\u003e\u003e `salrashid123/oauth2/google` is also not supported by Google\n\nalso see\n- [GCP Workload Identity Federation using OIDC Credentials](https://github.com/salrashid123/gcpcompat-oidc)\n- [GCP Workload Identity Federation using SAML Credentials](https://github.com/salrashid123/gcpcompat-saml)\n- [GCP Workload Identity Federation using AWS Credentials](https://github.com/salrashid123/gcpcompat-aws)\n \n---\n\n### Workload Federation - AWS\n\nGCP now surfaces a `STS Service` that will exchange one set of tokens for another using the GCP Secure Token Service (STS) [here](https://cloud.google.com/iam/docs/reference/sts/rest/v1beta/TopLevel/token).  These initial tokens can be either 3rd party or google `access_tokens` that are [downscoped](https://github.com/salrashid123/downscoped_token) (i.,e attenuated in permission set).\n\nTo use this tutorial, you need both a GCP and AWS project and the ability to create user/service accounts and then apply permissions on those to facilitate the mapping.\n\nAgain, the two types of flows this repo demonstrates:  \n\n- Manual Exchange:\n  In this you manually do all the steps of exchanging `AWS_ACCESS_KEY_ID/AWS_SECRET_ACCESS_KEY` for a federated token and then finally use that token\n\n- Automatic Exchange\n  In this you use the google cloud client libraries to do all the heavy lifting.  \u003c\u003c This is the recommended approach\n\n\n\u003e\u003e It is recommended to do the manual first just to understand this capability and then move onto the automatic\n\n\n#### AWS User/Session/Roles --\u003e GCP Identity --\u003e GCP Resource\n\nThis tutorial will cover various source AWS identity for federation and how they map to a GCP  [principal:// and principalSet://](https://cloud.google.com/iam/docs/workload-identity-federation#impersonation)\n\n---\n\na) `AWS User --\u003e GCP principal:// --\u003e Impersonate Service Account --\u003e GCP Resource`\n\n  AWS User  `\"Arn\": \"arn:aws:iam::291738886548:user/svcacct1\"` mapped to \n  `principal://iam.googleapis.com/projects/$PROJECT_NUMBER/locations/global/workloadIdentityPools/aws-pool-1/subject/arn:aws:iam::291738886548:user/svcacct1`\n\n---\n\nb) `AWS User --\u003e AWS Assumed Role --\u003e AWS Named Session --\u003e GCP principal:// --\u003e Impersonate Service Account --\u003e GCP Resource`\n\n  AWS User will Assume a Role and then acquire a *NAMED* AWS Session\n  `\"Arn\": \"arn:aws:sts::291738886548:assumed-role/gcpsts/mysession\"` mapped to \n  `principal://iam.googleapis.com/projects/$PROJECT_NUMBER/locations/global/workloadIdentityPools/aws-pool-1/subject/arn:aws:sts::291738886548:assumed-role/gcpsts/mysession`\n\n---\n\nc) `AWS User --\u003e AWS Assumed Role --\u003e GCP principalSet:// --\u003e Impersonate Service Account --\u003e GCP Resource`\n\n  AWS User assumes Role\n`arn:aws:sts::291738886548:assumed-role/gcpsts` mapped to\n`principalSet://iam.googleapis.com/projects/$PROJECT_NUMBER/locations/global/workloadIdentityPools/aws-pool-2/attribute.aws_role/arn:aws:sts::291738886548:assumed-role/gcpsts`\n\n---\n\nd) `AWS EC2 --\u003e AWS Assumed EC2 Role --\u003e  GCP principalSet:// --\u003e Impersonate Service Account --\u003e GCP Resource`\n\n  AWS EC2 Role\n  `arn:aws:sts::291738886548:assumed-role/ec2role` mapped to\n  `\"principalSet://iam.googleapis.com/projects/$PROJECT_NUMBER/locations/global/workloadIdentityPools/aws-pool-2/attribute.aws_role/arn:aws:sts::291738886548:assumed-role/ec2role\"`\n\n---\n\nOption (d) is likely the most common usecase since it allows a group of EC2 instances to collectively map to a GCP identity.\n\na) is used to map a given user (`aws-pool-1/subject/`)\nb) is used to map a user to a _named session_ as a subject.\nc) is used to map a user that assumes a role (`aws-pool-2/attribute.aws_role`)\n\n#### Manual Exchange\n\nOn the AWS side, you need to configure a user, then allow it to `AssumeRole` to derive a short-term token.  You do not need to go the extra step to assumeRole but this example shows best-practices for short-lived tokens.\n\n1. Create AWS user\n  In this case, the user is `\"arn:aws:iam::291738886548:user/svcacct1\"` with uid=`AIDAUH3H6EGKDO36JYJH3`\n\nUsing local env-var based bootstrap on your laptop:\n\n```bash\n$ export AWS_ACCESS_KEY_ID=redacted \n$ export AWS_SECRET_ACCESS_KEY=redacted\n\n$ aws sts get-caller-identity\n{\n    \"UserId\": \"AIDAUH3H6EGKDO36JYJH3\",\n    \"Account\": \"291738886548\",\n    \"Arn\": \"arn:aws:iam::291738886548:user/svcacct1\"\n}\n```\n\n![images/aws_user.png](images/aws_user.png)\n\n\n2. Define Role\n\nAllow the user to assume an AWS role (`gcpsts`)\n\nIn this case, we are assuming a role and a named session `arn:aws:sts::291738886548:assumed-role/gcpsts/mysession`\n\n\n```bash\n$ aws sts assume-role --role-arn arn:aws:iam::291738886548:role/gcpsts --role-session-name mysession\n{\n    \"Credentials\": {\n        \"AccessKeyId\": \"ASIAUH3H6EGKHQ-redacted\",\n        \"SecretAccessKey\": \"WgsIFtkz4mzb9ArKlds7ZFZDQEe-redacted\",\n        \"SessionToken\": \"FwoGZXIvYXdzEF-redacted\",\n        \"Expiration\": \"2020-10-22T12:26:05+00:00\"\n    },\n    \"AssumedRoleUser\": {\n        \"AssumedRoleId\": \"AROAUH3H6EGKHZUSB4BC5:mysession\",\n        \"Arn\": \"arn:aws:sts::291738886548:assumed-role/gcpsts/mysession\"\n    }\n}\n```\n\n![images/aws_role_trust.png](images/aws_role_trust.png)\n\n3.  Verify Role change\n\nUse the assumed roles token to confirm the change\n```bash\nexport AWS_ACCESS_KEY_ID=ASIAUH3H6EG-redacted\nexport AWS_SECRET_ACCESS_KEY=pyDAMjC+aoDT7wWE5MbVCw9j-redacted\nexport AWS_SESSION_TOKEN=FwoGZXIvYXdzEF-redacted\n\n$ aws sts get-caller-identity\n{\n    \"UserId\": \"AROAUH3H6EGKHZUSB4BC5:mysession\",\n    \"Account\": \"291738886548\",\n    \"Arn\": \"arn:aws:sts::291738886548:assumed-role/gcpsts/mysession\"\n}\n```\n\n### GCP\n\nSwitch to the GCP account\n\n\n1. Create Service Account\n\nCreate a service account the AWS one will map to and grant this service account permissions on something (eg, gcs bucket)\n\n```bash\nexport PROJECT_ID=`gcloud config get-value core/project`\nexport PROJECT_NUMBER=`gcloud projects describe $PROJECT_ID --format='value(projectNumber)'`\n\ngcloud iam service-accounts create aws-federated\n\n\n# upload a sample file to GCS which we will later recall using the federated flow\n\ngsutil mb gs://$PROJECT-mybucket\necho fooooo \u003e foo.txt\ngsutil cp foo.txt gs://$PROJECT-mybucket\ngsutil iam ch serviceAccount:aws-federated@$PROJECT.iam.gserviceaccount.com:objectViewer gs://$PROJECT-mybucket\n```\n\nFrom here, you can test using `principal://` or `principalSet://` as described above\n\n#### Using  (principal://)\n\nThe following commands below we are specifically mapping an arn to a subject.  That is, it will match for *exactly*\n\n* `\"arn:aws:iam::291738886548:user/svcacct1\"` (user)\n* `\"arn:aws:sts::291738886548:assumed-role/gcpsts/mysession\"` (session)\n\n- First create a workflow identity pool \n\n```bash\ngcloud iam workload-identity-pools create aws-pool-1 \\\n    --location=\"global\" \\\n    --description=\"AWS \" \\\n    --display-name=\"AWS Pool\"\n```\n\n- Define aws-provider\n\nDefine the aws-provider associated with that pool using your AWS AccountID (in this case its `291738886548`). \n\nThe `attribute-mapping=` sections are the default mapping that does the actual translation from the AWS `getCallerIdentity()` claim back to a GCP principal.  \nYou can define other mappings but we're using the default\n\n```bash\ngcloud iam workload-identity-pools providers create-aws aws-provider-1  \\\n   --workload-identity-pool=\"aws-pool-1\"     --account-id=\"291738886548\"   \\\n   --location=\"global\"\n```\n\n(note, we are using the [default mapping](https://cloud.google.com/iam/docs/access-resources-aws#add-aws)  `attribute-mapping=\"google.subject=assertion.arn,attribute.aws_role=...\"`)\n\n- Grant WorkloadIdentity Pool to use SA\n\nNow grant the mapped identity permissions to assume the actual GCP service account.\n\nIn the example below, we're allowing a user (`arn:aws:iam::291738886548:user/svcacct1`) and specific sessonName (`arn:aws:sts::291738886548:assumed-role/gcpsts/mysession`) will be allowed to impersonate `aws-federated@$PROJECT.iam.gserviceaccount.com`\n\n```bash\ngcloud iam service-accounts add-iam-policy-binding aws-federated@$PROJECT_ID.iam.gserviceaccount.com   \\\n    --role roles/iam.workloadIdentityUser \\\n    --member \"principal://iam.googleapis.com/projects/$PROJECT_NUMBER/locations/global/workloadIdentityPools/aws-pool-1/subject/arn:aws:iam::291738886548:user/svcacct1\"\n\ngcloud iam service-accounts add-iam-policy-binding aws-federated@$PROJECT_ID.iam.gserviceaccount.com   \\\n    --role roles/iam.workloadIdentityUser \\\n    --member \"principal://iam.googleapis.com/projects/$PROJECT_NUMBER/locations/global/workloadIdentityPools/aws-pool-1/subject/arn:aws:sts::291738886548:assumed-role/gcpsts/mysession\"\n```\n\n#### Using  (principalSet://)\n\nUse (`principalSet://`) to map any AWS system that assumes a role.  For example, if you have a set of AWS EC2 instances that all can assume a specific Role name, use `principalSet://`\n\nNote the command below we are specifically mapping federation on _TWO_ Roles that we will demo shortly.  The first one is for a user to assume that role; the second one is for ec2 itself.\n\n* `\"arn:aws:sts::291738886548:assumed-role/gcpsts\"`\n* `\"arn:aws:sts::291738886548:assumed-role/ec2role\"`\n\n![images/user_role.png](images/user_role.png)\n\n![images/ec2_role.png](images/ec2_role.png)\n\n- Define identity-pool\n\nWe will create a new identity pool here just to test this separately from (a)\n\n```bash\ngcloud iam workload-identity-pools create aws-pool-2 \\\n    --location=\"global\" \\\n    --description=\"AWS \" \\\n    --display-name=\"AWS Pool 2\"\n```\n- Define aws-provider\n\n```bash\ngcloud iam workload-identity-pools providers create-aws aws-provider-2  \\\n   --workload-identity-pool=\"aws-pool-2\"     --account-id=\"291738886548\"   \\\n   --location=\"global\" \n```\n\n(note, we are again using the default mapping `attribute-mapping` of `\"google.subject=assertion.arn\"` and `attribute.aws_role=\u003cAWS Role\u003e`)\n\n- Grant WorkloadIdentity Pool to use the service account\n\n```bash\ngcloud iam service-accounts add-iam-policy-binding aws-federated@$PROJECT_ID.iam.gserviceaccount.com   \\\n    --role roles/iam.workloadIdentityUser \\\n    --member \"principalSet://iam.googleapis.com/projects/$PROJECT_NUMBER/locations/global/workloadIdentityPools/aws-pool-2/attribute.aws_role/arn:aws:sts::291738886548:assumed-role/gcpsts\" \n\ngcloud iam service-accounts add-iam-policy-binding aws-federated@$PROJECT_ID.iam.gserviceaccount.com   \\\n    --role roles/iam.workloadIdentityUser \\\n    --member \"principalSet://iam.googleapis.com/projects/$PROJECT_NUMBER/locations/global/workloadIdentityPools/aws-pool-2/attribute.aws_role/arn:aws:sts::291738886548:assumed-role/ec2role\" \n```\n\n---\n\nYou should end up with IAM bindings on the service account that is used for impersonation. The bindings below shows both `principal://` and `principalSet://`\n\n```bash\n$ gcloud iam service-accounts get-iam-policy aws-federated@$PROJECT_ID.iam.gserviceaccount.com  \nbindings:\n- members:\n  - principal://iam.googleapis.com/projects/1071284184436/locations/global/workloadIdentityPools/aws-pool-1/subject/arn:aws:iam::291738886548:user/svcacct1\n  - principal://iam.googleapis.com/projects/1071284184436/locations/global/workloadIdentityPools/aws-pool-1/subject/arn:aws:sts::291738886548:assumed-role/gcpsts/mysession\n  - principalSet://iam.googleapis.com/projects/1071284184436/locations/global/workloadIdentityPools/aws-pool-2/attribute.aws_role/arn:aws:sts::291738886548:assumed-role/gcpsts\n  - principalSet://iam.googleapis.com/projects/1071284184436/locations/global/workloadIdentityPools/aws-pool-2/attribute.aws_role/arn:aws:sts::291738886548:assumed-role/ec2role\n  role: roles/iam.workloadIdentityUser\nversion: 1\n```\n\n\n![images/gcp_iam.png](images/gcp_iam.png)\n\n\n### Automatic Exchange\n\nWith the automatic exchange, the GCP cloud auth libraries do all these steps for you.\n\nIn this tutorial, setup an EC2 VM, install golang and configure it such that you can assume the role `ec2role` automatically on the VM\n\n\nFor this to work, you must have previously setup the `aws-federated@$PROJECT_ID.iam.gserviceaccount.com` service account and gave it permissions to the GCS object.  You should have also configured the `aws-provider-2` configurations and use `principalSet://`\n\nFirst step is to generate the client library helper file which will act as the `APPLICATION_DEFAULT_CREDENTIAL`\n\n```bash\ngcloud beta iam workload-identity-pools create-cred-config \\\n    projects/$PROJECT_NUMBER/locations/global/workloadIdentityPools/aws-pool-2/providers/aws-provider-2 \\\n    --service-account=aws-federated@$PROJECT_ID.iam.gserviceaccount.com \\\n    --output-file=sts-creds.json \\\n    --aws\n```\n\nIt should look something like this in `sts-creds.json`:\n\n```json\n{\n  \"type\": \"external_account\",\n  \"audience\": \"//iam.googleapis.com/projects/1071284184436/locations/global/workloadIdentityPools/aws-pool-2/providers/aws-provider-2\",\n  \"subject_token_type\": \"urn:ietf:params:aws:token-type:aws4_request\",\n  \"token_url\": \"https://sts.googleapis.com/v1/token\",\n  \"credential_source\": {\n    \"environment_id\": \"aws1\",\n    \"region_url\": \"http://169.254.169.254/latest/meta-data/placement/availability-zone\",\n    \"url\": \"http://169.254.169.254/latest/meta-data/iam/security-credentials\",\n    \"regional_cred_verification_url\": \"https://sts.{region}.amazonaws.com?Action=GetCallerIdentity\u0026Version=2011-06-15\"\n  },\n  \"service_account_impersonation_url\": \"https://iamcredentials.googleapis.com/v1/projects/-/serviceAccounts/aws-federated@mineral-minutia-820.iam.gserviceaccount.com:generateAccessToken\"\n}\n```\n\nWhat that basically states is for GCP to look for AWS federation credentials from the EC2 metadata server or from the AWS env variables in the current shell.  Once the AWS credentials are acquired, the client library will perform the STS exchange and enable the GCP client library access.\n\nCopy the `sts-creds.json` file to the EC2 instance\n\nOn the EC2 instance, make sure it has a role binding:\n\n```bash\n[root@ip-172-31-28-179 test]# aws sts get-caller-identity\n{\n    \"Account\": \"291738886548\", \n    \"UserId\": \"AROAUH3H6EGKM3W5BCPKR:i-01eb8a107a2026dcd\", \n    \"Arn\": \"arn:aws:sts::291738886548:assumed-role/ec2role/i-01eb8a107a2026dcd\"\n}\n```\n\nNow Make sure you've previously mapped the Assumed Role defined for `aws-pool-2` as a `principalSet://`\n\n```bash\ngcloud iam service-accounts add-iam-policy-binding aws-federated@$PROJECT_ID.iam.gserviceaccount.com   \\\n    --role roles/iam.workloadIdentityUser \\\n    --member \"principalSet://iam.googleapis.com/projects/$PROJECT_NUMBER/locations/global/workloadIdentityPools/aws-pool-2/attribute.aws_role/arn:aws:sts::291738886548:assumed-role/ec2role\" \n```\n\n---\n### Test Automatic\n\nFinally, on the EC2 instance, invoke the client provided in this repo:\n\n```bash\nexport GOOGLE_APPLICATION_CREDENTIALS=`pwd`/sts-creds.json\n\n$ go run main.go    --gcpBucket $PROJECT_ID-mybucket    --gcpObjectName foo.txt    --useADC\n  2021/03/10 22:05:36 \u003e\u003e\u003e\u003e\u003e\u003e\u003e\u003e\u003e\u003e\u003e\u003e\u003e\u003e\u003e\u003e\u003e Using ADC\n  FOOOOO\n```\n\nthe `FOOOO` is the contents of our file on GCS\n\nIf you are on your laptop and have the AWS Environment variables, you can also use the automatic flow\n\n```bash\nexport AWS_ACCESS_KEY_ID=redacted \nexport AWS_SECRET_ACCESS_KEY=redacted\nexport AWS_DEFAULT_REGION=us-east-1\n\nexport GOOGLE_APPLICATION_CREDENTIALS=`pwd`/sts-creds.json\n$ go run main.go    --gcpBucket $PROJECT_ID-mybucket    --gcpObjectName foo.txt    --useADC\n```\n\n\u003e\u003e TODO: update google storage client library to pickup [PR482](https://github.com/golang/oauth2/pull/482)\n\n---\n\n### Test Manual\n\nFor manual testing, we are using `main.go` which simply wraps the flow on your laptop (note the automatic was done on an EC2 instance)\n\n- Flags:\n```golang\n  gcpBucket               = flag.String(\"gcpBucket\", \"mineral-minutia-820-cab1\", \"GCS Bucket to access\")\n  gcpObjectName           = flag.String(\"gcpObjectName\", \"foo.txt\", \"GCS object to access\")\n  gcpResource             = flag.String(\"gcpResource\", \"//iam.googleapis.com/projects/1071284184436/locations/global/workloadIdentityPools/aws-pool-1/providers/aws-provider-1\", \"the GCP resource to map\")\n  gcpTargetServiceAccount = flag.String(\"gcpTargetServiceAccount\", \"aws-federated@mineral-minutia-820.iam.gserviceaccount.com\", \"the ServiceAccount to impersonate\")\n\n  awsRegion          = flag.String(\"awsRegion\", \"us-east-1\", \"AWS Region\")\n  awsRoleArn         = flag.String(\"awsRoleArn\", \"arn:aws:iam::291738886548:role/gcpsts\", \"ARN of the role to use\")\n  awsSessionName     = flag.String(\"awsSessionName\", \"mysession\", \"Name of the session to use\")\n  useADC             = flag.Bool(\"useADC\", false, \"Use Application Default Credentials\")\n  awsAccessKeyID     = flag.String(\"awsAccessKeyID\", \"AKIAUH3H6EGKE-redacted\", \"AWS access Key ID\")\n  awsSecretAccessKey = flag.String(\"awsSecretAccessKey\", \"YRJ86SK5qTOZQzZTI1u/cA5z5KmLT-redacted\", \"AWS SecretKey\")\n  useIAMToken        = flag.Bool(\"useIAMToken\", false, \"Use IAMCredentials Token exchange\")\n```\n\na) as user:\n\n```bash\n$ export AWS_ACCESS_KEY_ID=...\n$ export AWS_SECRET_ACCESS_KEY=...\n$ export AWS_REGION=us-east-1\n\n\n$ aws sts get-caller-identity\n{\n    \"UserId\": \"AIDAUH3H6EGKDO36JYJH3\",\n    \"Account\": \"291738886548\",\n    \"Arn\": \"arn:aws:iam::291738886548:user/svcacct1\"\n}\n\n$ go run main.go \\\n   --gcpBucket $PROJECT_ID-mybucket \\\n   --gcpObjectName foo.txt \\\n   --gcpResource //iam.googleapis.com/projects/$PROJECT_NUMBER/locations/global/workloadIdentityPools/aws-pool-1/providers/aws-provider-1 \\\n   --gcpTargetServiceAccount aws-federated@$PROJECT_ID.iam.gserviceaccount.com \\\n   --useIAMToken \\\n   --awsRegion $AWS_REGION \\\n   --awsRoleArn arn:aws:iam::291738886548:role/gcpsts \\\n   --awsSessionName mysession \\\n   --awsAccessKeyID $AWS_ACCESS_KEY_ID \\\n   --awsSecretAccessKey $AWS_SECRET_ACCESS_KEY \n \n2020/10/22 15:32:50 Original Caller Identity :{\n  Account: \"291738886548\",\n  Arn: \"arn:aws:iam::291738886548:user/svcacct1\",\n  UserId: \"AIDAUH3H6EGKDO36JYJH3\"\n}\n\n2020/10/22 15:32:50 Assumed user Arn: arn:aws:sts::291738886548:assumed-role/gcpsts/mysession\n2020/10/22 15:32:50 Assumed AssumedRoleId: AROAUH3H6EGKHZUSB4BC5:mysession\n2020/10/22 15:32:50 New Caller Identity :{\n  Account: \"291738886548\",\n  Arn: \"arn:aws:sts::291738886548:assumed-role/gcpsts/mysession\",\n  UserId: \"AROAUH3H6EGKHZUSB4BC5:mysession\"\n}\n2020/10/22 15:32:51 AWS Derived GCP access_token: ya29.c.KpUD4ge5T4NtKAvjbMvOm2DsB6L28hTdrwtAV3Ts-redacted\n\nfooooo\n```\n### Using Federated or IAM Tokens\n\nGCP STS Tokens can be used directly against a **few** GCP services such as (IAMCredentials and GCS (more to come later)).\n\nWhat that means is that you do not need to enable iam impersonation on these tokens to access these services; the STS token can be used directly.\n\nBasically, that means you can skip step `(5)` of [Exchange Token](https://cloud.google.com/iam/docs/access-resources-aws#exchange-token)\n\nThis not only saves the step of running the exchange but omits the need for a secondary GCP service account to impersonate.\n\nTo use GCS, allow either the Assumed Role or AWS User access to the resource.  In this case `storage.objectAdmin` access  (yes, i'm granting the permissions below on the project, you should grant on the bucket only):\n\nTo use Federated tokens, use remove the `--useIAMToken` flag and allow the federated identity _direct)access\n\n```bash\n# principal://\n# names session\ngcloud projects add-iam-policy-binding $PROJECT_ID  \\\n --member \"principal://iam.googleapis.com/projects/$PROJECT_NUMBER/locations/global/workloadIdentityPools/aws-pool-1/subject/arn:aws:sts::291738886548:assumed-role/gcpsts/mysession\" \\\n   --role roles/storage.objectAdmin\n# user\ngcloud projects add-iam-policy-binding $PROJECT_ID  \\\n    --member \"principal://iam.googleapis.com/projects/$PROJECT_NUMBER/locations/global/workloadIdentityPools/aws-pool-1/subject/arn:aws:iam::291738886548:user/svcacct1\"\\\n      --role roles/storage.objectAdmin\n\n# principalSet://\n# named role\ngcloud projects add-iam-policy-binding $PROJECT_ID  \\\n --member \"principalSet://iam.googleapis.com/projects/$PROJECT_NUMBER/locations/global/workloadIdentityPools/aws-pool-2/attribute.aws_role/arn:aws:sts::291738886548:assumed-role/gcpsts\" \\\n   --role roles/storage.objectAdmin\n\n# ec2 role\ngcloud projects add-iam-policy-binding $PROJECT_ID  \\\n --member \"principalSet://iam.googleapis.com/projects/$PROJECT_NUMBER/locations/global/workloadIdentityPools/aws-pool-2/attribute.aws_role/arn:aws:sts::291738886548:assumed-role/ec2role\" \\\n   --role roles/storage.objectAdmin\n```\n\nSet `UseIAMToken:  false` in the go code\n\n\n\u003e\u003e NOTE: the GCP \"Automatic\" libraries  use impersonation by default...However, if you DELETE the `service_account_impersonation_url` entry  in the sts-config.json file, the ADC library will end up using federated tokens!\n\n### Logging\n\nDepending on the mode you used `UseIAMToken` flag in code, you may either see the IAM service account impersonated then access the GCS resource, or the AWS principal directly.\n\n- `UseIAMToken:  true`:\n   In this mode, the AWS credential is exchanged for a GCP STS and then the GCP STS is again exchanged for a GCP ServiceAccount Token. \n      `AWS Creds` -\u003e `GCP STS (workload pool)` -\u003e `GCP IAM (service_account)` -\u003e `GCS`\n\n   The net result is you see the iam exchange but the original AWS caller is hidden in the GCSlogs\n   The following shows the logs emitted if using AssumeRole\n\n![images/gcp_gcs_data_access.png](images/gcp_gcs_data_access.png)\n\n![images/gcp_iam_audit_logs.png](images/gcp_iam_audit_logs.png)\n\n- `UseIAMToken:  false`:\n   In this mode, the AWS credential is exchanged for a GCP STS creds and then directly against a GCP Resource\n     `AWS Creds` -\u003e `GCP STS (workload pool)` -\u003e `GCS` \n\n   The following logs shows the dataaccess logs when accessed directly as `arn:aws:iam::291738886548:user/svcacct1`:\n\n![images/gcs_logs_federated.png](images/gcs_logs_federated.png)\n\n\u003e\u003e UseIAMToken=false only works on certain GCP resources.\n\n### Direct AWS Credentials\n\nIf you want to directly pipe in the AWS credential object (`\"github.com/aws/aws-sdk-go/aws/credentials\"`) into GCP, you will need to use the 'unsupported' library and bootstrap AWS creds first and then pipe it into GCP creds:\n\nIn the following, we are using AWS credentials as the source with the ARN of `--awsRoleArn arn:aws:iam::291738886548:user/svcacct1 `\n\n```golang\n  // NOTE credential object below is \"github.com/aws/aws-sdk-go/aws/credentials\"\n  creds = credentials.NewStaticCredentials(*awsAccessKeyID, *awsSecretAccessKey, \"\")\n\tconf = \u0026aws.Config{\n\t\tRegion:      aws.String(awsRegion),\n\t\tCredentials: creds,\n\t}\n\tstsService = sts.New(session, conf)\n\tinput = \u0026sts.GetCallerIdentityInput{}\n\tresult, err = stsService.GetCallerIdentity(input)\n\tif err != nil {\n\t\tlog.Fatal(err)\n\t}\n\tlog.Printf(\"New Caller Identity :\" + result.GoString())\n\n\tawsTokenSource, err := sal.AWSTokenSource(\n\t\t\u0026sal.AwsTokenConfig{\n\t\t\tAwsCredential:        *creds,\n\t\t\tScope:                \"https://www.googleapis.com/auth/cloud-platform\",\n\t\t\tTargetResource:       \"//iam.googleapis.com/projects/1071284184436/locations/global/workloadIdentityPools/aws-pool-1/providers/aws-provider-1\",\n\t\t\tRegion:               \"us-east-1\",\n\t\t\t\tTargetServiceAccount: \"aws-federated@mineral-minutia-820.iam.gserviceaccount.com\",\n\t\t\t\tUseIAMToken:          true,\n\t\t},\n\t)        \n```\n\nIf you want to see this work, uncomment the appropriate sections in `main.go`,  \n\n```bash\n$ go run main.go    --gcpBucket $PROJECT_ID-bucket    --gcpObjectName foo.txt  \\\n   --gcpResource //iam.googleapis.com/projects/$PROJECT_NUMBER/locations/global/workloadIdentityPools/aws-pool-1/providers/aws-provider-1   \\\n   --gcpTargetServiceAccount aws-federated@$PROJECT_ID.iam.gserviceaccount.com \\\n   --useIAMToken  \\\n   --awsRegion us-east-1 \\\n   --awsRoleArn arn:aws:iam::291738886548:user/svcacct1  \\\n   --awsAccessKeyID $AWS_ACCESS_KEY_ID \\\n   --awsSecretAccessKey $AWS_SECRET_ACCESS_KEY \n\n2021/03/14 15:38:19 Original Caller Identity :{\n  Account: \"291738886548\",\n  Arn: \"arn:aws:iam::291738886548:user/svcacct1\",\n  UserId: \"AIDAUH3H6EGKDO36JYJH3\"\n}\n\nFOOOOO\n```\n\n### GCP Organization Policy \n\nFinally, you can restrict which AWS projects are allowed federation to GCP by [specifying a restrict](https://cloud.google.com/iam/docs/manage-workload-identity-pools-providers#restrict)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsalrashid123%2Fgcpcompat-aws","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsalrashid123%2Fgcpcompat-aws","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsalrashid123%2Fgcpcompat-aws/lists"}