问题
I'm trying to sign GCS URLs with the GCE default service account. I gave the compute default service account the necessary "Service Account Token Creator" role. When I try to sign a url in the following Python code, I get an error:
import google.auth
import google.auth.iam
from google.auth.transport.requests import Request as gRequest
creds, _ = google.auth.default(request=gRequest(), scopes=[
'https://www.googleapis.com/auth/cloud-platform',
'https://www.googleapis.com/auth/devstorage.read_write',
'https://www.googleapis.com/auth/logging.write',
'https://www.googleapis.com/auth/firebase',
'https://www.googleapis.com/auth/compute.readonly',
'https://www.googleapis.com/auth/userinfo.email',
])
## creds is a google.auth.compute_engine.credentials.Credentials
## creds.service_account_email is '<project-id>-compute@developer.gserviceaccount.com'
signer = google.auth.iam.Signer(
gRequest(), credentials=creds,
service_account_email=creds.service_account_email)
signer.sign('stuff')
Error:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
<TRUNCATED - my code>
File "/usr/local/lib/python3.6/dist-packages/google/auth/iam.py", line 101, in sign
response = self._make_signing_request(message)
File "/usr/local/lib/python3.6/dist-packages/google/auth/iam.py", line 85, in _make_signing_request
response.data))
google.auth.exceptions.TransportError: Error calling the IAM signBytes API: b'{\n "error": {\n "code": 400,\
n "message": "Invalid service account email (default).",\n "status": "INVALID_ARGUMENT"\n }\n}\n'
Is using the GCE default SA not allowed? Are there other default SAs that aren't allowed (specifically the Google App Engine Flexible SA)?
回答1:
You need two roles. One of which you cannot grant in the Google Cloud Console to your default GCE service account. Make note of your service account email address that you want to use.
[UPDATE 01/19/2019]
When you create credentials, they are not initialized until required (e.g. no access token is requested). To preinitialize the credentials:
auth_url = "https://www.googleapis.com/oauth2/v4/token"
headers = {}
request = google.auth.transport.requests.Request()
creds.before_request(request, "POST", auth_url, headers)
[END UPDATE]
Grant your service account the role roles/iam.serviceAccounts.signBlob
gcloud projects add-iam-policy-binding <project-id> --member=serviceAccount:<project-id>-compute@developer.gserviceaccount.com --role=roles/iam.serviceAccounts.signBlob
Now this service account can sign data using the private key.
Now grant this service account the role roles/iam.serviceAccountTokenCreator
gcloud iam service-accounts add-iam-policy-binding <project-id>-compute@developer.gserviceaccount.com --member=<project-id>-compute@developer.gserviceaccount.com --role=roles/iam.serviceAccountTokenCreator
Now this service account can use this service account to create tokens. In the command you are giving the first service_account_email the priviledge to use the second service_account_email. Think of this as delegation. Notice that one role is at the project level and the other role is assigned to the service account itself.
In my code, I actually create a new service account and use that service account's email address for signing. I grant permissions to the new service account (with the first command) and I grant permission to use the new service account with my credentials (the second command).
来源:https://stackoverflow.com/questions/54271402/sign-google-cloud-storage-urls-with-google-compute-engine-default-service-accoun