GCP - Service Account
Service Account Key
A GCP Service Account Key is a long-term, static credential (usually in the form of a downloadable .json file) that acts as a permanent "username and password" for a service account.
It allows an application or script running outside of Google Cloud to authenticate as that service account and access GCP resources on its behalf.
- It's Long-Lived: Once you create this metal key, it works forever until you go to the security office and explicitly deactivate it (or the master locks are changed). It doesn't expire on its own.
- It's Static: The key itself doesn't change.
- It Works from Anywhere: Anyone who possesses this key—whether it's the real janitor, someone who found it on the street, or someone who stole it—can use it to enter the building. The door's lock only cares if the key fits; it doesn't know who is holding the key.
- It's a "Bearer" Token: Possession of the key grants access.
What's Inside the .json Key File?
The JSON file contains several fields, but the most important one is the private_key.
{
"type": "service_account",
"project_id": "my-gcp-project",
"private_key_id": "a1b2c3d4e5f6...",
"private_key": "-----BEGIN PRIVATE KEY-----\nMIIEvA... (a very long string of characters) ...\n-----END PRIVATE KEY-----\n",
"client_email": "[email protected]",
"client_id": "123456789...",
"auth_uri": "https://accounts.google.com/o/oauth2/auth",
"token_uri": "https://oauth2.googleapis.com/token",
...
}
When an application uses this file, it uses the private_key to sign a request to Google's authentication servers. Google then verifies this signature and, if it's valid, issues a short-lived OAuth 2.0 access token that the application can use to make API calls.
When Should You Use a Service Account Key? (The Legitimate, But Shrinking, Use Cases)
Historically, keys were the only way to authenticate from outside GCP. Today, with modern alternatives, their legitimate use is much more limited. You should only consider using a key when other methods are not feasible.
- On-Premise Servers: You have a physical server running in your own data center that needs to upload backups to Google Cloud Storage every night. This server is not part of any cloud environment.
- Other Cloud Providers: You have an application running in AWS or Azure that needs to access a BigQuery dataset in GCP.
- Third-Party SaaS Tools: A third-party monitoring or security tool that you use needs programmatic access to your GCP environment.
Even in these cases, a better, more secure modern alternative exists: Workload Identity Federation. This allows you to grant trust to an external identity (like an AWS IAM role or an on-premise Active Directory identity) without ever creating or managing a GCP key.
Why Are Service Account Keys So Dangerous? (The Security Risks)
Managing static keys is considered a security anti-pattern in modern cloud environments.
-
Huge Risk of Exposure: They are a file that must be stored somewhere. This makes them incredibly vulnerable to being:
- Accidentally committed to a public Git repository. This is one of the most common ways credentials are leaked. Automated bots are constantly scanning GitHub for exactly this mistake.
- Leaked from a developer's laptop.
- Left behind on a server that is later decommissioned.
- Shared insecurely over Slack or email.
-
They are Long-Lived: A stolen key works forever, or until someone notices the breach and remembers to go and manually revoke it. An attacker could have access for months without being detected. In contrast, access tokens generated via impersonation or federation typically expire in one hour.
-
Difficult to Manage and Rotate: Securely rotating keys across hundreds of applications is a massive operational burden. You have to generate a new key, securely distribute it to all your applications, and then revoke the old one, all without causing an outage. Most organizations fail to do this regularly.
The Modern, Secure Alternative: Impersonation & Federation
Instead of handing out physical copies of the master key, modern security practices prefer to grant temporary, audited access.
- For workloads inside GCP (e.g., a VM): Use the attached service account and Service Account Impersonation. The VM has its own low-privilege identity and can temporarily assume a higher-privilege role when needed. No keys are involved.
- For workloads outside GCP (e.g., on-prem or another cloud): Use Workload Identity Federation. This allows you to establish trust between your external identity provider and GCP, letting your on-prem application get short-lived GCP tokens without ever needing a GCP key.
Both Service Account Impersonation and Workload Identity Federation are processes to get a short-lived service account (OAuth 2.0) access token.
Service Account Key Alternative 1: Service Account Impersonation
Impersonation is the act of allowing one identity (like a user or another service account) to temporarily "wear the mask" of another service account and assume its permissions.
Impersonating a service account is a fundamental and powerful security practice in Google Cloud (GCP) and other cloud platforms. It's the recommended way to grant temporary, short-lived permissions to applications or users without having to manage long-term static keys.
Why is Impersonation So Important? The Security Benefits
- Eliminates Static Service Account Keys (
.jsonfiles): This is the #1 reason as mentioned above. Impersonation relies on short-lived OAuth 2.0 access tokens instead. - Principle of Least Privilege at Scale: It allows you to grant broad permissions to a central, powerful service account (e.g., one that can deploy to production) but only allow specific, trusted identities (like your CI/CD pipeline's service account) to temporarily assume those permissions when needed.
- Clear Audit Trail: When impersonation is used, Google Cloud Audit Logs record two critical pieces of information:
- Which identity (the principal) initiated the action.
- Which identity's permissions (the target service account) were used to perform the action. This makes it crystal clear who did what, and with whose authority.
- Centralized Permission Management: You manage permissions in one place. Instead of giving 10 different developer service accounts the same 20 permissions, you create one "developer-role" service account and simply grant those 10 service accounts the permission to impersonate it.
How to Impersonate a Service Account: The Two-Step Process
To impersonate a service account, you need to set up the permissions correctly. Let's call the two identities:
- Principal: The user or service account that will do the impersonating.
- Target SA: The service account that will be impersonated.
Step 1: Grant the Impersonation Permission
The Principal needs permission to generate credentials for the Target SA. This is done by granting the Principal the "Service Account Token Creator" (roles/iam.serviceAccountTokenCreator) role on the Target SA.
Using gcloud (The most common way):
Let's say:
[email protected]is your CI/CD pipeline's service account.[email protected]is the powerful service account with permissions to deploy to Cloud Run.
You would run this command:
gcloud iam service-accounts add-iam-policy-binding \
[email protected] \
--member="serviceAccount:[email protected]" \
--role="roles/iam.serviceAccountTokenCreator"
This command says: "Allow principal-sa to act as a token creator for deployer-sa."
Step 2: Perform the Impersonation
Now that the permission is granted, the Principal can generate short-lived credentials for the Target SA.
Example A: A Developer on their Laptop
A developer can configure their local gcloud CLI to act as a service account.
# 1. Authenticate gcloud with your own user account
gcloud auth login
# 2. Tell gcloud to use impersonation for all subsequent commands
gcloud config set auth/impersonate_service_account "[email protected]"
# 3. Now, any gcloud command you run...
gcloud run deploy my-app ...
# ...is executed with the permissions of 'deployer-sa', but audited as you.
To stop impersonating:
gcloud config unset auth/impersonate_service_account
Example B: A Service Account in a CI/CD Pipeline or on a VM (Workload Identity Federation)
This is the most common and secure pattern for applications. The application (running on a VM or in a CI/CD job) authenticates using its attached service account (principal-sa). It then uses the Google Cloud client libraries to programmatically generate an access token for the target service account.
The libraries handle this mostly automatically. In Go, for instance, you would specify the target service account when you create the credentials object.
// Simplified Go example
import "google.golang.org/api/option"
import "google.golang.org/api/impersonate"
// The target service account we want to impersonate
targetSA := "[email protected]"
// Create a credentials object that will handle the impersonation flow
ts, err := impersonate.CredentialsTokenSource(ctx, impersonate.CredentialsConfig{
TargetPrincipal: targetSA,
Scopes: []string{"https://www.googleapis.com/auth/cloud-platform"},
})
if err != nil {
return err
}
// Now, use these credentials to create a client for any GCP service
// The client will automatically have the permissions of the 'deployer-sa'
storageClient, err := storage.NewClient(ctx, option.WithTokenSource(ts))
This code, when run as principal-sa, will be able to perform actions on Cloud Storage using the permissions of deployer-sa.
Service Account Key Alternative 2: Workload Identity Federation
Workload Identity Federation allows you to give an identity from outside of Google Cloud (like an application in AWS, a GitHub Actions workflow, or a server in your on-premise data center) temporary, short-lived access to your GCP resources without ever creating or managing a GCP service account key.
It's a way to establish a trust relationship between Google Cloud and another trusted Identity Provider (IdP).
How Workload Identity Federation Works
It involves three main components:
- Workload Identity Pool: This is the GCP resource where you define which external identity providers you trust. You are creating a "pool" of trusted external identities.
- Workload Identity Provider: Within the pool, you configure the details of a specific IdP. For example:
- For AWS: You provide the AWS Account ID.
- For Azure: You provide the Azure Tenant ID and Application ID.
- For GitHub Actions: You provide the repository owner and name.
- For any OIDC provider (like on-prem ADFS): You provide the issuer URL.
- IAM Policy: You then write an IAM policy that says, "Allow identities from this pool that have a specific attribute (e.g., a specific AWS IAM Role ARN or a specific GitHub repository name) the permission to impersonate a specific GCP Service Account." This is the crucial mapping step.
The Authentication Flow:
- Step 1: The external workload (e.g., a script in a GitHub Actions runner) authenticates with its native IdP and gets a signed identity token.
- Step 2: The workload calls the Google Cloud Security Token Service (STS), presenting the external token and requesting a GCP token.
- Step 3: STS validates the external token against the configured Workload Identity Provider.
- Step 4: STS checks the IAM policy to see if this external identity is allowed to impersonate a GCP service account.
- Step 5: If everything checks out, STS returns a short-lived GCP service account access token.
- Step 6: The workload uses this GCP token to make authenticated calls to GCP APIs.
Why is this a Game-Changer?
- Eliminates Static Keys: This is its #1 benefit. It completely removes the need to manage and rotate dangerous
.jsonkey files for external applications. - Centralized Trust Management: You manage trust at the provider level, not the key level. If you no longer trust a specific AWS account, you can disable the provider in your pool, instantly revoking access for all identities from that account.
- Leverages Existing Identities: You don't need to create and manage a parallel set of identities in GCP. Your CI/CD system or other cloud applications can use the identity they already have.
- Improved Security Posture: It adheres to the principle of least privilege and reduces your attack surface dramatically by getting rid of long-lived, shareable credentials.
Service Account Formats?
1. Google Compute Engine (GCE) Default Service Account
This service account is automatically created when you enable the Compute Engine API in a project. It's intended for VMs that need to authenticate to GCP services.
- Format:
[email protected] - Example:
[email protected] - Components:
PROJECT_NUMBER: This is the numerical ID of your GCP project.-compute: A fixed string indicating its association with Compute Engine.@developer.gserviceaccount.com: The domain for default Google-managed service accounts.
- Purpose: Provides a default identity for GCE VMs, allowing them to access GCP resources based on the roles granted to this service account.
2. User-Managed Service Accounts
These are service accounts that you explicitly create within your GCP project. You can choose their display name and ID.
- General Format:
SERVICE_ACCOUNT_NAME@PROJECT_ID.iam.gserviceaccount.com - Examples:
- Components:
SERVICE_ACCOUNT_NAME: This is the unique ID you specify when creating the service account (e.g.,my-app-sa). It's often referred to as the "Service account ID" or "Email prefix." This ID must be unique within the project.PROJECT_ID: This is your actual GCP Project ID (not the project number), which you define when creating the project.iam.gserviceaccount.com: The standard domain for user-managed (and some other Google-managed) service accounts.
- Purpose: Provides a dedicated identity for specific applications, services, or VMs that require fine-grained access control. This is the recommended approach for most production workloads.
3. Service Agent
While "service accounts" are generally understood as identities that your workloads (VMs, applications) use, Service Agents are a specific type of Google-managed service account that Google's services use to act on your behalf within your project. They are designed to allow that Google service to perform operations on your resources (e.g., read/write to Cloud Storage, deploy Cloud Functions) without you having to manually grant permissions to a general Google identity.
- General Format:
service-PROJECT_NUMBER@gcp-sa-SERVICE_IDENTIFIER.iam.gserviceaccount.com - Components:
service-: A fixed prefix indicating it's a Google Service Agent.PROJECT_NUMBER: This is the numerical ID of your GCP project. This is crucial as it links the service agent specifically to your project.@gcp-sa-SERVICE_IDENTIFIER.iam.gserviceaccount.com:gcp-sa-: Another fixed prefix for Google Cloud Platform Service Agents.SERVICE_IDENTIFIER: A specific identifier that indicates which Google Cloud service this agent belongs to. This part is unique to each GCP service.iam.gserviceaccount.com: The standard domain for IAM service accounts.
Key Characteristics of Service Agents:
- Google-Managed: You do not create them; Google creates them when you enable a service.
- Permissions: They are automatically granted roles by Google (e.g., "Storage Object Admin" for the Cloud Storage Service Agent) to allow the respective service to operate correctly within your project.
- Cannot be deleted: You cannot directly delete these service accounts. They are tied to the lifecycle of the Google service within your project.
- Roles can be modified: While Google assigns default roles, you can manually modify the roles granted to these service agents, though it's generally not recommended unless you understand the implications, as it can break service functionality.
- Associated with Project Number: The use of
PROJECT_NUMBERin their email address format is a strong indicator that they are Google-managed and tied to the specific project.
4. Other Google-Managed Default Service Accounts
GCP services often create their own default service accounts when you enable them. These typically follow a pattern similar to user-managed accounts but with specific prefixes or project IDs.
- Google App Engine default service account:
- Format:
<project-id>@appspot.gserviceaccount.com - Example:
[email protected] - Purpose: Used by App Engine applications.
- Format:
- Cloud Functions default service account (often uses the App Engine default):
- Can use the App Engine default service account.
- If the App Engine default doesn't exist or specific settings are applied, it might use a format like:
service-<PROJECT_NUMBER>@gcf-admin-robot.iam.gserviceaccount.com.
- Cloud Build service account: (Legacy format; The recommended and modern approach is to use user-managed service accounts, tailored specifically for individual Cloud Build triggers or build configurations.)
- Format:
<PROJECT_NUMBER>@cloudbuild.gserviceaccount.com - Purpose: Used by Cloud Build to execute build steps.
- Format:
- Cloud Run default service account:
- Format:
<PROJECT_NUMBER>[email protected](often defaults to the GCE default, unless explicitly changed). - You can also specify a user-managed service account for Cloud Run services.
- Format:
- Cloud Dataflow default service account:
- Format:
service-<PROJECT_NUMBER>@dataflow-service-producer-prod.iam.gserviceaccount.com - Example:
service-123456789012@dataflow-service-producer-prod.iam.gserviceaccount.com - Purpose: Used by Dataflow jobs for internal operations.
- Format:
Key Takeaways:
@developer.gserviceaccount.com: Typically for the default Compute Engine service account, tied to the project number.@<project-id>.iam.gserviceaccount.com: The standard format for user-managed service accounts, tied to the project ID.- Other domains (
@appspot.gserviceaccount.com,@cloudbuild.gserviceaccount.com, etc.): Indicate specific Google-managed service accounts for various GCP products. - The
PROJECT_NUMBERis a numeric identifier for your project, whilePROJECT_IDis the alphanumeric string you choose. Both are unique to your project but used in different service account formats.