Create a Custom GCP Service Account Key with an Expiry Date
Introduction
Managing service account (SA) keys effectively is a critical foundational step for maintaining rigorous security perimeters within Google Cloud Platform (GCP). Unlike user identities, service accounts are non-human entities meant for programmatic access. When you download a JSON key for a service account, you are inherently taking a massive security risk: that static key never expires by default unless manually deleted.
One extremely effective way to immediately mature your cloud security posture is by deliberately generating custom keys with hardcoded, predefined expiration dates. This straightforward cryptographic practice drastically reduces the likelihood of stale, forgotten credentials being systematically leaked and misused by bad actors in the wild.
The Challenge: The Threat of Stale Credentials
GCP Console allows you to easily click "Create New Key," delivering a JSON file valid indefinitely. Over months, engineers download these keys to test local scripts, configure third-party CI/CD tools, or share them via insecure channels. When an employee leaves or a project concludes, these orphaned keys remain active, essentially serving as immortal backdoor passes into your cloud environment.
Common Pitfall: Hardcoding indefinite service account keys into application source code or Docker containers. If the source repository is compromised, the attacker instantly gains untethered access to your GCP infrastructure.
[Insert Image: Threat modeling diagram showing how a leaked JSON key from a developer's laptop can be used to exfiltrate data from a GCP project.]
The Solution/Process: Automated Custom Key Expiry
In this technical guide, we'll walk through precisely how to create a custom GCP service account key with an embedded expiration date using a remarkably simple and elegant Bash script. This automated process involves cleanly generating a local RSA key pair utilizing OpenSSL and securely configuring the service account key via the GCP API for safe, time-limited use.
Prerequisites
Before executing the script, rigorously ensure the following dependencies are met:
- You have an authenticated version of the Google Cloud SDK (gcloud) configured locally.
- You possess elevated IAM permissions (
roles/iam.serviceAccountKeyAdmin) forcing key uploads for the target SA. - The `openssl` and `jq` command-line utilities are installed.
Script Breakdown
1. Generate RSA Key Pair
Using the battle-tested openssl utility, the script dynamically generates a fresh RSA key pair locally. The critical -days flag mathematically defines the certificate's rigid expiration period (e.g., 90 days).
openssl req -x509 -nodes -newkey rsa:2048 -days "90" \
-keyout ./private_key.pem \
-out ./public_key.pem \
-subj "/CN=unused"
2. Upload the Public Key to the Service Account
The safe public key is transmitted and uploaded via the API to the target service account utilizing the gcloud iam service-accounts keys upload command. GCP accepts the public key and trusts the expiration date embedded within the certificate.
OUTPUT=$(gcloud iam service-accounts keys upload ./public_key.pem \
--iam-account="${SA_NAME}@${PROJECT_ID}.iam.gserviceaccount.com" \
--project=${PROJECT_ID} 2>&1)
Pro-Tip: Always delete the raw private_key.pem file from your local disk space immediately after formulating the final JSON structure.
3. Formulate the JSON Key File
The final, usable credential payload is safely constructed and saved in the standard Google JSON format utilizing jq. The sensitive private key and metadata are securely templated.
jq -n \
--arg PRIVATE_KEY "$(cat ./private_key.pem)" \
--arg PROJECT_ID "$PROJECT_ID" \
--arg CLIENT_EMAIL "${SA_NAME}@${PROJECT_ID}.iam.gserviceaccount.com" \
--arg UNIQUE_ID "$UNIQUE_ID" \
--arg KEY_ID "$KEY_ID" \
'{
"type": "service_account",
"project_id": $PROJECT_ID,
"private_key_id": $KEY_ID,
"private_key": $PRIVATE_KEY,
"client_email": $CLIENT_EMAIL,
"client_id": $UNIQUE_ID,
"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/\($CLIENT_EMAIL)",
"universe_domain": "googleapis.com"
}' > private-key.json
[Insert Image: Diagram illustrating the flow: OpenSSL generating the keypair `->` gcloud uploading the public key `->` jq assembling the final private JSON key combining GCP metadata.]
Key Takeaways
- Standard JSON service account keys downloaded from the GCP Console never expire, presenting a massive security vulnerability.
- Forcing keys to expire natively via OpenSSL ensures compromised credentials are automatically rendered useless after a short set period.
- Automating key rotation via scripts perfectly aligns with strict organizational InfoSec policies and compliance frameworks (like SOC2).
Conclusion
By fully automating the reliable creation of service account keys and structurally embedding expiration dates via x509 certificates, infrastructure teams can decisively close one of the most common cloud security gaps. This agile scripting approach ensures that leaked or stale credentials literally cannot linger indefinitely. You can trivially parameterize this script to plug straight into your bespoke CI/CD pipelines to automatically bootstrap time-limited developer environments safely.