This check flags personal Gmail or consumer Google accounts (like [email protected]) that have been granted IAM roles on your GCP project. Personal accounts sit outside your organization's controls, so move that access to a corporate identity in Cloud Identity or Workspace and remove the personal binding.
It usually starts innocently. A contractor needs quick access, someone spins up a side project, or an engineer logs in with whatever Google account their browser already had signed in. A personal @gmail.com address gets a role binding, the work gets done, and nobody ever comes back to clean it up. Months later that account still has Editor on a production project, and you have no way to enforce MFA, reset its password, or revoke it cleanly when the person leaves.
The Personal Account Used in IAM check catches exactly this situation: a consumer Google account holding IAM permissions on a GCP project instead of a managed corporate identity.
What this check detects
Lensix inspects the IAM policy bindings on your GCP projects, folders, and organization and looks for member principals that resolve to personal Google accounts rather than identities managed by your Google Workspace or Cloud Identity directory.
In practice, an IAM binding looks like this in the policy:
{
"bindings": [
{
"role": "roles/editor",
"members": [
"user:[email protected]",
"user:[email protected]"
]
}
]
}
The check distinguishes between two kinds of user: principals:
- Corporate identities tied to your verified domain (for example
[email protected]) that live in your directory and inherit your org policies. - Personal accounts such as
@gmail.comand@googlemail.com, or any account on a domain you do not own and manage.
Note: GCP does not differentiate personal from corporate accounts at the permission level. To IAM, user:[email protected] and user:[email protected] are both just users. The difference is who controls the account lifecycle, and for personal accounts the answer is "not you."
Why it matters
A personal account with project access is a governance hole. The risk is not theoretical, and it shows up in a few concrete ways.
You cannot enforce security controls
Corporate identities in Cloud Identity or Workspace inherit your organization's security posture: mandatory 2-step verification, session length limits, context-aware access, password policies, and session revocation. A personal Gmail account inherits none of that. If the owner has a weak password and no MFA, that is your production project one credential-stuffing attack away from compromise, and you have no visibility into it.
Offboarding becomes manual and error-prone
When an employee or contractor leaves, you suspend their corporate account and every bit of access they had stops working everywhere. A personal account does not get suspended because it is not yours to suspend. Someone has to remember it exists and manually strip every binding across every project. The accounts that get forgotten are the ones that become a breach years later.
Danger: A former contractor's personal account with retained roles/owner is one of the most common ways ex-staff regain access to cloud environments. They never lose the credentials, and nobody revokes them because the account is invisible to your HR offboarding process.
No audit trail to a real person
Cloud Audit Logs record the principal that performed an action. When that principal is [email protected], you have a name but no authoritative link to a known human in your directory. During an incident, attributing activity and confirming whether it was legitimate is much harder.
Shadow access that bypasses your org structure
Personal accounts often skip the access request and approval process entirely. They are granted ad hoc, frequently with far broader roles than needed (basic roles like Editor and Owner are common), and they never show up in access reviews that scope to your directory.
How to fix it
The goal is to replace each personal account binding with a managed corporate identity that has the least privilege needed, then remove the personal binding.
1. Find the personal accounts
List the IAM policy for the affected project and grep for consumer domains:
gcloud projects get-iam-policy PROJECT_ID \
--flatten="bindings[].members" \
--format="table(bindings.role, bindings.members)" \
| grep -Ei "gmail.com|googlemail.com"
To sweep an entire organization, iterate over projects:
for project in $(gcloud projects list --format="value(projectId)"); do
echo "== $project =="
gcloud projects get-iam-policy "$project" \
--flatten="bindings[].members" \
--format="value(bindings.role, bindings.members)" \
| grep -Ei "gmail.com|googlemail.com"
done
2. Provision a corporate identity
If the person needs ongoing access, create or confirm they have an account in your Cloud Identity / Workspace directory (for example [email protected]). For external collaborators, the right pattern is to invite them into your directory as a managed guest identity rather than binding their personal email directly.
3. Grant the corporate identity least-privilege access
Avoid recreating the same overly broad binding. Grant a predefined or custom role scoped to what is actually needed:
gcloud projects add-iam-policy-binding PROJECT_ID \
--member="user:[email protected]" \
--role="roles/compute.viewer"
Tip: Before swapping bindings, check the Recommender API or IAM Policy Insights to see which permissions the account actually used in the last 90 days. That tells you the minimal role to grant instead of blindly copying roles/editor.
gcloud recommender recommendations list \
--project=PROJECT_ID \
--recommender=google.iam.policy.Recommender \
--location=global
4. Remove the personal account binding
Warning: Confirm the corporate identity works and the person has logged in successfully before removing the personal binding. Pulling access prematurely can break running automation or lock someone out mid-task.
gcloud projects remove-iam-policy-binding PROJECT_ID \
--member="user:[email protected]" \
--role="roles/editor"
Repeat for every role the personal account held. The earlier flattened output gives you the exact role/member pairs to remove.
5. Verify it is gone
gcloud projects get-iam-policy PROJECT_ID \
--flatten="bindings[].members" \
--format="value(bindings.members)" \
| grep -Ei "gmail.com|googlemail.com" || echo "No personal accounts found"
How to prevent it from happening again
Cleanup is temporary. The fix that lasts is making it structurally impossible to add a personal account in the first place.
Enforce the Domain Restricted Sharing org policy
GCP ships an organization policy constraint, iam.allowedPolicyMemberDomains, that rejects any IAM binding for identities outside the customer IDs you allow. Once enabled, an attempt to bind user:[email protected] simply fails.
Find your customer ID:
gcloud organizations list
Apply the constraint with a policy file:
# domain-restriction-policy.yaml
name: organizations/ORG_ID/policies/iam.allowedPolicyMemberDomains
spec:
rules:
- values:
allowedValues:
- "C0xxxxxxx" # your Cloud Identity customer ID
gcloud org-policies set-policy domain-restriction-policy.yaml
Note: If you collaborate with another organization, add their customer ID to allowedValues rather than allowing arbitrary personal accounts. This keeps sharing scoped to trusted, managed directories.
Codify it in Terraform
Set the policy as code so it is version-controlled and cannot drift:
resource "google_organization_policy" "domain_restricted_sharing" {
org_id = var.org_id
constraint = "iam.allowedPolicyMemberDomains"
list_policy {
allow {
values = ["C0xxxxxxx"]
}
}
}
Gate IAM changes in CI/CD
Add a policy-as-code check that blocks any merge introducing a personal-account binding. With OPA / Conftest against a Terraform plan:
package gcp.iam
deny[msg] {
resource := input.resource_changes[_]
resource.type == "google_project_iam_member"
member := resource.change.after.member
endswith(member, "@gmail.com")
msg := sprintf("Personal account binding not allowed: %s", [member])
}
Wire it into the pipeline so the build fails before the apply:
terraform plan -out=tfplan
terraform show -json tfplan > plan.json
conftest test plan.json --policy ./policies
Run continuous detection
Org policies and CI gates cover changes going forward, but environments predate them. Lensix continuously scans existing IAM policies for personal accounts so the ones that slipped in before the guardrails existed do not stay hidden.
Best practices
- One identity source of truth. Every human accessing GCP should authenticate through Cloud Identity or Workspace. No exceptions for "just this once."
- Bind to groups, not individuals. Grant roles to Google Groups (
group:[email protected]) and manage membership in the directory. Access then follows your group lifecycle automatically. - Avoid basic roles. Owner, Editor, and Viewer are blunt instruments. Use predefined or custom roles scoped to the job.
- Manage external collaborators as guests. Invite contractors and partners into your directory so they inherit your MFA and offboarding, rather than binding their personal email.
- Review access regularly. Schedule quarterly IAM reviews and tie account deprovisioning to your HR offboarding workflow so leaving the company actually removes access.
- Enable MFA enforcement at the directory level so it applies to every identity, not just the ones people remember to configure.
Personal accounts in IAM are one of those issues that look minor on a single project and become a real problem at scale. Close the gap with the domain restriction policy, enforce it in your pipeline, and let continuous scanning catch the stragglers.

