Let me provide a comprehensive solution covering all three critical aspects:
Role Permissions Analysis:
The issue is that roles/iam.serviceAccountAdmin gives you permissions to manage service accounts (create, delete, list) but NOT to grant arbitrary roles to them. When you assign a role to a service account, you need two things:
- iam.serviceAccounts.setIamPolicy permission (which you have)
- Permission to grant the specific role you’re assigning
For your case assigning compute.instanceAdmin and storage.objectViewer:
// Your automation account needs:
roles/iam.serviceAccountAdmin // To modify SA
roles/compute.admin // To grant compute roles
roles/storage.admin // To grant storage roles
Service Account Admin Best Practice:
Instead of granting yourself all possible roles, use roles/iam.securityAdmin which has iam.roles.* permissions allowing you to grant any role. However, this is highly privileged. Better approach for automation:
Create a custom role:
gcloud iam roles create ServiceAccountRoleManager \
--project=PROJECT_ID \
--permissions=iam.serviceAccounts.setIamPolicy,iam.roles.get,resourcemanager.projects.getIamPolicy,resourcemanager.projects.setIamPolicy
Then grant your automation account this custom role PLUS the specific roles it needs to delegate (compute.admin, storage.admin in your case).
Organization Policy Check:
This is often the hidden blocker. Check these constraints:
- List active policies:
gcloud resource-manager org-policies list --project=PROJECT_ID
- Check service account restrictions:
gcloud resource-manager org-policies describe \
constraints/iam.allowedPolicyMemberDomains \
--project=PROJECT_ID
If this constraint is set, it may block service accounts from certain domains. You might need to add your service account’s domain to the allowed list.
- Check if automated changes are restricted:
gcloud resource-manager org-policies describe \
constraints/iam.disableServiceAccountKeyCreation \
--project=PROJECT_ID
Complete Solution:
For your automation service account, grant:
- roles/iam.serviceAccountAdmin (service account management)
- roles/iam.securityAdmin (ability to grant any role) OR specific admin roles for each service
- Verify no org policy constraints block programmatic IAM changes
The API call should then work. The console works because you’re authenticated as a user with broader permissions, while your automation service account has restricted scope. The key is ensuring your automation account has permission to grant the specific roles you’re assigning, not just permission to modify service accounts.