GCP secrets store Google Cloud service account credentials, enabling your workloads to authenticate with Google Cloud services or pull images from Google Artifact Registry.
Use Cases
Artifact Registry : Pull container images from Google Artifact Registry
Cloud Storage : Access files in Google Cloud Storage buckets
BigQuery : Query data from BigQuery datasets
Pub/Sub : Publish and subscribe to Pub/Sub topics
Any GCP Service : Authenticate with any Google Cloud API
For Google Artifact Registry, you can also use a Docker secret with base64-encoded service account credentials. The GCP secret type is recommended for direct GCP API access.
Configuration Options
The GCP secret stores a complete service account JSON key file:
Field Description typeAlways service_account project_idYour GCP project ID private_key_idUnique identifier for the private key private_keyRSA private key in PEM format client_emailService account email address client_idNumeric client ID auth_uriOAuth2 authorization endpoint token_uriOAuth2 token endpoint
Create a GCP Secret
Console UI
CLI
Terraform
Pulumi
Navigate to Secrets
In the Console, navigate to Secrets and click New , or use the Create dropdown in the top-right corner and select Secret .
Enter basic information
Enter a Name and optional Description .
Select secret type
Select GCP as the secret type.
Configure credentials
Click Data in the left pane. Drag and drop your service account JSON file, or click to import.
Create the secret
Click Create .
Download your service account key from the Google Cloud Console, then create the secret: cpln secret create-gcp \
--name gcp-service-account \
--file service-account.json \
--org my-org
Generate service account keys from the Google Cloud Console under IAM & Admin > Service Accounts > Keys . resource "cpln_secret" "gcp" {
name = "gcp-service-account"
description = "GCP service account for Cloud Storage access"
gcp = jsonencode ({
type = "service_account"
project_id = "my-project-123"
private_key_id = "abc123def456"
private_key = "-----BEGIN PRIVATE KEY----- \n ... \n -----END PRIVATE KEY----- \n "
client_email = "[email protected] "
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/my-service-account%40my-project-123.iam.gserviceaccount.com"
})
}
This example uses placeholder credentials for testing. In production, use file("service-account.json") or Terraform variables.
import * as cpln from "@pulumiverse/cpln" ;
const gcpSecret = new cpln . Secret ( "gcp-service-account" , {
name: "gcp-service-account" ,
description: "GCP service account credentials" ,
gcp: JSON . stringify ({
type: "service_account" ,
project_id: "my-project-123" ,
private_key_id: "abc123def456" ,
private_key: "-----BEGIN PRIVATE KEY----- \n ... \n -----END PRIVATE KEY----- \n " ,
client_email: "[email protected] " ,
client_id: "123456789012345678901" ,
auth_uri: "https://accounts.google.com/o/oauth2/auth" ,
token_uri: "https://oauth2.googleapis.com/token" ,
}),
});
import json
import pulumiverse_cpln as cpln
gcp_secret = cpln.Secret( "gcp-service-account" ,
name = "gcp-service-account" ,
description = "GCP service account credentials" ,
gcp = json.dumps({
"type" : "service_account" ,
"project_id" : "my-project-123" ,
"private_key_id" : "abc123def456" ,
"private_key" : "-----BEGIN PRIVATE KEY----- \n ... \n -----END PRIVATE KEY----- \n " ,
"client_email" : "[email protected] " ,
"client_id" : "123456789012345678901" ,
"auth_uri" : "https://accounts.google.com/o/oauth2/auth" ,
"token_uri" : "https://oauth2.googleapis.com/token" ,
}))
package main
import (
" encoding/json "
" github.com/pulumi/pulumi/sdk/v3/go/pulumi "
" github.com/pulumiverse/pulumi-cpln/sdk/go/cpln "
)
func main () {
pulumi . Run ( func ( ctx * pulumi . Context ) error {
gcpConfig , _ := json . Marshal ( map [ string ] string {
"type" : "service_account" ,
"project_id" : "my-project-123" ,
"private_key_id" : "abc123def456" ,
"private_key" : "-----BEGIN PRIVATE KEY----- \n ... \n -----END PRIVATE KEY----- \n " ,
"client_email" : "[email protected] " ,
"client_id" : "123456789012345678901" ,
"auth_uri" : "https://accounts.google.com/o/oauth2/auth" ,
"token_uri" : "https://oauth2.googleapis.com/token" ,
})
_ , err := cpln . NewSecret ( ctx , "gcp-service-account" , & cpln . SecretArgs {
Name : pulumi . String ( "gcp-service-account" ),
Description : pulumi . String ( "GCP service account credentials" ),
Gcp : pulumi . String ( string ( gcpConfig )),
})
return err
})
}
using System . Text . Json ;
using Pulumi ;
using Pulumiverse . Cpln ;
using Pulumiverse . Cpln . Inputs ;
return await Deployment . RunAsync (() =>
{
var gcpConfig = JsonSerializer . Serialize ( new
{
type = "service_account" ,
project_id = "my-project-123" ,
private_key_id = "abc123def456" ,
private_key = "-----BEGIN PRIVATE KEY----- \n ... \n -----END PRIVATE KEY----- \n " ,
client_email = "[email protected] " ,
client_id = "123456789012345678901" ,
auth_uri = "https://accounts.google.com/o/oauth2/auth" ,
token_uri = "https://oauth2.googleapis.com/token" ,
});
var gcpSecret = new Secret ( "gcp-service-account" , new SecretArgs
{
Name = "gcp-service-account" ,
Description = "GCP service account credentials" ,
Gcp = gcpConfig ,
});
});
Best Practices
Use least-privilege service accounts
Create dedicated service accounts with only the IAM roles your workload needs. Avoid using default service accounts or overly permissive roles.
Set up a key rotation schedule. Delete old keys after deploying new ones to Control Plane.
Use Workload Identity where possible
For GKE deployments, consider using Workload Identity instead of service account keys.
Using for Artifact Registry
To use a GCP secret for pulling images from Artifact Registry, add it as a pull secret to your GVC:
Console UI
CLI
Terraform
Pulumi
Navigate to your GVC
Open your GVC in the Console.
Open Pull Secrets
Click Pull Secrets in the left pane.
Add the secret
Click Add and select your GCP secret.
cpln gvc update my-gvc \
--set spec.pullSecretLinks+="gcp-service-account" \
--org my-org
resource "cpln_gvc" "my_gvc" {
name = "my-gvc"
pull_secrets = [
cpln_secret . gcp . name
]
}
import * as cpln from "@pulumiverse/cpln" ;
const gvc = new cpln . Gvc ( "my-gvc" , {
name: "my-gvc" ,
pullSecrets: [ gcpSecret . name ],
});
import pulumiverse_cpln as cpln
gvc = cpln.Gvc( "my-gvc" ,
name = "my-gvc" ,
pull_secrets = [gcp_secret.name])
gvc , err := cpln . NewGvc ( ctx , "my-gvc" , & cpln . GvcArgs {
Name : pulumi . String ( "my-gvc" ),
PullSecrets : pulumi . StringArray { gcpSecret . Name },
})
var gvc = new Gvc ( "my-gvc" , new GvcArgs
{
Name = "my-gvc" ,
PullSecrets = new [] { gcpSecret . Name },
});
The service account must have the roles/artifactregistry.reader role on the Artifact Registry repository.
Next Steps