0
votes

I am using Cloud Build and would like to run a Docker container under a different service account than the standard Cloud Build service account (A). The service account I would like to use (B) is from a different project. One way to do it would be to put the json key on Cloud Storage and then mount it in the Docker container, but I think it should be possible with IAM policies too. My cloubuild.yaml now contains the following steps:

steps:
  - name: 'gcr.io/kaniko-project/executor:v0.20.0'
    args:
      - --destination=gcr.io/$PROJECT_ID/namu-app:latest
      - --cache=true
      - --cache-ttl=168h
  - name: 'docker'
    args: ['run', '--network=cloudbuild', 'gcr.io/$PROJECT_ID/namu-app:latest']

The network is set so that Cloud Build service account is accessible to docker container - see https://cloud.google.com/cloud-build/docs/build-config#network. So I think my container should have access to the Cloud Build service account. Then I run the following code inside the Docker container:

import socket
from googleapiclient.discovery import build
from google.auth import impersonated_credentials, default

default_credentials, _ = default()
print("Token: {}".format(default_credentials.token))
play_credentials = impersonated_credentials.Credentials(
    source_credentials=default_credentials,
    target_principal='google-play-api@api-0000000000000000-0000000.iam.gserviceaccount.com',
    target_scopes=[],
    lifetime=3600)

TRACK = "internal"
PACKAGE_NAME = 'x.y.z'
APPBUNDLE_FILE = "./build/app/outputs/bundle/release/app.aab"

socket.setdefaulttimeout(300)
service = build('androidpublisher', 'v3')
edits = service.edits()
edit_id = edits.insert(body={}, packageName=PACKAGE_NAME).execute()['id']

However, this fails with:

 googleapiclient.errors.HttpError: <HttpError 403 when requesting https://www.googleapis.com/androidpublisher/v3/applications/x.y.z/edits?alt=json returned "Request had insufficient authentication scopes.">

I tried several ways of assigning service account roles, but no luck so far. I thought at first that explicitly 'impersonating' credentials might not be necessary (maybe it can be implicit?). In summary, I want service account A from project P1 to run as service account B from project P2. Any ideas?

2
The error you are getting is on the code side, try adding the required scope: target_scopes=['https://www.googleapis.com/auth/androidpublisher'].llompalles
Thank you. I added this, but the same error still occurs.Stéphane
Are you getting the same result when running the code on you local environment?llompalles
No, from my local environment this exact same script works (just tested it). A difference is that the service account that I use locally is my own (user) service account, not the Cloud Build service account.Stéphane
Did you also set permissions to the Cloud Build Service Account on the second project?Jose V

2 Answers

0
votes

You might follow to alternatives to troubleshoot this issue:

  1. Give the Cloud Build service account the same permissions that has the service account you are using to run this on your local environment.

  2. Authenticate with a different approach using a credentials file, as shown in this code snippet:

from apiclient.discovery import build
import httplib2
from oauth2client import client


SERVICE_ACCOUNT_EMAIL = (
    'ENTER_YOUR_SERVICE_ACCOUNT_EMAIL_HERE@developer.gserviceaccount.com')


# Load the key in PKCS 12 format that you downloaded from the Google APIs
# Console when you created your Service account.
f = file('key.p12', 'rb')
key = f.read()
f.close()

# Create an httplib2.Http object to handle our HTTP requests and authorize it
# with the Credentials. Note that the first parameter, service_account_name,
# is the Email address created for the Service account. It must be the email
# address associated with the key that was created.
credentials = client.SignedJwtAssertionCredentials(
      SERVICE_ACCOUNT_EMAIL,
      key,
      scope='https://www.googleapis.com/auth/androidpublisher')
  http = httplib2.Http()
  http = credentials.authorize(http)

service = build('androidpublisher', 'v3', http=http)
-1
votes

Using gcloud you can do gcloud run services update SERVICE --service-account SERVICE_ACCOUNT_EMAIL. Documentation also says that

In order to deploy a service with a non-default service account, the deployer must have the iam.serviceAccounts.actAs permission on the service account being deployed.

See https://cloud.google.com/run/docs/securing/service-identity#gcloud for more details.