Create GCP API Keys

The gcp:projects/apiKey:ApiKey resource, part of the Pulumi GCP provider, provisions Google Cloud API keys that authenticate requests to Google APIs. This guide focuses on three capabilities: platform-specific restrictions (Android, iOS, browser, server), API service targeting, and service account binding.

API keys authenticate to Google APIs within a project. Some configurations reference service accounts that must exist separately. The examples are intentionally small. Combine them with your own project structure and API enablement.

Create an unrestricted API key

Most teams start with an unrestricted key during development to verify API connectivity.

import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";

const primary = new gcp.projects.ApiKey("primary", {
    name: "key",
    displayName: "sample-key",
});
import pulumi
import pulumi_gcp as gcp

primary = gcp.projects.ApiKey("primary",
    name="key",
    display_name="sample-key")
package main

import (
	"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/projects"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := projects.NewApiKey(ctx, "primary", &projects.ApiKeyArgs{
			Name:        pulumi.String("key"),
			DisplayName: pulumi.String("sample-key"),
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Gcp = Pulumi.Gcp;

return await Deployment.RunAsync(() => 
{
    var primary = new Gcp.Projects.ApiKey("primary", new()
    {
        Name = "key",
        DisplayName = "sample-key",
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.projects.ApiKey;
import com.pulumi.gcp.projects.ApiKeyArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        var primary = new ApiKey("primary", ApiKeyArgs.builder()
            .name("key")
            .displayName("sample-key")
            .build());

    }
}
resources:
  primary:
    type: gcp:projects:ApiKey
    properties:
      name: key
      displayName: sample-key

The name property sets the resource identifier (must be unique, lowercase, RFC-1034 compliant). The displayName provides a human-readable label. Without restrictions, this key works from any platform and can access any enabled API in the project.

Restrict keys to specific APIs and referrers

Web applications limit which APIs a key can access and which domains can use it.

import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";

const primary = new gcp.projects.ApiKey("primary", {
    name: "key",
    displayName: "sample-key",
    restrictions: {
        apiTargets: [{
            service: "translate.googleapis.com",
            methods: ["GET*"],
        }],
        browserKeyRestrictions: {
            allowedReferrers: [".*"],
        },
    },
});
import pulumi
import pulumi_gcp as gcp

primary = gcp.projects.ApiKey("primary",
    name="key",
    display_name="sample-key",
    restrictions={
        "api_targets": [{
            "service": "translate.googleapis.com",
            "methods": ["GET*"],
        }],
        "browser_key_restrictions": {
            "allowed_referrers": [".*"],
        },
    })
package main

import (
	"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/projects"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := projects.NewApiKey(ctx, "primary", &projects.ApiKeyArgs{
			Name:        pulumi.String("key"),
			DisplayName: pulumi.String("sample-key"),
			Restrictions: &projects.ApiKeyRestrictionsArgs{
				ApiTargets: projects.ApiKeyRestrictionsApiTargetArray{
					&projects.ApiKeyRestrictionsApiTargetArgs{
						Service: pulumi.String("translate.googleapis.com"),
						Methods: pulumi.StringArray{
							pulumi.String("GET*"),
						},
					},
				},
				BrowserKeyRestrictions: &projects.ApiKeyRestrictionsBrowserKeyRestrictionsArgs{
					AllowedReferrers: pulumi.StringArray{
						pulumi.String(".*"),
					},
				},
			},
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Gcp = Pulumi.Gcp;

return await Deployment.RunAsync(() => 
{
    var primary = new Gcp.Projects.ApiKey("primary", new()
    {
        Name = "key",
        DisplayName = "sample-key",
        Restrictions = new Gcp.Projects.Inputs.ApiKeyRestrictionsArgs
        {
            ApiTargets = new[]
            {
                new Gcp.Projects.Inputs.ApiKeyRestrictionsApiTargetArgs
                {
                    Service = "translate.googleapis.com",
                    Methods = new[]
                    {
                        "GET*",
                    },
                },
            },
            BrowserKeyRestrictions = new Gcp.Projects.Inputs.ApiKeyRestrictionsBrowserKeyRestrictionsArgs
            {
                AllowedReferrers = new[]
                {
                    ".*",
                },
            },
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.projects.ApiKey;
import com.pulumi.gcp.projects.ApiKeyArgs;
import com.pulumi.gcp.projects.inputs.ApiKeyRestrictionsArgs;
import com.pulumi.gcp.projects.inputs.ApiKeyRestrictionsBrowserKeyRestrictionsArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        var primary = new ApiKey("primary", ApiKeyArgs.builder()
            .name("key")
            .displayName("sample-key")
            .restrictions(ApiKeyRestrictionsArgs.builder()
                .apiTargets(ApiKeyRestrictionsApiTargetArgs.builder()
                    .service("translate.googleapis.com")
                    .methods("GET*")
                    .build())
                .browserKeyRestrictions(ApiKeyRestrictionsBrowserKeyRestrictionsArgs.builder()
                    .allowedReferrers(".*")
                    .build())
                .build())
            .build());

    }
}
resources:
  primary:
    type: gcp:projects:ApiKey
    properties:
      name: key
      displayName: sample-key
      restrictions:
        apiTargets:
          - service: translate.googleapis.com
            methods:
              - GET*
        browserKeyRestrictions:
          allowedReferrers:
            - .*

The restrictions block controls key usage. The apiTargets array specifies which services the key can call; here, only translate.googleapis.com with GET methods. The browserKeyRestrictions block limits usage to requests from allowed referrer domains. The pattern “.” allows all referrers; replace with specific domains like “https://example.com/” for production.

Restrict keys to Android applications

Mobile apps distributed through app stores bind keys to specific package names and signing certificates.

import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";

const primary = new gcp.projects.ApiKey("primary", {
    name: "key",
    displayName: "sample-key",
    restrictions: {
        androidKeyRestrictions: {
            allowedApplications: [{
                packageName: "com.example.app123",
                sha1Fingerprint: "1699466a142d4682a5f91b50fdf400f2358e2b0b",
            }],
        },
        apiTargets: [{
            service: "translate.googleapis.com",
            methods: ["GET*"],
        }],
    },
});
import pulumi
import pulumi_gcp as gcp

primary = gcp.projects.ApiKey("primary",
    name="key",
    display_name="sample-key",
    restrictions={
        "android_key_restrictions": {
            "allowed_applications": [{
                "package_name": "com.example.app123",
                "sha1_fingerprint": "1699466a142d4682a5f91b50fdf400f2358e2b0b",
            }],
        },
        "api_targets": [{
            "service": "translate.googleapis.com",
            "methods": ["GET*"],
        }],
    })
package main

import (
	"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/projects"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := projects.NewApiKey(ctx, "primary", &projects.ApiKeyArgs{
			Name:        pulumi.String("key"),
			DisplayName: pulumi.String("sample-key"),
			Restrictions: &projects.ApiKeyRestrictionsArgs{
				AndroidKeyRestrictions: &projects.ApiKeyRestrictionsAndroidKeyRestrictionsArgs{
					AllowedApplications: projects.ApiKeyRestrictionsAndroidKeyRestrictionsAllowedApplicationArray{
						&projects.ApiKeyRestrictionsAndroidKeyRestrictionsAllowedApplicationArgs{
							PackageName:     pulumi.String("com.example.app123"),
							Sha1Fingerprint: pulumi.String("1699466a142d4682a5f91b50fdf400f2358e2b0b"),
						},
					},
				},
				ApiTargets: projects.ApiKeyRestrictionsApiTargetArray{
					&projects.ApiKeyRestrictionsApiTargetArgs{
						Service: pulumi.String("translate.googleapis.com"),
						Methods: pulumi.StringArray{
							pulumi.String("GET*"),
						},
					},
				},
			},
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Gcp = Pulumi.Gcp;

return await Deployment.RunAsync(() => 
{
    var primary = new Gcp.Projects.ApiKey("primary", new()
    {
        Name = "key",
        DisplayName = "sample-key",
        Restrictions = new Gcp.Projects.Inputs.ApiKeyRestrictionsArgs
        {
            AndroidKeyRestrictions = new Gcp.Projects.Inputs.ApiKeyRestrictionsAndroidKeyRestrictionsArgs
            {
                AllowedApplications = new[]
                {
                    new Gcp.Projects.Inputs.ApiKeyRestrictionsAndroidKeyRestrictionsAllowedApplicationArgs
                    {
                        PackageName = "com.example.app123",
                        Sha1Fingerprint = "1699466a142d4682a5f91b50fdf400f2358e2b0b",
                    },
                },
            },
            ApiTargets = new[]
            {
                new Gcp.Projects.Inputs.ApiKeyRestrictionsApiTargetArgs
                {
                    Service = "translate.googleapis.com",
                    Methods = new[]
                    {
                        "GET*",
                    },
                },
            },
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.projects.ApiKey;
import com.pulumi.gcp.projects.ApiKeyArgs;
import com.pulumi.gcp.projects.inputs.ApiKeyRestrictionsArgs;
import com.pulumi.gcp.projects.inputs.ApiKeyRestrictionsAndroidKeyRestrictionsArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        var primary = new ApiKey("primary", ApiKeyArgs.builder()
            .name("key")
            .displayName("sample-key")
            .restrictions(ApiKeyRestrictionsArgs.builder()
                .androidKeyRestrictions(ApiKeyRestrictionsAndroidKeyRestrictionsArgs.builder()
                    .allowedApplications(ApiKeyRestrictionsAndroidKeyRestrictionsAllowedApplicationArgs.builder()
                        .packageName("com.example.app123")
                        .sha1Fingerprint("1699466a142d4682a5f91b50fdf400f2358e2b0b")
                        .build())
                    .build())
                .apiTargets(ApiKeyRestrictionsApiTargetArgs.builder()
                    .service("translate.googleapis.com")
                    .methods("GET*")
                    .build())
                .build())
            .build());

    }
}
resources:
  primary:
    type: gcp:projects:ApiKey
    properties:
      name: key
      displayName: sample-key
      restrictions:
        androidKeyRestrictions:
          allowedApplications:
            - packageName: com.example.app123
              sha1Fingerprint: 1699466a142d4682a5f91b50fdf400f2358e2b0b
        apiTargets:
          - service: translate.googleapis.com
            methods:
              - GET*

The androidKeyRestrictions block requires both packageName and sha1Fingerprint. Google Play verifies these values at runtime, ensuring the key only works when called from the specified app. The apiTargets array limits which services the key can access, even from the allowed application.

Restrict keys to iOS applications

iOS apps verify the calling application’s bundle identifier to prevent unauthorized use.

import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";

const primary = new gcp.projects.ApiKey("primary", {
    name: "key",
    displayName: "sample-key",
    restrictions: {
        apiTargets: [{
            service: "translate.googleapis.com",
            methods: ["GET*"],
        }],
        iosKeyRestrictions: {
            allowedBundleIds: ["com.google.app.macos"],
        },
    },
});
import pulumi
import pulumi_gcp as gcp

primary = gcp.projects.ApiKey("primary",
    name="key",
    display_name="sample-key",
    restrictions={
        "api_targets": [{
            "service": "translate.googleapis.com",
            "methods": ["GET*"],
        }],
        "ios_key_restrictions": {
            "allowed_bundle_ids": ["com.google.app.macos"],
        },
    })
package main

import (
	"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/projects"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := projects.NewApiKey(ctx, "primary", &projects.ApiKeyArgs{
			Name:        pulumi.String("key"),
			DisplayName: pulumi.String("sample-key"),
			Restrictions: &projects.ApiKeyRestrictionsArgs{
				ApiTargets: projects.ApiKeyRestrictionsApiTargetArray{
					&projects.ApiKeyRestrictionsApiTargetArgs{
						Service: pulumi.String("translate.googleapis.com"),
						Methods: pulumi.StringArray{
							pulumi.String("GET*"),
						},
					},
				},
				IosKeyRestrictions: &projects.ApiKeyRestrictionsIosKeyRestrictionsArgs{
					AllowedBundleIds: pulumi.StringArray{
						pulumi.String("com.google.app.macos"),
					},
				},
			},
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Gcp = Pulumi.Gcp;

return await Deployment.RunAsync(() => 
{
    var primary = new Gcp.Projects.ApiKey("primary", new()
    {
        Name = "key",
        DisplayName = "sample-key",
        Restrictions = new Gcp.Projects.Inputs.ApiKeyRestrictionsArgs
        {
            ApiTargets = new[]
            {
                new Gcp.Projects.Inputs.ApiKeyRestrictionsApiTargetArgs
                {
                    Service = "translate.googleapis.com",
                    Methods = new[]
                    {
                        "GET*",
                    },
                },
            },
            IosKeyRestrictions = new Gcp.Projects.Inputs.ApiKeyRestrictionsIosKeyRestrictionsArgs
            {
                AllowedBundleIds = new[]
                {
                    "com.google.app.macos",
                },
            },
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.projects.ApiKey;
import com.pulumi.gcp.projects.ApiKeyArgs;
import com.pulumi.gcp.projects.inputs.ApiKeyRestrictionsArgs;
import com.pulumi.gcp.projects.inputs.ApiKeyRestrictionsIosKeyRestrictionsArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        var primary = new ApiKey("primary", ApiKeyArgs.builder()
            .name("key")
            .displayName("sample-key")
            .restrictions(ApiKeyRestrictionsArgs.builder()
                .apiTargets(ApiKeyRestrictionsApiTargetArgs.builder()
                    .service("translate.googleapis.com")
                    .methods("GET*")
                    .build())
                .iosKeyRestrictions(ApiKeyRestrictionsIosKeyRestrictionsArgs.builder()
                    .allowedBundleIds("com.google.app.macos")
                    .build())
                .build())
            .build());

    }
}
resources:
  primary:
    type: gcp:projects:ApiKey
    properties:
      name: key
      displayName: sample-key
      restrictions:
        apiTargets:
          - service: translate.googleapis.com
            methods:
              - GET*
        iosKeyRestrictions:
          allowedBundleIds:
            - com.google.app.macos

The iosKeyRestrictions block accepts a list of allowedBundleIds. iOS verifies the bundle identifier at runtime. Like Android restrictions, this combines with apiTargets to control both platform identity and service access.

Restrict keys to server IP addresses

Backend services running on known infrastructure use IP-based restrictions.

import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";

const primary = new gcp.projects.ApiKey("primary", {
    name: "key",
    displayName: "sample-key",
    restrictions: {
        apiTargets: [{
            service: "translate.googleapis.com",
            methods: ["GET*"],
        }],
        serverKeyRestrictions: {
            allowedIps: ["127.0.0.1"],
        },
    },
});
import pulumi
import pulumi_gcp as gcp

primary = gcp.projects.ApiKey("primary",
    name="key",
    display_name="sample-key",
    restrictions={
        "api_targets": [{
            "service": "translate.googleapis.com",
            "methods": ["GET*"],
        }],
        "server_key_restrictions": {
            "allowed_ips": ["127.0.0.1"],
        },
    })
package main

import (
	"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/projects"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := projects.NewApiKey(ctx, "primary", &projects.ApiKeyArgs{
			Name:        pulumi.String("key"),
			DisplayName: pulumi.String("sample-key"),
			Restrictions: &projects.ApiKeyRestrictionsArgs{
				ApiTargets: projects.ApiKeyRestrictionsApiTargetArray{
					&projects.ApiKeyRestrictionsApiTargetArgs{
						Service: pulumi.String("translate.googleapis.com"),
						Methods: pulumi.StringArray{
							pulumi.String("GET*"),
						},
					},
				},
				ServerKeyRestrictions: &projects.ApiKeyRestrictionsServerKeyRestrictionsArgs{
					AllowedIps: pulumi.StringArray{
						pulumi.String("127.0.0.1"),
					},
				},
			},
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Gcp = Pulumi.Gcp;

return await Deployment.RunAsync(() => 
{
    var primary = new Gcp.Projects.ApiKey("primary", new()
    {
        Name = "key",
        DisplayName = "sample-key",
        Restrictions = new Gcp.Projects.Inputs.ApiKeyRestrictionsArgs
        {
            ApiTargets = new[]
            {
                new Gcp.Projects.Inputs.ApiKeyRestrictionsApiTargetArgs
                {
                    Service = "translate.googleapis.com",
                    Methods = new[]
                    {
                        "GET*",
                    },
                },
            },
            ServerKeyRestrictions = new Gcp.Projects.Inputs.ApiKeyRestrictionsServerKeyRestrictionsArgs
            {
                AllowedIps = new[]
                {
                    "127.0.0.1",
                },
            },
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.projects.ApiKey;
import com.pulumi.gcp.projects.ApiKeyArgs;
import com.pulumi.gcp.projects.inputs.ApiKeyRestrictionsArgs;
import com.pulumi.gcp.projects.inputs.ApiKeyRestrictionsServerKeyRestrictionsArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        var primary = new ApiKey("primary", ApiKeyArgs.builder()
            .name("key")
            .displayName("sample-key")
            .restrictions(ApiKeyRestrictionsArgs.builder()
                .apiTargets(ApiKeyRestrictionsApiTargetArgs.builder()
                    .service("translate.googleapis.com")
                    .methods("GET*")
                    .build())
                .serverKeyRestrictions(ApiKeyRestrictionsServerKeyRestrictionsArgs.builder()
                    .allowedIps("127.0.0.1")
                    .build())
                .build())
            .build());

    }
}
resources:
  primary:
    type: gcp:projects:ApiKey
    properties:
      name: key
      displayName: sample-key
      restrictions:
        apiTargets:
          - service: translate.googleapis.com
            methods:
              - GET*
        serverKeyRestrictions:
          allowedIps:
            - 127.0.0.1

The serverKeyRestrictions block limits key usage to requests originating from allowedIps. This works for servers with static IP addresses or known IP ranges. Combine with apiTargets to control both network location and service access.

Bind keys to service accounts

Applications that need both API key simplicity and service account identity can bind keys to service accounts.

import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";

const project = new gcp.organizations.Project("project", {
    projectId: "app",
    name: "app",
    orgId: "123456789",
    deletionPolicy: "DELETE",
});
const keyServiceAccount = new gcp.serviceaccount.Account("key_service_account", {
    accountId: "app",
    project: project.projectId,
    displayName: "Test Service Account",
});
const primary = new gcp.projects.ApiKey("primary", {
    name: "key",
    displayName: "sample-key",
    project: project.projectId,
    serviceAccountEmail: keyServiceAccount.email,
});
import pulumi
import pulumi_gcp as gcp

project = gcp.organizations.Project("project",
    project_id="app",
    name="app",
    org_id="123456789",
    deletion_policy="DELETE")
key_service_account = gcp.serviceaccount.Account("key_service_account",
    account_id="app",
    project=project.project_id,
    display_name="Test Service Account")
primary = gcp.projects.ApiKey("primary",
    name="key",
    display_name="sample-key",
    project=project.project_id,
    service_account_email=key_service_account.email)
package main

import (
	"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/organizations"
	"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/projects"
	"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/serviceaccount"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		project, err := organizations.NewProject(ctx, "project", &organizations.ProjectArgs{
			ProjectId:      pulumi.String("app"),
			Name:           pulumi.String("app"),
			OrgId:          pulumi.String("123456789"),
			DeletionPolicy: pulumi.String("DELETE"),
		})
		if err != nil {
			return err
		}
		keyServiceAccount, err := serviceaccount.NewAccount(ctx, "key_service_account", &serviceaccount.AccountArgs{
			AccountId:   pulumi.String("app"),
			Project:     project.ProjectId,
			DisplayName: pulumi.String("Test Service Account"),
		})
		if err != nil {
			return err
		}
		_, err = projects.NewApiKey(ctx, "primary", &projects.ApiKeyArgs{
			Name:                pulumi.String("key"),
			DisplayName:         pulumi.String("sample-key"),
			Project:             project.ProjectId,
			ServiceAccountEmail: keyServiceAccount.Email,
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Gcp = Pulumi.Gcp;

return await Deployment.RunAsync(() => 
{
    var project = new Gcp.Organizations.Project("project", new()
    {
        ProjectId = "app",
        Name = "app",
        OrgId = "123456789",
        DeletionPolicy = "DELETE",
    });

    var keyServiceAccount = new Gcp.ServiceAccount.Account("key_service_account", new()
    {
        AccountId = "app",
        Project = project.ProjectId,
        DisplayName = "Test Service Account",
    });

    var primary = new Gcp.Projects.ApiKey("primary", new()
    {
        Name = "key",
        DisplayName = "sample-key",
        Project = project.ProjectId,
        ServiceAccountEmail = keyServiceAccount.Email,
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.organizations.Project;
import com.pulumi.gcp.organizations.ProjectArgs;
import com.pulumi.gcp.serviceaccount.Account;
import com.pulumi.gcp.serviceaccount.AccountArgs;
import com.pulumi.gcp.projects.ApiKey;
import com.pulumi.gcp.projects.ApiKeyArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        var project = new Project("project", ProjectArgs.builder()
            .projectId("app")
            .name("app")
            .orgId("123456789")
            .deletionPolicy("DELETE")
            .build());

        var keyServiceAccount = new Account("keyServiceAccount", AccountArgs.builder()
            .accountId("app")
            .project(project.projectId())
            .displayName("Test Service Account")
            .build());

        var primary = new ApiKey("primary", ApiKeyArgs.builder()
            .name("key")
            .displayName("sample-key")
            .project(project.projectId())
            .serviceAccountEmail(keyServiceAccount.email())
            .build());

    }
}
resources:
  primary:
    type: gcp:projects:ApiKey
    properties:
      name: key
      displayName: sample-key
      project: ${project.projectId}
      serviceAccountEmail: ${keyServiceAccount.email}
  project:
    type: gcp:organizations:Project
    properties:
      projectId: app
      name: app
      orgId: '123456789'
      deletionPolicy: DELETE
  keyServiceAccount:
    type: gcp:serviceaccount:Account
    name: key_service_account
    properties:
      accountId: app
      project: ${project.projectId}
      displayName: Test Service Account

The serviceAccountEmail property binds the key to a service account, creating an “auth-enabled” key. This combines API key authentication with service account identity, useful when you need both the simplicity of API keys and the identity tracking of service accounts. The key inherits the service account’s IAM permissions.

Beyond these examples

These snippets focus on specific API key features: platform-specific restrictions (Android, iOS, browser, server), API service targeting and method filtering, and service account binding. They’re intentionally minimal rather than full authentication solutions.

The examples may reference pre-existing infrastructure such as GCP projects with enabled APIs, and service accounts (for binding example). They focus on configuring the key rather than provisioning the surrounding project infrastructure.

To keep things focused, common API key patterns are omitted, including:

  • Key rotation and lifecycle management
  • Quota limits per key
  • Multiple API targets with different method restrictions
  • Combining platform restrictions with service account binding

These omissions are intentional: the goal is to illustrate how each key restriction is wired, not provide drop-in authentication modules. See the API Key resource reference for all available configuration options.

Let's create GCP API Keys

Get started with Pulumi Cloud, then follow our quick setup guide to deploy this infrastructure.

Try Pulumi Cloud for FREE

Frequently Asked Questions

Key Configuration & Naming
What are the naming requirements for API keys?
The name must be lowercase letters, numbers, and hyphens only, matching the regex [a-z]([a-z0-9-]{0,61}[a-z0-9])?. It must start with a letter, end with a letter or number, conform to RFC-1034, and have a maximum length of 63 characters.
What properties can't I change after creating an API key?
The name, project, and serviceAccountEmail properties are immutable. Changes to these fields require recreating the resource.
Can I update the display name of an existing API key?
Yes, the displayName property is modifiable and can be updated after creation.
Restrictions & Security
What types of platform restrictions can I apply to an API key?

You can restrict by platform using one of these options:

  1. Android - Use androidKeyRestrictions with package names and SHA1 fingerprints
  2. iOS - Use iosKeyRestrictions with bundle IDs
  3. Browser - Use browserKeyRestrictions with allowed referrers
  4. Server - Use serverKeyRestrictions with allowed IP addresses
How do I restrict an API key to specific Google Cloud APIs?
Configure apiTargets within the restrictions property, specifying the service name (e.g., translate.googleapis.com) and allowed methods (e.g., ["GET*"]).
Can I create an API key without any restrictions?
Yes, you can create a minimal API key with just name and displayName, though applying restrictions is recommended for production use.
How do I bind an API key to a service account?
Set the serviceAccountEmail property to the service account’s email address. This creates a service account bound key with authentication enabled.
Key Access & Usage
How do I retrieve the actual API key string?
The keyString output field contains an encrypted and signed value that can only be accessed through the GetKeyString method, not directly from resource outputs.
What import formats are supported for existing API keys?
You can import using three formats: projects/{{project}}/locations/global/keys/{{name}}, {{project}}/{{name}}, or just {{name}}.

Using a different cloud?

Explore security guides for other cloud providers: