feat: managed service account querying strategy#2433
Conversation
|
Hi @wojtekmach , would need some advice on the service account impersonation via Goth here. I've tried achieving the SA impersonation using the custom claims map as documented, but it does not seem to work This issue mentions the docs discrepancy, but i suspect why they're able to successfully impersonate is due to domain-wide delegation vs the gcp-specific iam role granted as documented here in the GCP docs. Any ideas? |
|
@Ziinc unfortunately this particular flow is not supported out of the box. And you're right custom claims map didn't work for me either. Could you check the following snippet and see if it does what you need? Remember to use a test gcloud account :) # $ PROJECT_ID="wojtekmach"
# $ gcloud services enable iam.googleapis.com iamcredentials.googleapis.com
# $ gcloud iam service-accounts create goth-test-sa1
# $ gcloud iam service-accounts create goth-test-sa2
# $ sa1="goth-test-sa1@${PROJECT_ID}.iam.gserviceaccount.com"
# $ sa2="goth-test-sa2@${PROJECT_ID}.iam.gserviceaccount.com"
# $ gcloud iam service-accounts keys create ~/sa1.json --iam-account=$sa1
# $ cloudshell download ~/sa1.json
# $ gcloud projects add-iam-policy-binding $PROJECT_ID \
# --member="serviceAccount:$sa2" \
# --role="roles/iam.serviceAccountViewer"
# $ gcloud iam service-accounts add-iam-policy-binding $sa2 \
# --member="serviceAccount:$sa1" \
# --role="roles/iam.serviceAccountTokenCreator"
Mix.install([:goth, :req])
project_id = "wojtekmach"
sa1 = "goth-test-sa1@#{project_id}.iam.gserviceaccount.com"
sa2 = "goth-test-sa2@#{project_id}.iam.gserviceaccount.com"
# 1. sa1 tries to view itself, fails because it does not have iam.serviceAccountViewer role
sa1_credentials =
File.read!(Path.expand("~/Downloads/sa1.json"))
|> Jason.decode!()
{:ok, %{token: sa1_token}} = Goth.Token.fetch(source: {:service_account, sa1_credentials})
Req.get!(
"https://iam.googleapis.com/v1/projects/-/serviceAccounts/#{sa1}",
auth: {:bearer, sa1_token}
).body
|> dbg()
# 2. sa1 creates a shortlived token for s2 and uses it to view s2
%{status: 200, body: %{"accessToken" => sa2_token}} =
Req.post!(
"https://iamcredentials.googleapis.com/v1/projects/-/serviceAccounts/#{sa2}:generateAccessToken",
auth: {:bearer, sa1_token},
json: %{
"scope" => ["https://www.googleapis.com/auth/cloud-platform"]
}
)
Req.get!(
"https://iam.googleapis.com/v1/projects/-/serviceAccounts/#{sa2}",
auth: {:bearer, sa2_token}
).body
|> dbg()Btw, please always ping @Logflare/dashbit even if you have a question to any of us in particular. This way we're all up to date and can respond to you when someone is off etc. |
|
@wojtekmach thanks for the hint, I was able to get the impersonation up and running with our fork 🎉 |
|
That's great, thanks for opening up a PR too! |
438825d to
c97f72f
Compare
wojtekmach
left a comment
There was a problem hiding this comment.
Looks good to me, I left a couple minor comments below.
This PR adds in managed service account querying, to get around Google's 100 rps rate limit on core REST api calls.