GCP Service Account Keys Explained: What They Are, How They Work, and When to Avoid Them
A service account key is a downloadable JSON file containing an RSA private key. Anyone who holds this file can authenticate as the service account it belongs to, from any machine, any IP address, anywhere in the world, with no time limit, until the key is explicitly deleted. That is what makes them powerful and what makes them risky.
Why this page exists
Service account keys appear throughout GCP documentation, tutorials, and older infrastructure setups. If you are learning GCP, you will encounter them. You may be asked to create one, debug why one is not working, or figure out whether you need one at all.
This page explains what service account keys are, how they work under the hood, what is actually inside the JSON file, and — critically — when you should reach for them versus when a safer alternative is the better call. By the end, you will have a complete mental model of the mechanism and a clear decision framework for when keys are and are not appropriate.
What is a service account key, in plain English
Start with service accounts.
A service account is a non-human identity in Google Cloud. It has an email
address like ci-deployer@my-project.iam.gserviceaccount.com and
it can be granted IAM roles just
like a user account can. Applications, pipelines, and automated processes
use service accounts to call GCP APIs instead of acting as a person.
Now, a service account on its own is just a record in IAM. To actually prove you are that identity when connecting from outside Google’s infrastructure, you need a credential. A service account key is that credential. It is a file that contains a private cryptographic key. When your code uses this file to make an API call, it signs a request with the private key, Google verifies the signature using the matching public key it holds, and then issues a short-lived access token. That token is what actually authorises the request.
The critical thing to understand: whoever holds the key file can act as that service account. The file itself is the proof of identity. There is no PIN, no MFA, no IP restriction, and no time limit baked into the key. The file is the credential. Full stop.
Think of it like a swipe card
A service account is like an employee record in an HR system — it defines who someone is and what they are allowed to access. A service account key is like the physical swipe card issued to that employee. Anyone who picks up the card can badge through the doors, regardless of who they actually are. The card reader does not check your face. It checks the card.
Service account keys are sometimes called “SA keys”, “JSON keys”, or just “key files”. They all mean the same thing: a downloaded JSON file containing a private key that authenticates as a specific service account. See Identity vs Service Accounts for a broader look at how GCP separates human and non-human identities.
How service account keys work
The authentication flow is worth understanding step by step. It explains why keys are powerful and why losing one is serious.
Key pair created. When you create a service account key, GCP generates an RSA key pair: a private key and a matching public key.
Private key delivered to you. The private key is embedded in a JSON file and downloaded to your machine. This is the only moment Google delivers the private key. It is not stored by Google after download.
Public key retained by Google. Google stores only the public key on its side, linked to the service account.
Your code signs requests. When your application needs to call a GCP API, it uses the private key to sign a short-lived JWT (JSON Web Token) asserting the service account identity.
Google verifies the signature. Google checks the JWT signature against the public key it holds. If the signature is valid, it knows the request came from whoever has the private key.
Access token issued. Google returns a short-lived OAuth 2.0 access token (typically valid for one hour). Your application uses this token to call GCP APIs.
Access is defined by IAM, not the key. What the token can actually do depends entirely on the IAM roles attached to the service account, not anything in the key file itself. The key proves identity. IAM determines what that identity is allowed to do.
Signing, not sharing a password
The signing step is similar to how a notarised document works. You sign the document with your private seal (the private key). Anyone with your public seal (the public key) can verify that you signed it, without you ever handing over your seal itself. Google never sees your private key again after you download it. It only ever sees your signature.
Most GCP client libraries handle steps 4 through 6 automatically when you
point them at a key file via the GOOGLE_APPLICATION_CREDENTIALS
environment variable. You rarely write the signing logic yourself.
What a service account key file contains
When you download a key, you get a JSON file that looks like this (values truncated for readability):
{
"type": "service_account",
"project_id": "my-app-prod",
"private_key_id": "abc123def456...",
"private_key": "-----BEGIN RSA PRIVATE KEY-----\nMIIEowIBAAKCAQEA...\n-----END RSA PRIVATE KEY-----\n",
"client_email": "ci-deployer@my-app-prod.iam.gserviceaccount.com",
"client_id": "123456789012345678901",
"auth_uri": "https://accounts.google.com/o/oauth2/auth",
"token_uri": "https://oauth2.googleapis.com/token",
"auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
"client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/ci-deployer%40my-app-prod.iam.gserviceaccount.com"
}Here is what each field means and which ones are sensitive:
private_key: the RSA private key. This is the dangerous field. Anyone with this value can sign authentication requests as the service account. Everything else in the file is non-secret metadata, but this field alone is what makes the file a live credential.private_key_id: a unique identifier for this specific key. Used when deleting or auditing keys. Not itself sensitive, but useful for tracking.client_email: the service account’s email address. This is the identity that gets used when making API calls. It tells you exactly which service account the key belongs to.project_id: the GCP project the service account lives in. Useful context for understanding the blast radius if the key is leaked.token_uri: the endpoint used to exchange a signed JWT for an access token. Client libraries use this automatically.
Treat the entire file as a secret, not just the private_key
field. The combination of fields gives an attacker everything needed to
impersonate the service account. Handle this file the same way you would
handle a production database password: never commit it to source control,
never paste it into a chat, and never leave it on a shared machine.
When service account keys are and are not needed
When keys are usually NOT needed
The majority of GCP workloads do not need service account keys, because
GCP provides a better mechanism: the metadata server.
When you attach a service account to a GCP resource, the metadata server
(a special internal endpoint at 169.254.169.254 accessible
only from within the resource) automatically provides temporary credentials
to code running on that resource. No file download, no secret management,
no rotation required.
This applies to all of the following:
- Compute Engine VMs with an attached service account
- Cloud Run services with a specified service account
- Cloud Functions with an assigned service account
- GKE pods using Workload Identity for GKE
- Cloud Build jobs, App Engine services, Dataflow jobs, and other managed runtimes
If your code is already running on GCP, there is almost certainly no reason to use a key. The credentials are already there, managed automatically, rotated automatically, and scoped to the resource they are running on. Using a key in this context adds risk with no benefit.
When keys might still be needed
Keys are occasionally legitimate when a workload cannot use the metadata server or Workload Identity Federation:
External applications without OIDC support. If a third-party tool needs to call GCP APIs and cannot obtain an OIDC token from a trusted identity provider, a key may be the only option.
On-premises systems in environments where federation setup is blocked. Some organisations have network or tooling constraints that make federation difficult to configure in the short term.
Migration windows. During a planned move from key-based auth to federation, keys may remain in place temporarily while the new authentication path is validated.
Local development against specific service account permissions. In some cases, a developer may need to test code running as a specific service account identity and impersonation is not available in the local environment. This is the weakest justification and should be evaluated carefully.
If you find yourself about to create a key, ask one question first: does this workload run on GCP, or can I configure Workload Identity Federation for the platform it runs on? If yes to either, you do not need a key.
When you will actually encounter service account keys
Even if keys are rarely the right choice for new infrastructure, you will encounter them in the real world. Understanding where they appear helps you recognise them when auditing, troubleshooting, or inheriting a codebase.
Legacy CI/CD pipelines. Many pipelines built before Workload Identity Federation existed use a key stored as a CI secret. GitHub Actions, CircleCI, Jenkins, and others all support this pattern. It works, but it carries ongoing key management overhead.
Terraform or IaC tooling run from local machines. Engineers who run
terraform applylocally sometimes authenticate via a key file rather than using Application Default Credentials fromgcloud auth application-default login.Third-party SaaS integrations. External tools that pull data from BigQuery, write to Cloud Storage, or call GCP APIs are sometimes configured with a service account key because the vendor does not support OIDC federation.
Data pipeline credentials. Scheduled jobs running on external servers (cron tasks, data loaders, ETL scripts) are sometimes authenticated using a key baked into the server configuration.
Documentation and tutorials. Many GCP tutorials still use
GOOGLE_APPLICATION_CREDENTIALSpointing at a key file to keep the example simple. This is fine for a tutorial but not a pattern to carry into production.
Encountering a key in existing infrastructure is not the same as endorsing the approach. If you inherit a key-based setup, treat it as technical debt worth migrating away from, not as confirmation that keys are the right tool.
Service account keys vs safer alternatives
Before choosing a key, it is worth understanding what the alternatives look like on the dimensions that matter most: whether a secret file is required, how long credentials last, and where each option works.
| Approach | Secret file required | Credential lifetime | Works outside GCP | Best for |
|---|---|---|---|---|
| Service account key | Yes — JSON key file | Until deleted (no expiry) | Yes, anywhere | Last resort for external workloads with no OIDC support |
| Attached service account (metadata server) | No | Short-lived, auto-rotated | No, GCP runtimes only | All workloads running on GCP |
| Workload Identity Federation | No | Short-lived tokens, exchanged per job | Yes, any OIDC/SAML provider | CI/CD, AWS, Azure, on-prem with OIDC |
| Service account impersonation | No | Short-lived (1 hour by default) | Requires existing GCP auth | Developers, admin scripts, testing with specific SA permissions |
The metadata server approach and Workload Identity Federation are both keyless. Neither requires storing a long-lived credential anywhere. Service account impersonation is also keyless: it generates temporary credentials on demand from an authenticated caller’s own identity.
Keys sit at the bottom of this hierarchy for a reason. They carry the highest operational overhead and the highest risk. They are the right tool only when the alternatives are genuinely unavailable.
Common mistakes
Creating a key for a workload already running on GCP. A Cloud Run service, Compute Engine VM, or Cloud Function does not need a key. Attach a service account to the resource and the metadata server handles authentication automatically. Downloading a key and embedding it in environment variables or container images adds risk with no benefit.
Storing the key file in source control. Even in a private repository, key files are at high risk. They survive in Git history after deletion, appear in CI logs, are present in forks, and are findable by automated scanning tools. The key file belongs in a secrets manager such as Secret Manager, not alongside your code.
Sharing one key across multiple workloads or environments. A key that is used by three applications cannot be rotated for one without disrupting the others. If it leaks from any of them, all three are compromised. One key per workload, one service account per workload.
Leaving keys active without any rotation or audit schedule. Keys do not expire. A key created for a project that ended two years ago is still fully valid today unless explicitly deleted. Run a regular audit of active keys using
gcloud iam service-accounts keys listand delete any that are orphaned, older than 90 days without a current documented purpose, or unused.Over-privileging the service account the key belongs to. A key leaking from a service account with
roles/editorgives an attacker near-complete access to the project. Apply least privilege to the service account before creating any key for it. Scope permissions to exactly what the workload needs, nothing more.Not monitoring key creation events. Without a Cloud Audit Logs alert on
CreateServiceAccountKey, rogue key creation in your project goes undetected. An attacker who gains temporary project access will often create a persistent key as their first move. An alert gives you a fighting chance to catch it.Creating a new key after a compromise instead of migrating away. After a key leaks, the instinct is to delete the bad key and create a fresh one. That recreates the same risk immediately. Use the incident as a forcing function to migrate to Workload Identity Federation or an attached service account instead.
Risks and security implications
Google’s own security guidance recommends avoiding service account keys entirely where possible. They are classified as long-lived credentials, which carry inherently higher risk than the short-lived tokens used by the metadata server or Workload Identity Federation.
Service account keys are treated as high-risk credentials in GCP security guidance. The core reasons are structural, not incidental:
Portable. Unlike credentials from the metadata server (which only work from the specific resource they are bound to), a key file works from anywhere: a developer laptop, a server in a different cloud, an attacker’s machine.
No built-in expiry. A key does not rotate itself. It does not expire after 24 hours. It is valid indefinitely unless you explicitly delete it. Most organisations have old keys they have forgotten about.
Silent to copy. A key is a text file. Copying it leaves no trace. Once a key exists in more than one location, you have no way to know how many copies exist or whether any unauthorised party has seen them.
Easy to leak accidentally. Developers commit key files to repos, paste them into Slack, embed them in Docker images, or print them in CI logs. Each of these paths has caused real cloud security incidents.
For a detailed look at the specific attack patterns and incident mechanics, see Why Service Account Keys Are Dangerous. That page covers the four structural properties that make keys uniquely risky and the most common real-world leak paths.
How to manage keys safely if you cannot avoid them
If you have evaluated the alternatives and a key is genuinely necessary, treat it with the same rigour you would apply to a production database password. That means:
Apply least privilege to the service account first. Scope IAM roles to exactly what the workload needs. A key with
roles/storage.objectVieweron one bucket is far less dangerous than a key withroles/editoron the whole project.One key per workload. Never share a key across multiple applications or environments. This allows individual rotation and limits blast radius if a key leaks.
Store keys in a secrets manager. Use Secret Manager or an equivalent vault (HashiCorp Vault, AWS Secrets Manager if you are in a multi-cloud setup). Never store key files directly on disk, in code, or in environment variables that could appear in logs.
Rotate keys on a schedule. Establish a maximum key age (90 days is a common target) and rotate before that deadline. Rotation means creating a new key, updating all consumers to use it, then deleting the old one.
Delete keys that are no longer in use. An unused key is pure risk. Audit regularly and delete anything without a current documented active consumer.
Monitor key creation and usage. Set up log-based alerts in Cloud Audit Logs for
google.iam.admin.v1.CreateServiceAccountKeyevents. Any unexpected key creation in a production project warrants immediate investigation.Restrict key creation with Organisation Policy. In projects where all workloads use metadata-based or federation-based auth, enforce the
iam.disableServiceAccountKeyCreationconstraint. This blocks key creation at the API level and prevents accidental or unauthorised key creation.Document every key. Record who owns each key, what it is used for, and when it was last reviewed. Without documentation, keys accumulate silently and become impossible to audit meaningfully.
How to create, list, and delete keys
The following commands cover the most common key management operations. Each service account can have up to 10 user-managed keys active at once.
Create a key and download it
This command creates a new key and writes the JSON file to your local machine. The file is downloadable only once. Google does not retain a copy of the private key after this point. Store it immediately in a secrets manager.
gcloud iam service-accounts keys create key.json \
--iam-account=ci-deployer@my-app-prod.iam.gserviceaccount.com \
--project=my-app-prodList all active keys for a service account
Use this to audit which keys exist and how old they are. The output shows
the key ID, creation time, and key type. Look for USER_MANAGED
keys: those are the ones you created and are responsible for.
gcloud iam service-accounts keys list \
--iam-account=ci-deployer@my-app-prod.iam.gserviceaccount.com \
--project=my-app-prodDelete a key by its ID
Use the key ID from the list output. Deleting a key revokes it immediately. Any system still using it will start getting authentication errors. Confirm that all consumers have switched to a new key before deleting.
gcloud iam service-accounts keys delete KEY_ID \
--iam-account=ci-deployer@my-app-prod.iam.gserviceaccount.com \
--project=my-app-prodFind old keys across a project
This pattern queries audit logs to find all key creation events in a project, which is useful when auditing an unfamiliar environment.
gcloud logging read \
'protoPayload.methodName="google.iam.admin.v1.CreateServiceAccountKey"' \
--project=my-app-prod \
--limit=50 \
--format='table(timestamp,protoPayload.authenticationInfo.principalEmail,protoPayload.request.name)'GCP also creates SYSTEM_MANAGED keys for internal use. These
appear in key listings but rotate automatically on a short cycle. You
cannot download or delete them. Only USER_MANAGED keys are
ones you created and are responsible for managing.
If you hit authentication errors after creating or rotating a key, the troubleshooting authentication errors guide covers the most common failure patterns and how to diagnose them.
Quick decision guide
Use this framework when deciding whether to create a service account key:
Workload runs on GCP (VM, Cloud Run, Cloud Functions, GKE, etc.) — Attach a service account to the resource. Use the metadata server. No key needed.
External CI/CD platform that supports OIDC (GitHub Actions, GitLab, CircleCI, etc.) — Use Workload Identity Federation. No key needed.
Developer running commands locally or testing with a specific service account — Use
gcloud auth application-default loginfor your own identity, or service account impersonation if SA-level credentials are specifically required. No key needed.External workload with no OIDC support and no path to federation — A key may be unavoidable. Apply all the safe management practices in the section above before creating one. Document the justification.
Summary
- A service account key is a JSON file with an RSA private key that authenticates as a service account from anywhere, with no expiry
- The
private_keyfield is the sensitive part — the rest of the file is supporting metadata - Access is determined by IAM roles on the service account, not by anything in the key file itself
- Most GCP workloads do not need keys — the metadata server provides credentials automatically on all GCP compute platforms
- For external workloads with OIDC support, Workload Identity Federation is the recommended keyless alternative
- If a key is unavoidable: one key per workload, store in Secret Manager, rotate on a schedule, delete when unused, monitor creation events
- Use
iam.disableServiceAccountKeyCreationOrganisation Policy to block key creation in production projects - After a key compromise, delete immediately and migrate to keyless auth — do not create a replacement key
Frequently asked questions
What is a service account key in GCP?
A service account key is a JSON file containing an RSA private key that lets any holder authenticate as the service account it belongs to, from any machine, anywhere in the world. The key has no built-in expiry and remains valid until explicitly deleted. It includes the private key, service account email, project ID, and token endpoint metadata.
Do Cloud Run or Compute Engine need service account keys?
No. Workloads running on GCP — including Compute Engine VMs, Cloud Run services, Cloud Functions, and GKE pods — access their attached service account automatically through the metadata server. No key file download is needed. Service account keys are only necessary for workloads running outside GCP that cannot use Workload Identity Federation.
Are service account keys the same as service accounts?
No. A service account is an identity — it has an email address, IAM roles, and permissions, but on its own it cannot do anything from an external machine. A service account key is a credential file that proves you are that identity. The key is the sensitive part. The service account itself is just a record in IAM.
How do I revoke a compromised service account key?
Delete the key immediately using the Console (IAM and Admin > Service Accounts > Keys tab > Delete) or via gcloud: gcloud iam service-accounts keys delete KEY_ID --iam-account=SA_EMAIL. Speed matters more than avoiding disruption. After deleting, check Cloud Audit Logs for API calls made by that identity since the suspected leak time, review IAM roles to assess blast radius, and migrate to Workload Identity Federation instead of creating a replacement key.
What should I use instead of service account keys?
For workloads on GCP: attach a service account directly to your compute resource and the metadata server handles authentication automatically. For external CI/CD pipelines such as GitHub Actions or GitLab: use Workload Identity Federation to exchange short-lived OIDC tokens for temporary GCP credentials. For developers: use gcloud auth application-default login for your own identity, or service account impersonation if service-account-level access is specifically needed.