On the off chance you have GCP workloads (i.g. GCE VMs or Cloud Run services) that need to apply terraform templates to create resources in an AWS account you can do so by fetching an identity token from the metadata server and using the token for workload identity federation.
This assumes your Cloud Run service or GCE VM already has a service account assigned.
- Get the OAuth 2 Client ID of your Google service account. In the Google Cloud console follow IAM & Admin > Service Accounts and copy the OAuth 2 Client ID value. Alternatively run the following gcloud cli command:
gcloud iam service-accounts describe <service-account> | grep "oauth2ClientId"
- Create an AWS IAM role with
Web identity
as the Trusted entity type andGoogle
as the Identity provider. Edit the Trust Relationship section to look something like the following:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Federated": "accounts.google.com"
},
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
"StringEquals": {
"accounts.google.com:aud": "<oauth2-client-id>"
}
}
}
]
}
- Assign a policy to the IAM role, for instance if you want to manage manage EC2 instances through the service account your policy should look something like the following:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "VisualEditor0",
"Effect": "Allow",
"Action": [
"ec2:AttachVolume",
"ec2:CreateTags",
"ec2:CreateVolume",
"ec2:DeleteTags",
"ec2:DeleteVolume",
"ec2:DescribeImages",
"ec2:DescribeInstanceAttribute",
"ec2:DescribeInstances",
"ec2:DescribeInstanceStatus",
"ec2:DescribeInstanceTypes",
"ec2:DescribeTags",
"ec2:DescribeVolumeAttribute",
"ec2:DescribeVolumes",
"ec2:DescribeVolumeStatus",
"ec2:DetachVolume",
"ec2:ModifyInstanceAttribute",
"ec2:MonitorInstances",
"ec2:RebootInstances",
"ec2:RunInstances",
"ec2:StartInstances",
"ec2:StopInstances",
"ec2:TerminateInstances",
"ec2:UnmonitorInstances",
],
"Resource": "*"
}
]
}
- Get the ARN of the IAM role. In the AWS console follow IAM > Role, click on the role you created and copy the ARN value. Alternatively run the following aws cli command:
aws iam get-role --role-name <iam-role> --query "Role.Arn"
- In terraform define an http resource with
https://aws.amazon.com
as the audience to get an identity token from the metadataserver:
data "http" "id_token_request" {
url = "http://metadata/computeMetadata/v1/instance/service-accounts/default/identity?audience=https://aws.amazon.com&format=full&licenses=FALSE"
request_headers = {
Metadata-Flavor = "Google"
}
}
- In terraform define the aws resource with a
assume_role_with_web_identity
block using the ARN of the IAM role and the identity token fetched from the metadata server:
provider "aws" {
assume_role_with_web_identity {
role_arn = <iam-role-arn>
session_name = "gcp-to-aws"
web_identity_token = data.http.id_token_request.response_body
}
...
}
- Define the rest of your terraform template + apply = profit
The http request only works for GCP resources that have a service account attached to it and can access the metadata server. To validate locally we need to use the gcloud auth print-identity-token
command while impersonating the service account. (You will need the necessary GCP role to impersonate).
id_token=$(gcloud auth print-identity-token --audiences=https://aws.amazon.com --impersonate-service-account <service-account> --include-email)
Once you have the token you can inspect it.
curl "https://oauth2.googleapis.com/tokeninfo?id_token=${id_token}"
You can also test assuming the IAM role in AWS with this token.
aws sts assume-role-with-web-identity \
--role-arn <iam-role-arn> \
--role-session-name "gcp-to-aws" \
--web-identity-token ${id_token}