Why Service Account Impersonation is Essential for Secure and Efficient Cloud Development

Hikikomori NekoHikikomori Neko
8 min read

From securing a local development environment to managing on-call incident response, a common challenge is authenticating with the cloud provider safely and effectively. Instead of using long-lived credentials like secret keys or an overly permissive user account, a more secure practice is to impersonate a service account. This approach allows us to operate with only the necessary permissions, effectively applying the principle of least privilege to our development workflow. In addition to the security benefits, it also minimizes the potential damage from incorrect commands or unintentional actions. This is the same principle for accessing the production environment during on-call rotations, where we should always default to view-only permissions and only escalate to a privileged role when required.

My recent experience creating an agentic application with Google Cloud provided a timely reminder of this process. While the initial setup for impersonation involves some overhead compared to using a powerful user account, experience has shown me that this upfront investment is invaluable. The initial friction of following best practices quickly becomes negligible, whereas the convenient path too often evolves into a maintenance nightmare down the road. In this article, I will share the key benefits of service account impersonation I've learned over the years.

Benefit #1: Proactive Permission Right-Sizing

One key benefit of service account impersonation is its role in right-sizing permissions for production. By using this method during development, we organically discover the exact permissions our application needs to function. This proactive process yields a clear and validated permission set that can be used to configure a dedicated, least-privilege service account for the final service or CI/CD pipeline. It avoids the common pitfall of assigning overly broad permissions out of uncertainty and replaces the time-consuming, trial-and-error process of establishing a security policy.

While tools like access recommenders and security scanners are valuable for auditing, their reactive nature often makes remediation slow and error-prone. Removing permissions is quick, but it risks inadvertently deleting a subtle, required permission, which could turn a release into a high-risk event, especially with poor test coverage. The issue requires even greater caution when considering permissions that are required but used infrequently, such as for a once-a-year event or disaster recovery. A single missing permission can become a critical production incident or a bottleneck when it's needed the most. For this reason, building the policy correctly from the start is inherently safer and more reliable.

Benefit #2: Safer On-Call with Automated Workflows

A key operational benefit of impersonation is how it dramatically reduces the blast radius of human error. Whether it's using the wrong cloud console or a script executed in the wrong terminal, mistakes are unfortunately common when multitasking between on-call and development duties. To mitigate these risks, professional teams often implement procedural safeguards like using different color themes for consoles or requiring a second engineer for manual changes. However, these safeguards still fundamentally rely on human discipline.

In contrast, a better approach is to prepare automated workflows for common on-call operations. By default, users should have view-only permissions. When a production alert occurs, they can impersonate a service account that is authorized to execute these pre-approved workflows. This creates multiple layers of safety. For instance, if a command meant for development is mistakenly run in a production terminal, it will simply fail against the user's restricted permissions. For necessary interventions, users trigger specific, tested workflows via service account impersonation. Finally, for true emergencies or uncommon events, a separate privilege escalation process allows for broader manual access, ensuring even last-resort actions are handled efficiently and with complete traceability. This system-enforced guardrail gives us an additional layer of protection that not only reduces the chance of human error but also the stress of a production incident.

Benefit #3: A Crystal-Clear Audit Trail

One of the most compelling reasons to use service account impersonation is the unambiguous audit trail it creates. When a user impersonates a service account, Cloud Audit Logs show exactly which user initiated the action, providing a clear record of accountability. This is a significant improvement over two common, less secure patterns:

  • Privileged User Accounts: When a powerful user account is used for both administrative and development tasks, the audit logs become ambiguous. It's nearly impossible to tell whether a logged action was an administrative command or a local application's activity.

  • Static Service Account Keys: This is the least secure option, as it provides no user identity in the logs. This complete loss of traceability is a major security and compliance risk.

This elegant approach solves both problems by decoupling user authentication from task-specific permissions. We grant a user a narrow permission to impersonate a service account, rather than assigning broad permissions directly. This allows us to enforce robust controls like multi-factor authentication (MFA) at the user level, while the service account holds the granular permissions for the task at hand.

To see this in action, let's walk through an audit log example, but first, a crucial reminder: we must enable audit logs for the API we want to trace. Assuming an action was performed by an application, like a call to the GenerateContent API, the authenticationInfo block in the audit log will show that while the principalEmail was the service account, our user account was also logged in the serviceAccountDelegationInfo block.

"authenticationInfo": {
  "principalEmail": "local-dev@service-account-email",
  "principalSubject": "serviceAccount:local-dev@service-account-email",
  "serviceAccountDelegationInfo": [
    0: {
      "firstPartyPrincipal": {
        "principalEmail": "[USER ACCOUNT]"
      }
    }
  ]
}

The log entry gives us even more context, as it also identifies the source of the API call. By looking at the callerSuppliedUserAgent field, we can determine how the action was initiated. For example, an application SDK leaves a clear footprint:

"requestMetadata": {
  "callerIp": "[IP ADDRESS]",
  "callerSuppliedUserAgent": "google-genai-sdk/1.27.0 gl-python/3.13.5 google-adk/1.8.0 gl-python/3.13.5,gzip(gfe)"
}

If the action had been performed using the gcloud command line tool instead, the user agent would clearly identify the gcloud tool:

"requestMetadata": {
  "callerIp": "[IP ADDRESS]",
  "callerSuppliedUserAgent": "google-cloud-sdk gcloud/531.0.0 command/gcloud.storage.ls ... ,gzip(gfe)"
}

Together, these fields provide a complete story, identifying the user who initiated the action and the tool they used, whether it was an application SDK or a command-line tool. In contrast, this rich, traceable information is completely lost when using static service account keys, as the audit log can only identify the service account and the specific key that was used.

"authenticationInfo": {
  "principalEmail": "local-dev@service-account-email",
  "serviceAccountKeyName": "[SERVICE ACCOUNT KEY PATH]"
}

The Impersonation Workflow: CLI and Applications

The setup for service account impersonation in Google Cloud has a common point of confusion: the steps for the gcloud CLI and a local application's SDK are slightly different. To run a gcloud command with a service account identity, we need to configure impersonation for the CLI. However, to run our local application and allow its SDK to access services with a service account identity, we need to set up Application Default Credentials (ADC) with impersonation. It's important to note that if we need both functionalities, we should complete both setup steps.

Let's walk through an example to demonstrate the process. The first step is to authenticate our gcloud CLI tool, as this is a prerequisite for granting the necessary IAM permissions. When we run the command below, we'll be prompted for our credentials. Once complete, all subsequent gcloud commands will use our user account's identity. Note that this step is not necessary if we are using Cloud Shell.

gcloud auth login

Next, we need to grant our user account the permission to impersonate a service account, which is the Service Account Token Creator role. This is a critical step, as even the project Owner role does not include this permission by default. To grant the role for a specific service account, we use the following command:

gcloud iam service-accounts add-iam-policy-binding "[SERVICE_ACCOUNT_EMAIL]" \
    --member="user:[USER_ACCOUNT_EMAIL]" \
    --role="roles/iam.serviceAccountTokenCreator"

To confirm the role has been granted, we can list the principals with this role using the following command. We should see our user account in the output as a principal with that role.

gcloud iam service-accounts get-iam-policy "[SERVICE_ACCOUNT_EMAIL]" \
    --flatten="bindings[].members" \
    --filter="bindings.role:roles/iam.serviceAccountTokenCreator"

Now that our user account has the permission to impersonate the service account, the following impersonation process diverge for gcloud CLI and the application SDK.

Path A: Configuring the gcloud CLI

To configure our gcloud CLI to use impersonation, we can run the command below. Once it's complete, all subsequent gcloud commands we execute will use the specified service account.

gcloud config set auth/impersonate_service_account "[SERVICE_ACCOUNT_EMAIL]"

As a side note, if we only need to impersonate for a single gcloud command, we can use the --impersonate-service-account parameter to override the default.

gcloud storage ls --impersonate-service-account "[SERVICE_ACCOUNT_EMAIL]"

When needed, we can disable service account impersonation for gcloud CLI with the following command:

gcloud config unset auth/impersonate_service_account

Path B: Configuring Application Default Credentials (ADC)

Let's look at the process for setting up service account impersonation for our local application SDK. The following command will use the specified service account to create a local Application Default Credentials (ADC) file. Our application SDK will then use the impersonated identity to access Google Cloud services.

gcloud auth application-default login \
    --impersonate-service-account "[SERVICE_ACCOUNT_EMAIL]"

Note that not all the client libraries support credentials from a local ADC file generated via impersonation, though the most common ones do. For a full list of supported libraries, please refer to the Google Cloud Documentation below.

Reference: Google Cloud Documentation

Conclusion

Being granted access to a production environment is a privilege that puts significant weight on a developer and demonstrates a high level of trust. My experience with on-call rotations taught me that in addition to security, we also need robust systems to protect against our own mistakes, especially when under stress. While many complain that security policies hinder efficiency, the protection we gain from avoiding our own errors often outweighs the inconvenience. In fact, the damage from internal missteps can sometimes be even greater than that of an external cyberattack. This principle becomes even more critical in the era of agentic applications, where autonomous agents perform tasks on our behalf. As we begin to use these agentic workflows to help make decisions on production incidents, adopting a secure-by-default workflow, like service account impersonation, will be essential for managing risk while gaining the efficiency these new tools provide.

My journey as a student of security and cloud-native design will continue. In a future article, I will explore the process of privilege access management, where we can transparently request privilege escalation when needed.

Thank you for reading!

0
Subscribe to my newsletter

Read articles from Hikikomori Neko directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Hikikomori Neko
Hikikomori Neko