Configuring Custom Default Gateways on VPC-Backed Subnets in VCFA

Create a VPC-backed subnet in VCFA 9 and NSX assigns the default gateway for you — the first usable address in the CIDR. Try to change it in NSX Manager and the field is greyed out. It looks like a platform limitation. It isn’t. The gateway is fully configurable, at creation and afterwards, through the Supervisor API. This post covers the whole path: installing the CLI, establishing organization and namespace context, creating a subnet with a custom gateway, modifying an existing one, and verifying that NSX actually realised the change.

Contents
1. Why the NSX Manager field is disabled · 2. Prerequisites · 3. Establishing context with the VCF CLI · 4. Understanding the two Subnet kinds · 5. Creating a subnet with a custom gateway · 6. Modifying an existing subnet · 7. Verifying realisation · 8. Choosing a valid CIDR

1. Why the NSX Manager field is disabled

VPC-backed subnets in VCFA 9 are managed declaratively. The Kubernetes object is the source of truth, and a controller reconciles it into NSX continuously. Editing the realised configuration in NSX Manager sits outside that loop — so even when a change appears to save, the controller restores whatever the object specifies. That is also why the value reverts on refresh: a symptom that reads like a defect but is the reconciliation loop working correctly.

The rule that follows is worth carrying beyond this specific case: in a declarative system, a greyed-out control usually means you are looking at realised state rather than desired state. The edit belongs in the object.

2. Prerequisites

RequirementWhere to get it
VCF CLI (the vcf command)Broadcom Support portal. It supersedes the older kubectl cci plugin.
kubectlAny recent release. The VCF CLI generates the kubeconfig it uses.
An API tokenVCF Automation org portal → user menu → API Tokens → Generate. Displayed once; copy it immediately.
Namespace accessA role that permits creating objects in a Supervisor Namespace. Read-only consumers can follow along but not apply.

Commands below are PowerShell on Windows. They work identically on Linux and macOS with the usual quoting differences.

3. Establishing context with the VCF CLI

Store the token in a variable. The quotes matter — without them PowerShell attempts to execute the token as a command.

$vcfa_token = "your-api-token-here"

Create the organization context. This is the CLI’s term for a saved connection to a VCF Automation tenant.

vcf context create my-org `
  --endpoint https://vcfa.example.com `
  --type cci `
  --auth-type basic `
  --tenant-name My-Org `
  --api-token $vcfa_token `
  --insecure-skip-tls-verify

Substitute your endpoint and tenant name. Use --insecure-skip-tls-verify only in a lab; in production supply your fleet CA with --ca-certificate instead.

The CLI creates one context for the organization plus one for every Supervisor Namespace you can reach. List them:

kubectl config get-contexts
NAME                                      NAMESPACE
my-org
my-org:app-ns-4hm32:default-project       app-ns-4hm32
my-org:phoenix-ns-kj9g6:team-phoenix      phoenix-ns-kj9g6
Context names have three parts The format is <org>:<namespace>:<project>. Using the bare namespace name returns “no context exists with the name”. Copy the full string from the output above.

Switch into the namespace where the subnet will live:

kubectl config use-context my-org:phoenix-ns-kj9g6:team-phoenix

Confirm you are on the namespace layer rather than the organization layer — the presence of subnetsets is a reliable indicator:

kubectl get subnetsets
NAME          ACCESSMODE   IPV4SUBNETSIZE   NETWORKADDRESSES
pod-default   PrivateTGW   32
vm-default    Private      32               172.30.0.64/27
Tokens expire mid-session An expired token surfaces as Unauthorized, as com.vmware.vapi.std.errors.unauthorized, or — confusingly — as a complaint about downloading the OpenAPI schema on an otherwise valid manifest. All three mean the same thing. Re-authenticate with vcf context use my-org, then switch back to your namespace context.

4. Understanding the two Subnet kinds

Before writing any YAML, know which object you are creating. VCFA 9 exposes two distinct Subnet kinds in different API groups, corresponding to the two areas of the VCF Automation UI. They are not interchangeable.

Build & DeployManage & Govern
ContextNamespaceOrganization
API groupcrd.nsx.vmware.com/v1alpha1vpc.nsx.vmware.com/v1alpha1
ScopeSupervisor NamespaceVPC
Name formatdb-tier<vpc>:db-tier
Additional required fields—regionName, vpcName

Both support custom gateways, so the technique here applies at either level. Most consumers want the namespace-scoped object; the VPC-scoped one is for governance workflows.

Diagnosing the wrong layer “The server doesn’t have a resource type” almost always means you are on the wrong context rather than that the object does not exist. Check with kubectl config current-context before assuming a CRD is missing.

5. Creating a subnet with a custom gateway

By default NSX assigns the first usable address in the range — a subnet allocated 172.30.0.192/27 receives gateway 172.30.0.193. To choose a different address you must supply both the CIDR and the gateway, because the gateway is only meaningful relative to a known range.

Namespace-scoped (Build & Deploy):

apiVersion: crd.nsx.vmware.com/v1alpha1
kind: Subnet
metadata:
  name: db-tier
  namespace: phoenix-ns-kj9g6
spec:
  accessMode: Private
  ipAddresses:
    - 172.30.1.224/27
  advancedConfig:
    gatewayAddresses:
      - 172.30.1.240/27

VPC-scoped (Manage & Govern), run against the organization context:

apiVersion: vpc.nsx.vmware.com/v1alpha1
kind: Subnet
metadata:
  name: default-region-west:db-tier
  namespace: team-phoenix
spec:
  regionName: region-west
  vpcName: default-region-west
  accessMode: Private
  ipAddresses:
    - 172.30.1.224/27
  advancedConfig:
    gatewayAddresses:
      - 172.30.1.240/27
kubectl create -f subnet.yaml
Use create, not apply kubectl apply writes a last-applied-configuration annotation that this API rejects outright with “Annotation updates are not supported.” Use kubectl create for new objects and kubectl edit or kubectl patch for changes. Inside a VKS guest cluster, ordinary apply works normally — the restriction applies to the VCF Automation API only.

The gateway may sit at any usable address within the CIDR. It does not have to be the first.

6. Modifying an existing subnet

Contrary to what the greyed-out NSX Manager field suggests, the gateway can also be changed after creation:

kubectl edit subnet db-tier

Or without an interactive editor:

kubectl patch subnet db-tier --type=merge `
  -p '{"spec":{"advancedConfig":{"gatewayAddresses":["172.30.1.250/27"]}}}'
PowerShell and inline JSON Wrap the JSON in single quotes and use plain double quotes inside. Escaping the inner quotes with backslashes — the pattern that works in bash — produces “invalid character ‘\\’ looking for beginning of object key string” here.

Changing the gateway alters routing for every workload on the subnet, so treat it as a change with a maintenance window rather than a routine edit.

7. Verifying realisation

This is the step most worth building into your habits, and it generalises well beyond gateways.

kubectl create and kubectl edit return success the moment the Kubernetes API accepts the object. NSX realisation happens afterwards, asynchronously, and it can fail silently.

kubectl get subnet db-tier -o jsonpath='{.status.conditions}'

A healthy subnet:

[{"reason":"SubnetReady","status":"True","type":"Ready",
  "message":"NSX Subnet with DHCPDeactivated has been successfully created/updated"}]

A failed one carries the real NSX error in the condition message:

[{"reason":"SubnetNotReady","status":"False","type":"Ready",
  "message":"... IpAddressBlocks path=[...] do not have spare capacity
   to allocate CIDR of size 32 and startIp 172.30.0.160."}]

Confirm the realised addressing too, which is where you will see whether your requested gateway was honoured:

kubectl get subnet db-tier -o jsonpath='{.status.networkAddresses}{"\n"}{.status.gatewayAddresses}'
A failed subnet still looks created It appears in kubectl get subnets with a name, an access mode, and a spec. It simply has no network behind it. Any automation against this API should poll status.conditions rather than trusting the command’s exit code.

8. Choosing a valid CIDR

Specifying ipAddresses disables automatic allocation — ipv4SubnetSize is then ignored entirely, and selecting a valid free range becomes your responsibility.

Each access mode draws from a different IP block, and the blocks do not overlap:

Access modeAddress sourceReachable from
PrivateThe VPC’s own private rangeWithin the VPC; SNAT applied on egress
PrivateTGWA separate transit-gateway blockOther VPCs on the same transit gateway — routed, not NAT’d
PublicThe NSX Project’s external blockNatively routed beyond the VPC

Choose from the wrong pool and NSX names the block it expected:

CIDR 172.30.1.64/27 does not belong to IpAddressBlocks
path=[/orgs/default/projects/.../ip-blocks/default-tgw-region-west]

To find free space, list what is already allocated:

kubectl get subnets,subnetsets -o custom-columns=`
'NAME:.metadata.name,CIDR:.status.networkAddresses'
Allocation is sequential NSX allocates from the next free boundary rather than filling gaps. Apparent gaps in your namespace’s view are usually claimed by other namespaces sharing the same VPC, which you cannot see from a tenant context. Step past the highest allocated block rather than attempting to reuse a gap — and if you hit “do not have spare capacity” on a range that looks free, that is why.

Summary

TaskCommand or field
Authenticatevcf context create <org> --type cci --api-token $token
Switch to namespacekubectl config use-context <org>:<ns>:<project>
Set gateway at creationspec.advancedConfig.gatewayAddresses plus spec.ipAddresses
Change it laterkubectl edit subnet <name>
Verifykubectl get subnet <name> -o jsonpath='{.status.conditions}'
Find free rangeskubectl get subnets,subnetsets with status.networkAddresses

If you are new to this API, the companion post Your First VM and Kubernetes Cluster in VCF Automation walks through projects, namespaces, virtual machines and VKS clusters using the same toolchain.

Comments

Leave a Reply

More posts