Create GCP API Keys

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

API keys belong to GCP projects. Service account binding requires an existing service account. The examples are intentionally small. Combine them with your own project configuration and IAM policies.

Create an unrestricted API key

Development workflows often start with an unrestricted key to verify service connectivity before applying production 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",
});
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 a unique identifier within the project (lowercase, RFC-1034 compliant). The displayName provides a human-readable label. Without restrictions, the key works with any Google API from any source.

Restrict API key to browser referrers

Web applications need to protect API keys while allowing legitimate browser requests from known domains.

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 browserKeyRestrictions property limits usage to requests with matching HTTP referrer headers. The allowedReferrers array accepts regex patterns; .* allows all referrers. The apiTargets array restricts which services and methods the key can access. Here, only GET methods on the Translation API are permitted.

Restrict API key to Android applications

Mobile applications embed API keys in client code, requiring package name and certificate fingerprint validation.

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 property validates both the app’s package name and its SHA-1 signing certificate fingerprint. This prevents unauthorized apps from using the key even if they obtain it from decompiled code. The apiTargets array further restricts which services the key can access.

Restrict API key to iOS applications

iOS applications require bundle ID validation to ensure only authorized apps can use the embedded key.

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 property validates the app’s bundle identifier. The allowedBundleIds array lists permitted bundle IDs. Combined with apiTargets, this ensures only your iOS app can access specific Google services.

Restrict API key to server IP addresses

Backend services running on known infrastructure can restrict key usage to specific IP addresses.

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 property limits requests to specific source IPs. The allowedIps array accepts individual addresses or CIDR ranges. This prevents key misuse if it’s exposed in logs or configuration files.

Bind API key to a service account

Service account binding creates authentication-enabled keys that inherit the service account’s IAM permissions and audit trail.

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, enabling authentication and IAM-based authorization. This creates an auth-enabled key that appears in audit logs with the service account’s identity. The key inherits the service account’s permissions rather than relying solely on API key restrictions.

Beyond these examples

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

The examples may reference pre-existing infrastructure such as GCP organizations (for service account example) and billing accounts (for project creation). They focus on configuring the key rather than provisioning surrounding infrastructure.

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

  • Key rotation and lifecycle management
  • Multiple API target configurations
  • Combining restriction types
  • Project-level key quotas and limits

These omissions are intentional: the goal is to illustrate how each API key feature is wired, not provide drop-in security 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, match the regex [a-z]([a-z0-9-]{0,61}[a-z0-9])? (RFC-1034 compliant), have a maximum of 63 characters, and be unique within the project. This property is immutable after creation.
What properties can't be changed after creation?
Three properties are immutable: name, project, and serviceAccountEmail. Choose these values carefully during initial creation.
Restrictions & Security
What types of restrictions can I apply to an API key?

You can apply four platform-specific restrictions:

  1. Android - androidKeyRestrictions with package names and SHA1 fingerprints
  2. iOS - iosKeyRestrictions with allowed bundle IDs
  3. Browser - browserKeyRestrictions with allowed referrers
  4. Server - serverKeyRestrictions with allowed IP addresses
How do I restrict an API key to specific Google APIs?
Configure apiTargets within restrictions with the service name and allowed methods. For example, service: "translate.googleapis.com" with methods: ["GET*"] restricts the key to GET requests on the Translate API.
Can I create an API key without any restrictions?
Yes, you can create a key with only name and displayName properties, as shown in the minimal_key example. However, applying restrictions is recommended for security.
How do I create a service account bound API key?
Set serviceAccountEmail to the email address of a service account. This creates an auth-enabled key bound to that service account. Note that this property is immutable after creation.
Key Access & Usage
How do I retrieve the actual API key string?
The keyString output property contains the encrypted and signed key value, but it can only be accessed through the GetKeyString method, not directly from the resource output.

Using a different cloud?

Explore security guides for other cloud providers: