Back to Checks
gcp

Service account has no user-managed keys

iam_sa_no_user_managed_keys
Service: iamSeverity: medium
OfficialBuilt-inVerified
Categories:secretsidentity-access
Resource Type:iam.googleapis.com/ServiceAccount

IAM service accounts do not have keys of type USER_MANAGED; only Google-managed keys (or no keys) are present.

Risk

User-managed keys are downloadable and long-lived, increasing theft and reuse risk. An attacker with a key can impersonate the service account, perform unauthorized API calls, exfiltrate data, and alter resources, impacting confidentiality and integrity, and potentially availability. Copies in repos or logs can evade centralized rotation and revocation.

Run this check with Prowler

Run in Prowler Cloud
Run
prowler gcp --checks iam_sa_no_user_managed_keys

Recommendation

Avoid user-managed keys. Use service account impersonation or Workload Identity Federation for short-lived credentials and least privilege. Enforce iam.disableServiceAccountKeyCreation, restrict who can create keys, and monitor usage. If exceptions are unavoidable, tightly scope, rotate aggressively, and store keys securely.

Remediation

CLI

gcloud iam service-accounts keys delete <KEY_ID> --iam-account=<SERVICE_ACCOUNT_EMAIL>

Other

1In the Google Cloud console, go to IAM & Admin > Service Accounts
2Select your project and click the affected service account
3Open the Keys tab
4For each key with Type "User-managed", click Delete and confirm
5Verify no User-managed keys remain for that service account
6Repeat for any other affected service accounts

Check Code

from prowler.lib.check.models import Check, Check_Report_GCP
from prowler.providers.gcp.services.iam.iam_client import iam_client


class iam_sa_no_user_managed_keys(Check):
    def execute(self) -> Check_Report_GCP:
        findings = []
        for account in iam_client.service_accounts:
            report = Check_Report_GCP(
                metadata=self.metadata(),
                resource=account,
                resource_id=account.email,
                location=iam_client.region,
            )
            report.status = "PASS"
            report.status_extended = (
                f"Account {account.email} does not have user-managed keys."
            )
            for key in account.keys:
                if key.type == "USER_MANAGED":
                    report.status = "FAIL"
                    report.status_extended = (
                        f"Account {account.email} has user-managed keys."
                    )
            findings.append(report)

        return findings