Deploy GCP Anthos Clusters on AWS

The gcp:container/awsCluster:AwsCluster resource, part of the Pulumi GCP provider, provisions an Anthos cluster control plane that runs on AWS infrastructure while being managed from Google Cloud. This guide focuses on three capabilities: control plane encryption and AWS authentication, network and RBAC configuration, and logging and instance placement.

Anthos clusters on AWS require extensive pre-existing infrastructure: AWS VPC, subnets, security groups, IAM roles, and KMS keys, plus a GCP project with the Anthos Multicloud API enabled. The examples are intentionally small. Combine them with your own AWS infrastructure and GCP Fleet configuration.

Deploy a cluster with encryption and proxy configuration

Teams running Kubernetes on AWS through GKE Multicloud provision control plane infrastructure with encryption, authentication, and network configuration spanning both clouds.

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

const versions = gcp.container.getAwsVersions({
    project: "my-project-name",
    location: "us-west1",
});
const primary = new gcp.container.AwsCluster("primary", {
    authorization: {
        adminUsers: [{
            username: "my@service-account.com",
        }],
        adminGroups: [{
            group: "group@domain.com",
        }],
    },
    awsRegion: "my-aws-region",
    controlPlane: {
        awsServicesAuthentication: {
            roleArn: "arn:aws:iam::012345678910:role/my--1p-dev-oneplatform",
            roleSessionName: "my--1p-dev-session",
        },
        configEncryption: {
            kmsKeyArn: "arn:aws:kms:my-aws-region:012345678910:key/12345678-1234-1234-1234-123456789111",
        },
        databaseEncryption: {
            kmsKeyArn: "arn:aws:kms:my-aws-region:012345678910:key/12345678-1234-1234-1234-123456789111",
        },
        iamInstanceProfile: "my--1p-dev-controlplane",
        subnetIds: ["subnet-00000000000000000"],
        version: versions.then(versions => versions.validVersions?.[0]),
        instanceType: "t3.medium",
        mainVolume: {
            iops: 3000,
            kmsKeyArn: "arn:aws:kms:my-aws-region:012345678910:key/12345678-1234-1234-1234-123456789111",
            sizeGib: 10,
            volumeType: "GP3",
        },
        proxyConfig: {
            secretArn: "arn:aws:secretsmanager:us-west-2:126285863215:secret:proxy_config20210824150329476300000001-ABCDEF",
            secretVersion: "12345678-ABCD-EFGH-IJKL-987654321098",
        },
        rootVolume: {
            iops: 3000,
            kmsKeyArn: "arn:aws:kms:my-aws-region:012345678910:key/12345678-1234-1234-1234-123456789111",
            sizeGib: 10,
            volumeType: "GP3",
        },
        securityGroupIds: ["sg-00000000000000000"],
        sshConfig: {
            ec2KeyPair: "my--1p-dev-ssh",
        },
        tags: {
            owner: "my@service-account.com",
        },
    },
    fleet: {
        project: "my-project-number",
    },
    location: "us-west1",
    name: "name",
    networking: {
        podAddressCidrBlocks: ["10.2.0.0/16"],
        serviceAddressCidrBlocks: ["10.1.0.0/16"],
        vpcId: "vpc-00000000000000000",
    },
    annotations: {
        "label-one": "value-one",
    },
    description: "A sample aws cluster",
    project: "my-project-name",
});
import pulumi
import pulumi_gcp as gcp

versions = gcp.container.get_aws_versions(project="my-project-name",
    location="us-west1")
primary = gcp.container.AwsCluster("primary",
    authorization={
        "admin_users": [{
            "username": "my@service-account.com",
        }],
        "admin_groups": [{
            "group": "group@domain.com",
        }],
    },
    aws_region="my-aws-region",
    control_plane={
        "aws_services_authentication": {
            "role_arn": "arn:aws:iam::012345678910:role/my--1p-dev-oneplatform",
            "role_session_name": "my--1p-dev-session",
        },
        "config_encryption": {
            "kms_key_arn": "arn:aws:kms:my-aws-region:012345678910:key/12345678-1234-1234-1234-123456789111",
        },
        "database_encryption": {
            "kms_key_arn": "arn:aws:kms:my-aws-region:012345678910:key/12345678-1234-1234-1234-123456789111",
        },
        "iam_instance_profile": "my--1p-dev-controlplane",
        "subnet_ids": ["subnet-00000000000000000"],
        "version": versions.valid_versions[0],
        "instance_type": "t3.medium",
        "main_volume": {
            "iops": 3000,
            "kms_key_arn": "arn:aws:kms:my-aws-region:012345678910:key/12345678-1234-1234-1234-123456789111",
            "size_gib": 10,
            "volume_type": "GP3",
        },
        "proxy_config": {
            "secret_arn": "arn:aws:secretsmanager:us-west-2:126285863215:secret:proxy_config20210824150329476300000001-ABCDEF",
            "secret_version": "12345678-ABCD-EFGH-IJKL-987654321098",
        },
        "root_volume": {
            "iops": 3000,
            "kms_key_arn": "arn:aws:kms:my-aws-region:012345678910:key/12345678-1234-1234-1234-123456789111",
            "size_gib": 10,
            "volume_type": "GP3",
        },
        "security_group_ids": ["sg-00000000000000000"],
        "ssh_config": {
            "ec2_key_pair": "my--1p-dev-ssh",
        },
        "tags": {
            "owner": "my@service-account.com",
        },
    },
    fleet={
        "project": "my-project-number",
    },
    location="us-west1",
    name="name",
    networking={
        "pod_address_cidr_blocks": ["10.2.0.0/16"],
        "service_address_cidr_blocks": ["10.1.0.0/16"],
        "vpc_id": "vpc-00000000000000000",
    },
    annotations={
        "label-one": "value-one",
    },
    description="A sample aws cluster",
    project="my-project-name")
package main

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

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		versions, err := container.GetAwsVersions(ctx, &container.GetAwsVersionsArgs{
			Project:  pulumi.StringRef("my-project-name"),
			Location: pulumi.StringRef("us-west1"),
		}, nil)
		if err != nil {
			return err
		}
		_, err = container.NewAwsCluster(ctx, "primary", &container.AwsClusterArgs{
			Authorization: &container.AwsClusterAuthorizationArgs{
				AdminUsers: container.AwsClusterAuthorizationAdminUserArray{
					&container.AwsClusterAuthorizationAdminUserArgs{
						Username: pulumi.String("my@service-account.com"),
					},
				},
				AdminGroups: container.AwsClusterAuthorizationAdminGroupArray{
					&container.AwsClusterAuthorizationAdminGroupArgs{
						Group: pulumi.String("group@domain.com"),
					},
				},
			},
			AwsRegion: pulumi.String("my-aws-region"),
			ControlPlane: &container.AwsClusterControlPlaneArgs{
				AwsServicesAuthentication: &container.AwsClusterControlPlaneAwsServicesAuthenticationArgs{
					RoleArn:         pulumi.String("arn:aws:iam::012345678910:role/my--1p-dev-oneplatform"),
					RoleSessionName: pulumi.String("my--1p-dev-session"),
				},
				ConfigEncryption: &container.AwsClusterControlPlaneConfigEncryptionArgs{
					KmsKeyArn: pulumi.String("arn:aws:kms:my-aws-region:012345678910:key/12345678-1234-1234-1234-123456789111"),
				},
				DatabaseEncryption: &container.AwsClusterControlPlaneDatabaseEncryptionArgs{
					KmsKeyArn: pulumi.String("arn:aws:kms:my-aws-region:012345678910:key/12345678-1234-1234-1234-123456789111"),
				},
				IamInstanceProfile: pulumi.String("my--1p-dev-controlplane"),
				SubnetIds: pulumi.StringArray{
					pulumi.String("subnet-00000000000000000"),
				},
				Version:      pulumi.String(versions.ValidVersions[0]),
				InstanceType: pulumi.String("t3.medium"),
				MainVolume: &container.AwsClusterControlPlaneMainVolumeArgs{
					Iops:       pulumi.Int(3000),
					KmsKeyArn:  pulumi.String("arn:aws:kms:my-aws-region:012345678910:key/12345678-1234-1234-1234-123456789111"),
					SizeGib:    pulumi.Int(10),
					VolumeType: pulumi.String("GP3"),
				},
				ProxyConfig: &container.AwsClusterControlPlaneProxyConfigArgs{
					SecretArn:     pulumi.String("arn:aws:secretsmanager:us-west-2:126285863215:secret:proxy_config20210824150329476300000001-ABCDEF"),
					SecretVersion: pulumi.String("12345678-ABCD-EFGH-IJKL-987654321098"),
				},
				RootVolume: &container.AwsClusterControlPlaneRootVolumeArgs{
					Iops:       pulumi.Int(3000),
					KmsKeyArn:  pulumi.String("arn:aws:kms:my-aws-region:012345678910:key/12345678-1234-1234-1234-123456789111"),
					SizeGib:    pulumi.Int(10),
					VolumeType: pulumi.String("GP3"),
				},
				SecurityGroupIds: pulumi.StringArray{
					pulumi.String("sg-00000000000000000"),
				},
				SshConfig: &container.AwsClusterControlPlaneSshConfigArgs{
					Ec2KeyPair: pulumi.String("my--1p-dev-ssh"),
				},
				Tags: pulumi.StringMap{
					"owner": pulumi.String("my@service-account.com"),
				},
			},
			Fleet: &container.AwsClusterFleetArgs{
				Project: pulumi.String("my-project-number"),
			},
			Location: pulumi.String("us-west1"),
			Name:     pulumi.String("name"),
			Networking: &container.AwsClusterNetworkingArgs{
				PodAddressCidrBlocks: pulumi.StringArray{
					pulumi.String("10.2.0.0/16"),
				},
				ServiceAddressCidrBlocks: pulumi.StringArray{
					pulumi.String("10.1.0.0/16"),
				},
				VpcId: pulumi.String("vpc-00000000000000000"),
			},
			Annotations: pulumi.StringMap{
				"label-one": pulumi.String("value-one"),
			},
			Description: pulumi.String("A sample aws cluster"),
			Project:     pulumi.String("my-project-name"),
		})
		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 versions = Gcp.Container.GetAwsVersions.Invoke(new()
    {
        Project = "my-project-name",
        Location = "us-west1",
    });

    var primary = new Gcp.Container.AwsCluster("primary", new()
    {
        Authorization = new Gcp.Container.Inputs.AwsClusterAuthorizationArgs
        {
            AdminUsers = new[]
            {
                new Gcp.Container.Inputs.AwsClusterAuthorizationAdminUserArgs
                {
                    Username = "my@service-account.com",
                },
            },
            AdminGroups = new[]
            {
                new Gcp.Container.Inputs.AwsClusterAuthorizationAdminGroupArgs
                {
                    Group = "group@domain.com",
                },
            },
        },
        AwsRegion = "my-aws-region",
        ControlPlane = new Gcp.Container.Inputs.AwsClusterControlPlaneArgs
        {
            AwsServicesAuthentication = new Gcp.Container.Inputs.AwsClusterControlPlaneAwsServicesAuthenticationArgs
            {
                RoleArn = "arn:aws:iam::012345678910:role/my--1p-dev-oneplatform",
                RoleSessionName = "my--1p-dev-session",
            },
            ConfigEncryption = new Gcp.Container.Inputs.AwsClusterControlPlaneConfigEncryptionArgs
            {
                KmsKeyArn = "arn:aws:kms:my-aws-region:012345678910:key/12345678-1234-1234-1234-123456789111",
            },
            DatabaseEncryption = new Gcp.Container.Inputs.AwsClusterControlPlaneDatabaseEncryptionArgs
            {
                KmsKeyArn = "arn:aws:kms:my-aws-region:012345678910:key/12345678-1234-1234-1234-123456789111",
            },
            IamInstanceProfile = "my--1p-dev-controlplane",
            SubnetIds = new[]
            {
                "subnet-00000000000000000",
            },
            Version = versions.Apply(getAwsVersionsResult => getAwsVersionsResult.ValidVersions[0]),
            InstanceType = "t3.medium",
            MainVolume = new Gcp.Container.Inputs.AwsClusterControlPlaneMainVolumeArgs
            {
                Iops = 3000,
                KmsKeyArn = "arn:aws:kms:my-aws-region:012345678910:key/12345678-1234-1234-1234-123456789111",
                SizeGib = 10,
                VolumeType = "GP3",
            },
            ProxyConfig = new Gcp.Container.Inputs.AwsClusterControlPlaneProxyConfigArgs
            {
                SecretArn = "arn:aws:secretsmanager:us-west-2:126285863215:secret:proxy_config20210824150329476300000001-ABCDEF",
                SecretVersion = "12345678-ABCD-EFGH-IJKL-987654321098",
            },
            RootVolume = new Gcp.Container.Inputs.AwsClusterControlPlaneRootVolumeArgs
            {
                Iops = 3000,
                KmsKeyArn = "arn:aws:kms:my-aws-region:012345678910:key/12345678-1234-1234-1234-123456789111",
                SizeGib = 10,
                VolumeType = "GP3",
            },
            SecurityGroupIds = new[]
            {
                "sg-00000000000000000",
            },
            SshConfig = new Gcp.Container.Inputs.AwsClusterControlPlaneSshConfigArgs
            {
                Ec2KeyPair = "my--1p-dev-ssh",
            },
            Tags = 
            {
                { "owner", "my@service-account.com" },
            },
        },
        Fleet = new Gcp.Container.Inputs.AwsClusterFleetArgs
        {
            Project = "my-project-number",
        },
        Location = "us-west1",
        Name = "name",
        Networking = new Gcp.Container.Inputs.AwsClusterNetworkingArgs
        {
            PodAddressCidrBlocks = new[]
            {
                "10.2.0.0/16",
            },
            ServiceAddressCidrBlocks = new[]
            {
                "10.1.0.0/16",
            },
            VpcId = "vpc-00000000000000000",
        },
        Annotations = 
        {
            { "label-one", "value-one" },
        },
        Description = "A sample aws cluster",
        Project = "my-project-name",
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.container.ContainerFunctions;
import com.pulumi.gcp.container.inputs.GetAwsVersionsArgs;
import com.pulumi.gcp.container.AwsCluster;
import com.pulumi.gcp.container.AwsClusterArgs;
import com.pulumi.gcp.container.inputs.AwsClusterAuthorizationArgs;
import com.pulumi.gcp.container.inputs.AwsClusterControlPlaneArgs;
import com.pulumi.gcp.container.inputs.AwsClusterControlPlaneAwsServicesAuthenticationArgs;
import com.pulumi.gcp.container.inputs.AwsClusterControlPlaneConfigEncryptionArgs;
import com.pulumi.gcp.container.inputs.AwsClusterControlPlaneDatabaseEncryptionArgs;
import com.pulumi.gcp.container.inputs.AwsClusterControlPlaneMainVolumeArgs;
import com.pulumi.gcp.container.inputs.AwsClusterControlPlaneProxyConfigArgs;
import com.pulumi.gcp.container.inputs.AwsClusterControlPlaneRootVolumeArgs;
import com.pulumi.gcp.container.inputs.AwsClusterControlPlaneSshConfigArgs;
import com.pulumi.gcp.container.inputs.AwsClusterFleetArgs;
import com.pulumi.gcp.container.inputs.AwsClusterNetworkingArgs;
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) {
        final var versions = ContainerFunctions.getAwsVersions(GetAwsVersionsArgs.builder()
            .project("my-project-name")
            .location("us-west1")
            .build());

        var primary = new AwsCluster("primary", AwsClusterArgs.builder()
            .authorization(AwsClusterAuthorizationArgs.builder()
                .adminUsers(AwsClusterAuthorizationAdminUserArgs.builder()
                    .username("my@service-account.com")
                    .build())
                .adminGroups(AwsClusterAuthorizationAdminGroupArgs.builder()
                    .group("group@domain.com")
                    .build())
                .build())
            .awsRegion("my-aws-region")
            .controlPlane(AwsClusterControlPlaneArgs.builder()
                .awsServicesAuthentication(AwsClusterControlPlaneAwsServicesAuthenticationArgs.builder()
                    .roleArn("arn:aws:iam::012345678910:role/my--1p-dev-oneplatform")
                    .roleSessionName("my--1p-dev-session")
                    .build())
                .configEncryption(AwsClusterControlPlaneConfigEncryptionArgs.builder()
                    .kmsKeyArn("arn:aws:kms:my-aws-region:012345678910:key/12345678-1234-1234-1234-123456789111")
                    .build())
                .databaseEncryption(AwsClusterControlPlaneDatabaseEncryptionArgs.builder()
                    .kmsKeyArn("arn:aws:kms:my-aws-region:012345678910:key/12345678-1234-1234-1234-123456789111")
                    .build())
                .iamInstanceProfile("my--1p-dev-controlplane")
                .subnetIds("subnet-00000000000000000")
                .version(versions.validVersions()[0])
                .instanceType("t3.medium")
                .mainVolume(AwsClusterControlPlaneMainVolumeArgs.builder()
                    .iops(3000)
                    .kmsKeyArn("arn:aws:kms:my-aws-region:012345678910:key/12345678-1234-1234-1234-123456789111")
                    .sizeGib(10)
                    .volumeType("GP3")
                    .build())
                .proxyConfig(AwsClusterControlPlaneProxyConfigArgs.builder()
                    .secretArn("arn:aws:secretsmanager:us-west-2:126285863215:secret:proxy_config20210824150329476300000001-ABCDEF")
                    .secretVersion("12345678-ABCD-EFGH-IJKL-987654321098")
                    .build())
                .rootVolume(AwsClusterControlPlaneRootVolumeArgs.builder()
                    .iops(3000)
                    .kmsKeyArn("arn:aws:kms:my-aws-region:012345678910:key/12345678-1234-1234-1234-123456789111")
                    .sizeGib(10)
                    .volumeType("GP3")
                    .build())
                .securityGroupIds("sg-00000000000000000")
                .sshConfig(AwsClusterControlPlaneSshConfigArgs.builder()
                    .ec2KeyPair("my--1p-dev-ssh")
                    .build())
                .tags(Map.of("owner", "my@service-account.com"))
                .build())
            .fleet(AwsClusterFleetArgs.builder()
                .project("my-project-number")
                .build())
            .location("us-west1")
            .name("name")
            .networking(AwsClusterNetworkingArgs.builder()
                .podAddressCidrBlocks("10.2.0.0/16")
                .serviceAddressCidrBlocks("10.1.0.0/16")
                .vpcId("vpc-00000000000000000")
                .build())
            .annotations(Map.of("label-one", "value-one"))
            .description("A sample aws cluster")
            .project("my-project-name")
            .build());

    }
}
resources:
  primary:
    type: gcp:container:AwsCluster
    properties:
      authorization:
        adminUsers:
          - username: my@service-account.com
        adminGroups:
          - group: group@domain.com
      awsRegion: my-aws-region
      controlPlane:
        awsServicesAuthentication:
          roleArn: arn:aws:iam::012345678910:role/my--1p-dev-oneplatform
          roleSessionName: my--1p-dev-session
        configEncryption:
          kmsKeyArn: arn:aws:kms:my-aws-region:012345678910:key/12345678-1234-1234-1234-123456789111
        databaseEncryption:
          kmsKeyArn: arn:aws:kms:my-aws-region:012345678910:key/12345678-1234-1234-1234-123456789111
        iamInstanceProfile: my--1p-dev-controlplane
        subnetIds:
          - subnet-00000000000000000
        version: ${versions.validVersions[0]}
        instanceType: t3.medium
        mainVolume:
          iops: 3000
          kmsKeyArn: arn:aws:kms:my-aws-region:012345678910:key/12345678-1234-1234-1234-123456789111
          sizeGib: 10
          volumeType: GP3
        proxyConfig:
          secretArn: arn:aws:secretsmanager:us-west-2:126285863215:secret:proxy_config20210824150329476300000001-ABCDEF
          secretVersion: 12345678-ABCD-EFGH-IJKL-987654321098
        rootVolume:
          iops: 3000
          kmsKeyArn: arn:aws:kms:my-aws-region:012345678910:key/12345678-1234-1234-1234-123456789111
          sizeGib: 10
          volumeType: GP3
        securityGroupIds:
          - sg-00000000000000000
        sshConfig:
          ec2KeyPair: my--1p-dev-ssh
        tags:
          owner: my@service-account.com
      fleet:
        project: my-project-number
      location: us-west1
      name: name
      networking:
        podAddressCidrBlocks:
          - 10.2.0.0/16
        serviceAddressCidrBlocks:
          - 10.1.0.0/16
        vpcId: vpc-00000000000000000
      annotations:
        label-one: value-one
      description: A sample aws cluster
      project: my-project-name
variables:
  versions:
    fn::invoke:
      function: gcp:container:getAwsVersions
      arguments:
        project: my-project-name
        location: us-west1

The controlPlane block defines the AWS infrastructure for the Kubernetes control plane. The awsServicesAuthentication property specifies the IAM role ARN that grants the control plane access to AWS services. Encryption is configured via configEncryption and databaseEncryption, both pointing to KMS key ARNs. The networking block defines VPC, pod, and service CIDR ranges. The authorization block grants cluster-admin access to specific users or groups. The fleet property registers the cluster with a GCP Fleet for centralized management.

Configure logging and instance placement

Production clusters often require centralized logging for troubleshooting and compliance, plus control over EC2 instance tenancy.

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

const versions = gcp.container.getAwsVersions({
    project: "my-project-name",
    location: "us-west1",
});
const primary = new gcp.container.AwsCluster("primary", {
    authorization: {
        adminUsers: [{
            username: "my@service-account.com",
        }],
    },
    awsRegion: "my-aws-region",
    controlPlane: {
        awsServicesAuthentication: {
            roleArn: "arn:aws:iam::012345678910:role/my--1p-dev-oneplatform",
            roleSessionName: "my--1p-dev-session",
        },
        configEncryption: {
            kmsKeyArn: "arn:aws:kms:my-aws-region:012345678910:key/12345678-1234-1234-1234-123456789111",
        },
        databaseEncryption: {
            kmsKeyArn: "arn:aws:kms:my-aws-region:012345678910:key/12345678-1234-1234-1234-123456789111",
        },
        iamInstanceProfile: "my--1p-dev-controlplane",
        subnetIds: ["subnet-00000000000000000"],
        version: versions.then(versions => versions.validVersions?.[0]),
        instanceType: "t3.medium",
        mainVolume: {
            iops: 3000,
            kmsKeyArn: "arn:aws:kms:my-aws-region:012345678910:key/12345678-1234-1234-1234-123456789111",
            sizeGib: 10,
            volumeType: "gp3",
        },
        proxyConfig: {
            secretArn: "arn:aws:secretsmanager:us-west-2:126285863215:secret:proxy_config20210824150329476300000001-ABCDEF",
            secretVersion: "12345678-ABCD-EFGH-IJKL-987654321098",
        },
        rootVolume: {
            iops: 3000,
            kmsKeyArn: "arn:aws:kms:my-aws-region:012345678910:key/12345678-1234-1234-1234-123456789111",
            sizeGib: 10,
            volumeType: "gp3",
        },
        securityGroupIds: ["sg-00000000000000000"],
        sshConfig: {
            ec2KeyPair: "my--1p-dev-ssh",
        },
        tags: {
            owner: "my@service-account.com",
        },
        instancePlacement: {
            tenancy: "dedicated",
        },
    },
    fleet: {
        project: "my-project-number",
    },
    location: "us-west1",
    name: "name",
    networking: {
        podAddressCidrBlocks: ["10.2.0.0/16"],
        serviceAddressCidrBlocks: ["10.1.0.0/16"],
        vpcId: "vpc-00000000000000000",
    },
    annotations: {
        "label-one": "value-one",
    },
    description: "A sample aws cluster",
    project: "my-project-name",
    loggingConfig: {
        componentConfig: {
            enableComponents: [
                "system_components",
                "workloads",
            ],
        },
    },
});
import pulumi
import pulumi_gcp as gcp

versions = gcp.container.get_aws_versions(project="my-project-name",
    location="us-west1")
primary = gcp.container.AwsCluster("primary",
    authorization={
        "admin_users": [{
            "username": "my@service-account.com",
        }],
    },
    aws_region="my-aws-region",
    control_plane={
        "aws_services_authentication": {
            "role_arn": "arn:aws:iam::012345678910:role/my--1p-dev-oneplatform",
            "role_session_name": "my--1p-dev-session",
        },
        "config_encryption": {
            "kms_key_arn": "arn:aws:kms:my-aws-region:012345678910:key/12345678-1234-1234-1234-123456789111",
        },
        "database_encryption": {
            "kms_key_arn": "arn:aws:kms:my-aws-region:012345678910:key/12345678-1234-1234-1234-123456789111",
        },
        "iam_instance_profile": "my--1p-dev-controlplane",
        "subnet_ids": ["subnet-00000000000000000"],
        "version": versions.valid_versions[0],
        "instance_type": "t3.medium",
        "main_volume": {
            "iops": 3000,
            "kms_key_arn": "arn:aws:kms:my-aws-region:012345678910:key/12345678-1234-1234-1234-123456789111",
            "size_gib": 10,
            "volume_type": "gp3",
        },
        "proxy_config": {
            "secret_arn": "arn:aws:secretsmanager:us-west-2:126285863215:secret:proxy_config20210824150329476300000001-ABCDEF",
            "secret_version": "12345678-ABCD-EFGH-IJKL-987654321098",
        },
        "root_volume": {
            "iops": 3000,
            "kms_key_arn": "arn:aws:kms:my-aws-region:012345678910:key/12345678-1234-1234-1234-123456789111",
            "size_gib": 10,
            "volume_type": "gp3",
        },
        "security_group_ids": ["sg-00000000000000000"],
        "ssh_config": {
            "ec2_key_pair": "my--1p-dev-ssh",
        },
        "tags": {
            "owner": "my@service-account.com",
        },
        "instance_placement": {
            "tenancy": "dedicated",
        },
    },
    fleet={
        "project": "my-project-number",
    },
    location="us-west1",
    name="name",
    networking={
        "pod_address_cidr_blocks": ["10.2.0.0/16"],
        "service_address_cidr_blocks": ["10.1.0.0/16"],
        "vpc_id": "vpc-00000000000000000",
    },
    annotations={
        "label-one": "value-one",
    },
    description="A sample aws cluster",
    project="my-project-name",
    logging_config={
        "component_config": {
            "enable_components": [
                "system_components",
                "workloads",
            ],
        },
    })
package main

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

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		versions, err := container.GetAwsVersions(ctx, &container.GetAwsVersionsArgs{
			Project:  pulumi.StringRef("my-project-name"),
			Location: pulumi.StringRef("us-west1"),
		}, nil)
		if err != nil {
			return err
		}
		_, err = container.NewAwsCluster(ctx, "primary", &container.AwsClusterArgs{
			Authorization: &container.AwsClusterAuthorizationArgs{
				AdminUsers: container.AwsClusterAuthorizationAdminUserArray{
					&container.AwsClusterAuthorizationAdminUserArgs{
						Username: pulumi.String("my@service-account.com"),
					},
				},
			},
			AwsRegion: pulumi.String("my-aws-region"),
			ControlPlane: &container.AwsClusterControlPlaneArgs{
				AwsServicesAuthentication: &container.AwsClusterControlPlaneAwsServicesAuthenticationArgs{
					RoleArn:         pulumi.String("arn:aws:iam::012345678910:role/my--1p-dev-oneplatform"),
					RoleSessionName: pulumi.String("my--1p-dev-session"),
				},
				ConfigEncryption: &container.AwsClusterControlPlaneConfigEncryptionArgs{
					KmsKeyArn: pulumi.String("arn:aws:kms:my-aws-region:012345678910:key/12345678-1234-1234-1234-123456789111"),
				},
				DatabaseEncryption: &container.AwsClusterControlPlaneDatabaseEncryptionArgs{
					KmsKeyArn: pulumi.String("arn:aws:kms:my-aws-region:012345678910:key/12345678-1234-1234-1234-123456789111"),
				},
				IamInstanceProfile: pulumi.String("my--1p-dev-controlplane"),
				SubnetIds: pulumi.StringArray{
					pulumi.String("subnet-00000000000000000"),
				},
				Version:      pulumi.String(versions.ValidVersions[0]),
				InstanceType: pulumi.String("t3.medium"),
				MainVolume: &container.AwsClusterControlPlaneMainVolumeArgs{
					Iops:       pulumi.Int(3000),
					KmsKeyArn:  pulumi.String("arn:aws:kms:my-aws-region:012345678910:key/12345678-1234-1234-1234-123456789111"),
					SizeGib:    pulumi.Int(10),
					VolumeType: pulumi.String("gp3"),
				},
				ProxyConfig: &container.AwsClusterControlPlaneProxyConfigArgs{
					SecretArn:     pulumi.String("arn:aws:secretsmanager:us-west-2:126285863215:secret:proxy_config20210824150329476300000001-ABCDEF"),
					SecretVersion: pulumi.String("12345678-ABCD-EFGH-IJKL-987654321098"),
				},
				RootVolume: &container.AwsClusterControlPlaneRootVolumeArgs{
					Iops:       pulumi.Int(3000),
					KmsKeyArn:  pulumi.String("arn:aws:kms:my-aws-region:012345678910:key/12345678-1234-1234-1234-123456789111"),
					SizeGib:    pulumi.Int(10),
					VolumeType: pulumi.String("gp3"),
				},
				SecurityGroupIds: pulumi.StringArray{
					pulumi.String("sg-00000000000000000"),
				},
				SshConfig: &container.AwsClusterControlPlaneSshConfigArgs{
					Ec2KeyPair: pulumi.String("my--1p-dev-ssh"),
				},
				Tags: pulumi.StringMap{
					"owner": pulumi.String("my@service-account.com"),
				},
				InstancePlacement: &container.AwsClusterControlPlaneInstancePlacementArgs{
					Tenancy: pulumi.String("dedicated"),
				},
			},
			Fleet: &container.AwsClusterFleetArgs{
				Project: pulumi.String("my-project-number"),
			},
			Location: pulumi.String("us-west1"),
			Name:     pulumi.String("name"),
			Networking: &container.AwsClusterNetworkingArgs{
				PodAddressCidrBlocks: pulumi.StringArray{
					pulumi.String("10.2.0.0/16"),
				},
				ServiceAddressCidrBlocks: pulumi.StringArray{
					pulumi.String("10.1.0.0/16"),
				},
				VpcId: pulumi.String("vpc-00000000000000000"),
			},
			Annotations: pulumi.StringMap{
				"label-one": pulumi.String("value-one"),
			},
			Description: pulumi.String("A sample aws cluster"),
			Project:     pulumi.String("my-project-name"),
			LoggingConfig: &container.AwsClusterLoggingConfigArgs{
				ComponentConfig: &container.AwsClusterLoggingConfigComponentConfigArgs{
					EnableComponents: pulumi.StringArray{
						pulumi.String("system_components"),
						pulumi.String("workloads"),
					},
				},
			},
		})
		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 versions = Gcp.Container.GetAwsVersions.Invoke(new()
    {
        Project = "my-project-name",
        Location = "us-west1",
    });

    var primary = new Gcp.Container.AwsCluster("primary", new()
    {
        Authorization = new Gcp.Container.Inputs.AwsClusterAuthorizationArgs
        {
            AdminUsers = new[]
            {
                new Gcp.Container.Inputs.AwsClusterAuthorizationAdminUserArgs
                {
                    Username = "my@service-account.com",
                },
            },
        },
        AwsRegion = "my-aws-region",
        ControlPlane = new Gcp.Container.Inputs.AwsClusterControlPlaneArgs
        {
            AwsServicesAuthentication = new Gcp.Container.Inputs.AwsClusterControlPlaneAwsServicesAuthenticationArgs
            {
                RoleArn = "arn:aws:iam::012345678910:role/my--1p-dev-oneplatform",
                RoleSessionName = "my--1p-dev-session",
            },
            ConfigEncryption = new Gcp.Container.Inputs.AwsClusterControlPlaneConfigEncryptionArgs
            {
                KmsKeyArn = "arn:aws:kms:my-aws-region:012345678910:key/12345678-1234-1234-1234-123456789111",
            },
            DatabaseEncryption = new Gcp.Container.Inputs.AwsClusterControlPlaneDatabaseEncryptionArgs
            {
                KmsKeyArn = "arn:aws:kms:my-aws-region:012345678910:key/12345678-1234-1234-1234-123456789111",
            },
            IamInstanceProfile = "my--1p-dev-controlplane",
            SubnetIds = new[]
            {
                "subnet-00000000000000000",
            },
            Version = versions.Apply(getAwsVersionsResult => getAwsVersionsResult.ValidVersions[0]),
            InstanceType = "t3.medium",
            MainVolume = new Gcp.Container.Inputs.AwsClusterControlPlaneMainVolumeArgs
            {
                Iops = 3000,
                KmsKeyArn = "arn:aws:kms:my-aws-region:012345678910:key/12345678-1234-1234-1234-123456789111",
                SizeGib = 10,
                VolumeType = "gp3",
            },
            ProxyConfig = new Gcp.Container.Inputs.AwsClusterControlPlaneProxyConfigArgs
            {
                SecretArn = "arn:aws:secretsmanager:us-west-2:126285863215:secret:proxy_config20210824150329476300000001-ABCDEF",
                SecretVersion = "12345678-ABCD-EFGH-IJKL-987654321098",
            },
            RootVolume = new Gcp.Container.Inputs.AwsClusterControlPlaneRootVolumeArgs
            {
                Iops = 3000,
                KmsKeyArn = "arn:aws:kms:my-aws-region:012345678910:key/12345678-1234-1234-1234-123456789111",
                SizeGib = 10,
                VolumeType = "gp3",
            },
            SecurityGroupIds = new[]
            {
                "sg-00000000000000000",
            },
            SshConfig = new Gcp.Container.Inputs.AwsClusterControlPlaneSshConfigArgs
            {
                Ec2KeyPair = "my--1p-dev-ssh",
            },
            Tags = 
            {
                { "owner", "my@service-account.com" },
            },
            InstancePlacement = new Gcp.Container.Inputs.AwsClusterControlPlaneInstancePlacementArgs
            {
                Tenancy = "dedicated",
            },
        },
        Fleet = new Gcp.Container.Inputs.AwsClusterFleetArgs
        {
            Project = "my-project-number",
        },
        Location = "us-west1",
        Name = "name",
        Networking = new Gcp.Container.Inputs.AwsClusterNetworkingArgs
        {
            PodAddressCidrBlocks = new[]
            {
                "10.2.0.0/16",
            },
            ServiceAddressCidrBlocks = new[]
            {
                "10.1.0.0/16",
            },
            VpcId = "vpc-00000000000000000",
        },
        Annotations = 
        {
            { "label-one", "value-one" },
        },
        Description = "A sample aws cluster",
        Project = "my-project-name",
        LoggingConfig = new Gcp.Container.Inputs.AwsClusterLoggingConfigArgs
        {
            ComponentConfig = new Gcp.Container.Inputs.AwsClusterLoggingConfigComponentConfigArgs
            {
                EnableComponents = new[]
                {
                    "system_components",
                    "workloads",
                },
            },
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.container.ContainerFunctions;
import com.pulumi.gcp.container.inputs.GetAwsVersionsArgs;
import com.pulumi.gcp.container.AwsCluster;
import com.pulumi.gcp.container.AwsClusterArgs;
import com.pulumi.gcp.container.inputs.AwsClusterAuthorizationArgs;
import com.pulumi.gcp.container.inputs.AwsClusterControlPlaneArgs;
import com.pulumi.gcp.container.inputs.AwsClusterControlPlaneAwsServicesAuthenticationArgs;
import com.pulumi.gcp.container.inputs.AwsClusterControlPlaneConfigEncryptionArgs;
import com.pulumi.gcp.container.inputs.AwsClusterControlPlaneDatabaseEncryptionArgs;
import com.pulumi.gcp.container.inputs.AwsClusterControlPlaneMainVolumeArgs;
import com.pulumi.gcp.container.inputs.AwsClusterControlPlaneProxyConfigArgs;
import com.pulumi.gcp.container.inputs.AwsClusterControlPlaneRootVolumeArgs;
import com.pulumi.gcp.container.inputs.AwsClusterControlPlaneSshConfigArgs;
import com.pulumi.gcp.container.inputs.AwsClusterControlPlaneInstancePlacementArgs;
import com.pulumi.gcp.container.inputs.AwsClusterFleetArgs;
import com.pulumi.gcp.container.inputs.AwsClusterNetworkingArgs;
import com.pulumi.gcp.container.inputs.AwsClusterLoggingConfigArgs;
import com.pulumi.gcp.container.inputs.AwsClusterLoggingConfigComponentConfigArgs;
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) {
        final var versions = ContainerFunctions.getAwsVersions(GetAwsVersionsArgs.builder()
            .project("my-project-name")
            .location("us-west1")
            .build());

        var primary = new AwsCluster("primary", AwsClusterArgs.builder()
            .authorization(AwsClusterAuthorizationArgs.builder()
                .adminUsers(AwsClusterAuthorizationAdminUserArgs.builder()
                    .username("my@service-account.com")
                    .build())
                .build())
            .awsRegion("my-aws-region")
            .controlPlane(AwsClusterControlPlaneArgs.builder()
                .awsServicesAuthentication(AwsClusterControlPlaneAwsServicesAuthenticationArgs.builder()
                    .roleArn("arn:aws:iam::012345678910:role/my--1p-dev-oneplatform")
                    .roleSessionName("my--1p-dev-session")
                    .build())
                .configEncryption(AwsClusterControlPlaneConfigEncryptionArgs.builder()
                    .kmsKeyArn("arn:aws:kms:my-aws-region:012345678910:key/12345678-1234-1234-1234-123456789111")
                    .build())
                .databaseEncryption(AwsClusterControlPlaneDatabaseEncryptionArgs.builder()
                    .kmsKeyArn("arn:aws:kms:my-aws-region:012345678910:key/12345678-1234-1234-1234-123456789111")
                    .build())
                .iamInstanceProfile("my--1p-dev-controlplane")
                .subnetIds("subnet-00000000000000000")
                .version(versions.validVersions()[0])
                .instanceType("t3.medium")
                .mainVolume(AwsClusterControlPlaneMainVolumeArgs.builder()
                    .iops(3000)
                    .kmsKeyArn("arn:aws:kms:my-aws-region:012345678910:key/12345678-1234-1234-1234-123456789111")
                    .sizeGib(10)
                    .volumeType("gp3")
                    .build())
                .proxyConfig(AwsClusterControlPlaneProxyConfigArgs.builder()
                    .secretArn("arn:aws:secretsmanager:us-west-2:126285863215:secret:proxy_config20210824150329476300000001-ABCDEF")
                    .secretVersion("12345678-ABCD-EFGH-IJKL-987654321098")
                    .build())
                .rootVolume(AwsClusterControlPlaneRootVolumeArgs.builder()
                    .iops(3000)
                    .kmsKeyArn("arn:aws:kms:my-aws-region:012345678910:key/12345678-1234-1234-1234-123456789111")
                    .sizeGib(10)
                    .volumeType("gp3")
                    .build())
                .securityGroupIds("sg-00000000000000000")
                .sshConfig(AwsClusterControlPlaneSshConfigArgs.builder()
                    .ec2KeyPair("my--1p-dev-ssh")
                    .build())
                .tags(Map.of("owner", "my@service-account.com"))
                .instancePlacement(AwsClusterControlPlaneInstancePlacementArgs.builder()
                    .tenancy("dedicated")
                    .build())
                .build())
            .fleet(AwsClusterFleetArgs.builder()
                .project("my-project-number")
                .build())
            .location("us-west1")
            .name("name")
            .networking(AwsClusterNetworkingArgs.builder()
                .podAddressCidrBlocks("10.2.0.0/16")
                .serviceAddressCidrBlocks("10.1.0.0/16")
                .vpcId("vpc-00000000000000000")
                .build())
            .annotations(Map.of("label-one", "value-one"))
            .description("A sample aws cluster")
            .project("my-project-name")
            .loggingConfig(AwsClusterLoggingConfigArgs.builder()
                .componentConfig(AwsClusterLoggingConfigComponentConfigArgs.builder()
                    .enableComponents(                    
                        "system_components",
                        "workloads")
                    .build())
                .build())
            .build());

    }
}
resources:
  primary:
    type: gcp:container:AwsCluster
    properties:
      authorization:
        adminUsers:
          - username: my@service-account.com
      awsRegion: my-aws-region
      controlPlane:
        awsServicesAuthentication:
          roleArn: arn:aws:iam::012345678910:role/my--1p-dev-oneplatform
          roleSessionName: my--1p-dev-session
        configEncryption:
          kmsKeyArn: arn:aws:kms:my-aws-region:012345678910:key/12345678-1234-1234-1234-123456789111
        databaseEncryption:
          kmsKeyArn: arn:aws:kms:my-aws-region:012345678910:key/12345678-1234-1234-1234-123456789111
        iamInstanceProfile: my--1p-dev-controlplane
        subnetIds:
          - subnet-00000000000000000
        version: ${versions.validVersions[0]}
        instanceType: t3.medium
        mainVolume:
          iops: 3000
          kmsKeyArn: arn:aws:kms:my-aws-region:012345678910:key/12345678-1234-1234-1234-123456789111
          sizeGib: 10
          volumeType: gp3
        proxyConfig:
          secretArn: arn:aws:secretsmanager:us-west-2:126285863215:secret:proxy_config20210824150329476300000001-ABCDEF
          secretVersion: 12345678-ABCD-EFGH-IJKL-987654321098
        rootVolume:
          iops: 3000
          kmsKeyArn: arn:aws:kms:my-aws-region:012345678910:key/12345678-1234-1234-1234-123456789111
          sizeGib: 10
          volumeType: gp3
        securityGroupIds:
          - sg-00000000000000000
        sshConfig:
          ec2KeyPair: my--1p-dev-ssh
        tags:
          owner: my@service-account.com
        instancePlacement:
          tenancy: dedicated
      fleet:
        project: my-project-number
      location: us-west1
      name: name
      networking:
        podAddressCidrBlocks:
          - 10.2.0.0/16
        serviceAddressCidrBlocks:
          - 10.1.0.0/16
        vpcId: vpc-00000000000000000
      annotations:
        label-one: value-one
      description: A sample aws cluster
      project: my-project-name
      loggingConfig:
        componentConfig:
          enableComponents:
            - system_components
            - workloads
variables:
  versions:
    fn::invoke:
      function: gcp:container:getAwsVersions
      arguments:
        project: my-project-name
        location: us-west1

The loggingConfig block enables component-level logging by specifying which components to monitor (system_components and workloads). Logs flow to Cloud Logging for centralized analysis. The instancePlacement property controls EC2 tenancy; setting it to “dedicated” ensures control plane instances run on single-tenant hardware, useful for compliance or licensing requirements. This configuration extends the basic cluster setup with operational visibility and infrastructure isolation.

Beyond these examples

These snippets focus on specific cluster-level features: control plane encryption and authentication, network configuration and RBAC, and logging and instance placement. They’re intentionally minimal rather than full Kubernetes deployments.

The examples rely on pre-existing infrastructure such as AWS VPC, subnets, security groups, AWS IAM roles and instance profiles, AWS KMS keys for encryption, AWS Secrets Manager for proxy configuration, and a GCP project with Anthos Multicloud API enabled. They focus on configuring the cluster control plane rather than provisioning the underlying AWS or GCP infrastructure.

To keep things focused, common cluster patterns are omitted, including:

  • Binary Authorization for image verification
  • Node pool configuration (separate resource)
  • Cluster autoscaling and monitoring
  • Custom tagging beyond owner metadata

These omissions are intentional: the goal is to illustrate how each cluster feature is wired, not provide drop-in Kubernetes modules. See the GKE on AWS Cluster resource reference for all available configuration options.

Let's deploy GCP Anthos Clusters

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

Try Pulumi Cloud for FREE

Frequently Asked Questions

Cluster Lifecycle & Immutability
What fields can't I change after creating the cluster?
The awsRegion, fleet, location, name, and project fields are immutable and require cluster recreation if changed.
Why aren't all my cluster annotations being managed?
The annotations field is non-authoritative and only manages annotations present in your configuration. Use the effectiveAnnotations output to see all annotations on the resource.
AWS Authentication & IAM
How do I set up AWS authentication for the control plane?
Configure controlPlane.awsServicesAuthentication with roleArn (your IAM role ARN) and roleSessionName for the control plane to access AWS services.
What IAM resources does the control plane need?
The control plane requires an iamInstanceProfile, security group IDs (securityGroupIds), and subnet IDs (subnetIds) in your AWS account.
How do I configure SSH access to control plane nodes?
Set controlPlane.sshConfig.ec2KeyPair to your EC2 key pair name.
Encryption & Security
What encryption is required for the cluster?

You must provide AWS KMS key ARNs for three encryption types:

  1. Config encryption - controlPlane.configEncryption.kmsKeyArn
  2. Database encryption - controlPlane.databaseEncryption.kmsKeyArn
  3. Volume encryption - kmsKeyArn in both mainVolume and rootVolume
How do I configure proxy settings for the cluster?
Set controlPlane.proxyConfig with secretArn (AWS Secrets Manager ARN) and secretVersion containing your proxy configuration.
Control Plane Configuration
How do I configure control plane volumes?
Configure both mainVolume and rootVolume with iops (e.g., 3000), sizeGib (e.g., 10), volumeType (e.g., gp3), and kmsKeyArn for encryption.
Should I use GP3 or gp3 for volumeType?
Use lowercase gp3. The basic example shows uppercase GP3, but the enum examples demonstrate lowercase is the correct format.
What instance type should I use for the control plane?
Set controlPlane.instanceType to an AWS EC2 instance type (e.g., t3.medium as shown in examples).
Authorization & Observability
What's the difference between adminUsers and adminGroups?
adminUsers grants cluster access to individual users by username, while adminGroups grants access to entire groups by group identifier.
How do I enable logging for cluster components?
Configure loggingConfig.componentConfig.enableComponents with an array like ["system_components", "workloads"].
How do I connect the cluster to a GKE fleet?
Set fleet.project to your GCP project number (not project ID). This field is immutable after creation.

Using a different cloud?

Explore containers guides for other cloud providers: