Skip to main content

google.iam.admin.v1.PatchServiceAccount

Event Information

  • Event meaning & scope

    • google.iam.admin.v1.PatchServiceAccount is emitted when an existing IAM service account is modified via the IAM Admin API projects.serviceAccounts.patch method (or tools/console that call it).
    • It typically reflects changes to fields like displayName, description, disabled state, or other metadata on the service account resource (not key creation/deletion or role bindings).
  • Security & compliance relevance

    • This event indicates an administrative change to an identity, which can affect access governance and audit requirements for standards like ISO 27001, SOC 2, PCI DSS, and HIPAA.
    • Frequent or unexpected patch operations, especially on high-privilege service accounts, can signal misconfiguration or potential abuse and should be monitored and correlated with change-management tickets.
  • Practical actions

    • Log and alert on this event, filtered for privileged or production service accounts (e.g., those used for CI/CD, workload identity, or cross-project access).
    • Ensure Cloud Audit Logs (Admin Activity) are enabled and retained for required periods, and periodically review PatchServiceAccount entries to verify authorized changes and adherence to least-privilege and change-control policies.

Examples

  • Privilege escalation via roles/key reuse

    • Attacker patches a low-privilege service account to add highly privileged IAM roles (e.g., roles/owner, roles/iam.serviceAccountTokenCreator), violating least-privilege (ISO 27001 A.9, SOC 2 CC6).
    • Mitigation: Restrict who can call google.iam.admin.v1.PatchServiceAccount, enforce approval workflows, and monitor for role changes on service accounts.
  • Abuse of workload identity / impersonation

    • Patch updates the description, display_name, or labels to masquerade as a legitimate production service account, then this account is bound to sensitive resources and used for impersonation, breaching access control policies (PCI DSS 7, HIPAA §164.312(a)).
    • Mitigation: Alert on changes to critical service accounts, enforce naming/labeling policies, and require justifications in change management.
  • Disruption or covert decommissioning of critical services

    • Patching removes or disables key service accounts used by production workloads (e.g., CI/CD, backup agents), causing outages or silently breaking logging/backup processes, affecting availability and integrity (SOC 2 CC7, ISO 27001 A.12).
    • Mitigation: Protect high-impact service accounts with org policies, maintain an allowlist, and set alerts for patch operations on those accounts.

Remediation

Using Console

  • Constrain who can patch service accounts (prevent privilege escalation & abuse)

    • In GCP Console, go to IAM & Admin → IAM → use the filter Role: Service Account Admin (and also check for Owner, Editor, and any custom roles with iam.serviceAccounts.update, iam.serviceAccountKeys.create, resourcemanager.projects.setIamPolicy).
    • For each over-privileged user/group:
      • Click the pencil icon → remove high-privilege roles on the project; instead, assign least-privilege custom roles that exclude iam.serviceAccounts.update, iam.serviceAccountKeys.create, and roles/owner on the project.
    • Go to IAM & Admin → Roles → for any custom roles, click into the role → Permissions → remove:
      • iam.serviceAccounts.update, iam.serviceAccounts.setIamPolicy, iam.serviceAccountKeys.*, resourcemanager.projects.setIamPolicy (or equivalents) from roles that shouldn’t modify service accounts; save and roll out via change management for ISO 27001 / SOC 2 traceability.
  • Protect & monitor critical service accounts (prevent impersonation, covert decommissioning)

    • Identify critical SAs: go to IAM & Admin → Service Accounts, sort/filter for production/CI/CD/backup/logging accounts; tag them consistently (e.g., labels environment=prod, critical=true) via Service Account → Edit.
    • Lock down who can change them:
      • For each critical SA → click it → PermissionsGrant Access only to a dedicated admin group; avoid granting Service Account Admin or Service Account Token Creator directly to individuals; ensure workloads use Service Account User at most.
    • Set alerts:
      • Go to Monitoring → Alerting → Create PolicyAdd ConditionSelect a metric and switch to Logs-based.
      • In Logs Explorer, build a query like:
        • resource.type="service_account" AND protoPayload.methodName="google.iam.admin.v1.PatchServiceAccount"
        • Further filter by labels or name (e.g., protoPayload.resourceName:"projects/-/serviceAccounts/prod-" or labels.critical="true").
      • Use this query as the condition, and set notification channels (email/Slack/Webhook). This covers:
        • Privilege escalation (unexpected role/description/label changes),
        • Impersonation attempts (SAs renamed/relabeled to mimic prod),
        • Covert decommissioning (disable/delete/patch).
  • Enforce org-wide controls & approvals (compliance, change control)

    • At the organization level, go to IAM & Admin → Organization Policies and:
      • Enable policies such as “Restrict Service Account Key Creation” and, if available, restrict who can act as service accounts (constraints/iam.allowedServiceAccountImpersonation where applicable), applying to prod folders/projects.
    • Implement change approval:
      • Require all service-account role changes to go through a ticket/change request (e.g., link IAM changes to Jira/ServiceNow IDs in the description field or internal runbooks), to satisfy PCI DSS / HIPAA / ISO 27001 / SOC 2 change management.
    • Periodically review:
      • Use IAM → Service Accounts and IAM → IAM Recommender / Policy Analyzer to review who can update or impersonate critical SAs; remove unused or unjustified bindings and document exceptions for audits.

Using CLI

  • Constrain who can patch/alter service accounts (prevent privilege escalation & impersonation)

    • Remove broad IAM on service accounts and grant only tightly scoped roles (e.g., to security automation) at the narrowest level:
      # Remove high‑risk roles from a user/principal
      gcloud projects remove-iam-policy-binding PROJECT_ID \
      --member="user:admin@example.com" \
      --role="roles/iam.serviceAccountAdmin"

      # Grant minimal patch ability only to a security group at org/folder/project as needed
      gcloud organizations add-iam-policy-binding ORG_ID \
      --member="group:secops@example.com" \
      --role="roles/iam.serviceAccountAdmin"
    • Enforce org policies to prevent risky bindings and over‑privileged roles on service accounts:
      # Block using roles/owner on service accounts
      gcloud org-policies set-policy policy-owner-block.yaml --organization=ORG_ID
      # Example YAML (policy-owner-block.yaml)
      # constraint: constraints/iam.allowedPolicyMemberDomains or
      # constraint: constraints/iam.allowedPolicyMemberTypes etc., combined with policy analyzer
    • Require change control for patching by sending gcloud changes via CI/CD with approvals; ensure logs are immutable:
      # Enable Audit Logs for IAM Admin APIs (includes PatchServiceAccount)
      gcloud logging sinks create iam-admin-logs-bq \
      bigquery.googleapis.com/projects/PROJECT_ID/datasets/SEC_AUDIT \
      --log-filter='protoPayload.serviceName="iam.googleapis.com"'
  • Protect critical service accounts (prevent disruption/decommissioning & abuse)

    • Mark high‑impact SAs and store an allowlist; regularly reconcile desired vs actual bindings:
      # List all service accounts for inventory/allowlist
      gcloud iam service-accounts list --project=PROJECT_ID

      # Export IAM policy for drift detection
      gcloud projects get-iam-policy PROJECT_ID \
      --format=json > project-iam-policy.json
    • Lock down critical SAs with least privilege and prevent deletion using dedicated admin groups:
      # Restrict who can delete SA keys
      gcloud iam service-accounts add-iam-policy-binding SA_NAME@PROJECT_ID.iam.gserviceaccount.com \
      --member="group:secops@example.com" \
      --role="roles/iam.serviceAccountKeyAdmin"

      # Remove delete rights from general admins
      gcloud iam service-accounts remove-iam-policy-binding SA_NAME@PROJECT_ID.iam.gserviceaccount.com \
      --member="group:devops@example.com" \
      --role="roles/owner"
    • Monitor for patch, update, and delete events on critical SAs and alert:
      # Create alerting filter (used in Cloud Logging or Monitoring)
      protoPayload.serviceName="iam.googleapis.com"
      protoPayload.methodName=("google.iam.admin.v1.PatchServiceAccount" OR
      "google.iam.admin.v1.DeleteServiceAccount") AND
      protoPayload.resourceName:"projects/PROJECT_ID/serviceAccounts/critical-"
  • Detect and govern impersonation / workload identity changes

    • Alert on changes to impersonation‑related roles (roles/iam.serviceAccountTokenCreator, roles/iam.serviceAccountUser) and bindings:
      gcloud logging sinks create sa-impersonation-logs \
      pubsub.googleapis.com/projects/PROJECT_ID/topics/SEC_TOPIC \
      --log-filter='protoPayload.methodName:"SetIamPolicy" AND
      protoPayload.resourceName:"projects/PROJECT_ID/serviceAccounts/" AND
      ("roles/iam.serviceAccountUser" OR "roles/iam.serviceAccountTokenCreator")'
    • Enforce naming/labeling standards and monitor for suspicious modifications to description, display_name, and labels:
      # Show details for a suspected SA
      gcloud iam service-accounts describe \
      SA_NAME@PROJECT_ID.iam.gserviceaccount.com \
      --format="yaml(email,displayName,description,labels)"
    • Periodically validate effective access vs policy (for PCI/HIPAA/SOC2 evidence) with Policy Analyzer / Policy Troubleshooter:
      # Check if a principal can impersonate a service account
      gcloud policy-intelligence troubleshoot-iam-policy \
      --principal-email="user:alice@example.com" \
      --full-resource-name="//iam.googleapis.com/projects/PROJECT_ID/serviceAccounts/SA_NAME@PROJECT_ID.iam.gserviceaccount.com" \
      --permission="iam.serviceAccounts.getAccessToken"

Using Python

  • Restrict & govern who can patch service accounts (prevent privilege escalation / abuse)

    • Use IAM to allow iam.serviceAccountAdmin or iam.serviceAccount.setter only for tightly controlled groups, and enforce approval via change management:
      gcloud projects add-iam-policy-binding PROJECT_ID \
      --member=group:cloud-iam-admins@company.com \
      --role=roles/iam.serviceAccountAdmin
    • Example Python guardrail: validate requested role changes before applying, to block escalation (run as part of CI/CD / change pipeline, not given to end-users directly):
      from google.cloud import iam_v1

      PROJECT_ID = "my-project"
      FORBIDDEN_ROLES = {
      "roles/owner",
      "roles/iam.serviceAccountAdmin",
      "roles/iam.serviceAccountTokenCreator",
      }

      def validate_binding_changes(new_policy):
      for binding in new_policy.bindings:
      if binding.role in FORBIDDEN_ROLES:
      raise RuntimeError(f"Forbidden role assignment: {binding.role}")

      def safe_patch_service_account_policy(sa_email, updater):
      client = iam_v1.IAMPolicyClient()
      resource = f"projects/{PROJECT_ID}/serviceAccounts/{sa_email}"

      # get existing policy
      policy = client.get_iam_policy(resource=resource)

      # let updater modify the policy object (add/remove bindings)
      updated_policy = updater(policy)

      # validate for escalation
      validate_binding_changes(updated_policy)

      # write back
      client.set_iam_policy(resource=resource, policy=updated_policy)

      # Example usage: only allow adding a pre-approved role
      def add_ci_role_updater(policy):
      from google.iam.v1 import policy_pb2
      binding = policy_pb2.Binding(
      role="roles/cloudbuild.builds.builder",
      members=["serviceAccount:ci-automation@my-project.iam.gserviceaccount.com"]
      )
      policy.bindings.append(binding)
      return policy

      if __name__ == "__main__":
      safe_patch_service_account_policy(
      sa_email="ci-automation@my-project.iam.gserviceaccount.com",
      updater=add_ci_role_updater
      )
    • Back this with org policy (Org Policy Service) to forbid broad roles on service accounts where possible, and align with ISO 27001 A.9 / SOC 2 CC6 by documenting the approval workflow for any role change.
  • Detect impersonation abuse & covert decommissioning (monitor patch operations and metadata changes)

    • Use Cloud Audit Logs + Python to alert on sensitive changes: description/display_name/labels changes (impersonation), and any patch/delete on protected SAs (availability / logging / backup SAs):
      from google.cloud import logging_v2

      PROJECT_ID = "my-project"
      CRITICAL_SAS = {
      "backup-agent@my-project.iam.gserviceaccount.com",
      "cicd-runner@my-project.iam.gserviceaccount.com",
      "prod-logging@my-project.iam.gserviceaccount.com",
      }

      def handle_entry(entry):
      proto_payload = entry.proto_payload
      if proto_payload.service_name != "iam.googleapis.com":
      return

      method = proto_payload.method_name
      resource = proto_payload.resource_name # e.g. projects/PROJECT/serviceAccounts/EMAIL
      if not resource:
      return

      sa_email = resource.split("/")[-1]

      # 1) any patch on critical SA
      if method in ("google.iam.admin.v1.PatchServiceAccount",
      "google.iam.admin.v1.DeleteServiceAccount"):
      if sa_email in CRITICAL_SAS:
      print(f"[ALERT] Critical SA changed: {method} on {sa_email}")
      # here: send to Pub/Sub / email / ticketing

      # 2) patch on *any* SA changing description/display_name/labels (impersonation pattern)
      if method == "google.iam.admin.v1.PatchServiceAccount":
      for meta in proto_payload.metadata:
      if meta.name == "google.api.field_mask":
      paths = meta.value.string_value.split(",")
      if any(p.strip() in ("description", "display_name", "labels") for p in paths):
      print(f"[ALERT] Metadata change on SA {sa_email}: {paths}")

      def stream_audit_logs():
      client = logging_v2.LoggingServiceV2Client()
      parent = f"projects/{PROJECT_ID}"
      flt = (
      'logName:"cloudaudit.googleapis.com/activity" '
      'AND protoPayload.serviceName="iam.googleapis.com" '
      'AND protoPayload.methodName:"google.iam.admin.v1."'
      )
      for entry in client.list_log_entries({"resource_names": [parent], "filter": flt}):
      handle_entry(entry)

      if __name__ == "__main__":
      stream_audit_logs()
    • Use this to support PCI DSS 7 / HIPAA 164.312(a) by proving that all changes to high-risk identities are monitored, with alerts tied into your SIEM or ticketing system.
  • Protect high-impact service accounts via policy & allowlists (prevent disruption)

    • Maintain a centralized allowlist of “protected” SAs (backup, logging, CI/CD, production runtimes), and enforce that only designated admin groups can modify them; implement a protective wrapper for updates:
      PROTECTED_SAS = {
      "backup-agent@my-project.iam.gserviceaccount.com",
      "cicd-runner@my-project.iam.gserviceaccount.com",
      "prod-logging@my-project.iam.gserviceaccount.com",
      }

      ALLOWED_UPDATER_MEMBERS = {
      "group:platform-ops@company.com",
      "group:security-admins@company.com",
      }

      from google.cloud import iam_v1

      def is_caller_allowed(entry):
      caller = entry.proto_payload.authentication_info.principal_email
      # In production, map caller to group via your IdP or Cloud Identity groups
      return any(group in ALLOWED_UPDATER_MEMBERS for group in []) # stub

      def guard_critical_sa_change(entry):
      method = entry.proto_payload.method_name
      resource = entry.proto_payload.resource_name
      if not (method.startswith("google.iam.admin.v1.PatchServiceAccount") or
      method.startswith("google.iam.admin.v1.DeleteServiceAccount")):
      return

      sa_email = resource.split("/")[-1]
      if sa_email not in PROTECTED_SAS:
      return

      if not is_caller_allowed(entry):
      print(f"[BLOCK/ROLLBACK] Unauthorized change to protected SA {sa_email}")

      # Optional: auto-rollback last change using stored baseline
      # (requires you to persist last-known-good SA configs and reapply them)

      # Call guard_critical_sa_change() from your log processing pipeline
    • Complement this with:
      • Org Policy / IAM deny policies to prevent deletion or role changes to specific SAs except by specific admins.
      • Regular comparison of current SA IAM and metadata against a baseline (GitOps) and auto-remediate drift, supporting SOC 2 CC7 / ISO 27001 A.12 by ensuring critical services can’t be silently decommissioned.