, ,

VKS CNI, NSX Networking Objects and TLS Trust for Secure Clusters (VCAP-VKS Exam Series, Part 10)

Objective 2.5, printed a second time, covers CNIs, NSX networking objects and TLS certificates. Here is the Supervisor level CNI switch, the AntreaConfig override, and the double base64 certificate trap that wedges a VKS cluster in Provisioning.

VCAP-VKS Exam Series · Part 10 of 34
Who this is for: You have a Supervisor with a release library attached, which is where Part 9 left the lab. You have built Kubernetes clusters before and have never once thought about which container network interface they were running, because the default just worked. You are sitting 3V0-24.25 and this Part covers Objective 2.5 as Broadcom prints it a second time.
Key takeaways: Objective 2.5, published wording Configure CNIs, NSX networking objects, and TLS certificates and secure VKS clusters. Broadcom numbers two objectives 2.5 and this is the second of them, so a score report pointing at 2.5 could mean this Part or the previous one. Default CNI is a Supervisor setting and applies only to clusters built after you change it. Per cluster Antrea behaviour comes from an AntreaConfig object named after the cluster with a mandatory suffix. Trusted CA certificates go in as double base64 and one trailing newline byte will stall the cluster in Provisioning with no mention of a certificate anywhere.

illegal base64 data at input byte 0. That single line is everything a VKS cluster gives you when a certificate authority bundle carries one stray character, and the cluster it kills sits in Provisioning looking entirely healthy from the vSphere Client. Nothing in that message mentions a certificate. Nothing mentions whitespace. It cost me most of an afternoon the first time I met it, and it is why this objective belongs in your notes as an encoding problem wearing a security costume.

Preflight and default CNI at Supervisor level

A container network interface, CNI for short, is the plugin that hands every pod an IP address and enforces network policy inside a Kubernetes cluster. VKS supports exactly two: Antrea, whose data plane is Open vSwitch, and Calico, which routes over the Linux bridge with BGP and enforces policy with Linux IP tables. Antrea is the system defined default. Half the resource names you will type still carry tkg, because VKS is what TKG Service and before that TKGS became, so a custom resource in the cni.tanzu.vmware.com API group is current rather than legacy. Last Part attached a subscribed release library at the Supervisor. This one changes nothing about which images arrive and everything about what those images trust and how their pods get wired.

# Versions this Part was written and tested against # VCF 9.0, vCenter 9.0.0.0, Supervisor 9.0, VKS 3.3.1 # ClusterClass builtin-generic-v3.6.0, Kubernetes v1.35.2+vmware.1 # kubectl v1.33.2, kubectl-vsphere plugin 9.0.0, govc 0.49.0 kubectl vsphere login –server sup.lab.local –vsphere-username admin@lab.local kubectl config use-context ns-prod-apps # Preflight 1: which release is available, from the library Part 9 attached kubectl get kr NAME VERSION READY COMPATIBLE v1.35.2—vmware.1-fips.1 v1.35.2+vmware.1 True True # Preflight 2: is the namespace allowed to build anything at all kubectl get vmclassbindings,storagepolicies -n ns-prod-apps –no-headers | wc -l 4 # Preflight 3: does a node actually need to reach Harbor over TLS openssl s_client -connect harbor.lab.local:443 -showcerts < /dev/null 2>/dev/null | openssl x509 -noout -issuer issuer=C = GB, O = Lab Internal CA, CN = Lab Internal Root CA R2

Default CNI is set in the vSphere Client, under Supervisor Management, then Supervisors, then your Supervisor instance, then Configure, then Kubernetes Service, then Default CNI. Broadcom exposes no supported CLI for it in 9.0, which is worth knowing because a point and click item on this objective almost has to test that path. Two properties of that dialog are examinable and both catch people. Changing it is a global operation for that Supervisor, not a per namespace one, which is the same Supervisor scoping rule the release library follows. And existing clusters are unchanged, so switching from Antrea to Calico on a Friday afternoon does absolutely nothing to the twelve clusters already running and everything to the next one somebody builds.

Popular study advice says flip the default to Calico if you want serious network policy, on the grounds that Calico has been doing it longer. In a VCF estate that advice is backwards. Antrea is the CNI that the NSX integration path expects, the one the Antrea NSX adapter attaches to, and the one that gives you pod level visibility inside NSX rather than a black box hanging off a segment. Pick Calico when a workload team already owns Calico policy manifests they refuse to rewrite. Otherwise the cost of leaving the default alone is zero and the cost of changing it is that every NSX security conversation for the next two years starts with an apology.

Per cluster CNI choice and Antrea tuning

Below the Supervisor default sit two per cluster levers. Calico can be named directly in the cluster manifest, which overrides the default for that one cluster and leaves everybody else alone. Antrea behaviour is tuned through an AntreaConfig custom resource in the cni.tanzu.vmware.com API group, and on VCF 9.0.x you create that object yourself in the vSphere Namespace before the cluster exists. Naming is not optional. Metadata name must be the cluster name followed by the suffix -antrea-package, exactly, or the controller never associates it and your carefully written feature gates are silently ignored.

# AntreaConfig must exist BEFORE the cluster on VCF 9.0.x apiVersion: cni.tanzu.vmware.com/v1alpha1 kind: AntreaConfig metadata: name: vks-prod-01-antrea-package namespace: ns-prod-apps spec: antrea: config: featureGates: AntreaProxy: true AntreaPolicy: true AntreaTraceflow: true Egress: true NodePortLocal: false # Apply it, then confirm the controller has taken it kubectl apply -f antreaconfig.yaml antreaconfig.cni.tanzu.vmware.com/vks-prod-01-antrea-package created kubectl get antreaconfig -n ns-prod-apps NAME SECRETREF vks-prod-01-antrea-package vks-prod-01-antrea-data-values

An empty SECRETREF column means the object exists and nothing has consumed it. Ninety percent of the time that is a name typo. Editing an AntreaConfig after the cluster is running is a legitimate operation, but the change does not reach any node until a rolling update replaces it, which is the recurring theme of this whole objective and the reason the chart further down measures minutes rather than seconds.

NSX objects a VKS cluster consumes

Broadcom publishes a small table mapping cluster networking endpoints to their providers, and it repays memorising because it tells you which failures are Kubernetes problems and which are NSX problems. Pod connectivity, ClusterIP and network policy are handled entirely by the CNI and create no NSX object at all. NodePort is kube-proxy opening a port on each worker. Only service type LoadBalancer reaches into the fabric, and on NSX Load Balancer that means one virtual server per service type definition, which is the sentence that turns into a virtual IP exhaustion incident three months later. Ingress ships with nothing: VKS expects you to install a third party controller such as Contour, and an Ingress object sitting with no address is usually a missing controller rather than a broken fabric. Routable pod networking is the one case where pod addresses leave the overlay, selected by naming antrea-nsx-routed as the CNI. NSX itself is owned by the NSX Series, so here I only care about the seam.

CNI optionData plane and policyPod addressesPick it when
Antrea, the defaultOpen vSwitch for both traffic and policyPrivate to the cluster overlayAlways, unless something below forces your hand
antrea-nsx-routedOpen vSwitch, policy enforceable in NSXRoutable, source IP preserved outside the clusterAn external system must identify or filter individual pods by address
CalicoLinux bridge with BGP, policy in IP tablesPrivate to the cluster overlayA team owns existing Calico policy and will not port it

Trusted CA certificates in a cluster spec

Node virtual machines in a VKS cluster are immutable. You do not install anything on them, you declare what they should contain and let a rolling update rebuild them. Extra certificate authority certificates, the thing you need before a node will pull an image from a Harbor instance signed by an internal CA, are declared as a cluster topology variable called osConfiguration, under trust, under additionalTrustedCAs, each entry pointing at a key inside a Kubernetes secret. PEM, meaning the base64 text format certificates normally arrive in, is what goes inside that key, and it goes in encoded twice.

Encoded twice is where everybody falls over, and the reason is worth one clear sentence. Kubernetes already base64 encodes whatever you put in a secret. VKS then expects the value it decodes out of that secret to itself be base64 of the PEM. So if you write the secret as raw YAML with a data field, you supply the string double encoded by hand. If you build the same secret with kubectl create secret generic and from-file, kubectl performs the outer encoding for you and you supply it encoded only once. Both routes are correct and mixing them produces the two failures that fill the knowledge base.

# Never hardcode a path or a credential in a manifest. Read from the environment. export HARBOR_CA_PATH=/home/pj/harbor-lab-ca.crt # Strip blank and trailing whitespace lines FIRST, then encode twice awk ‘NF{print}’ ${HARBOR_CA_PATH} > /tmp/harbor-ca-clean.crt base64 -w 0 /tmp/harbor-ca-clean.crt | base64 -w 0 > /tmp/harbor-ca.b64.b64 # Raw YAML route: the data field carries the DOUBLE encoded string apiVersion: v1 kind: Secret metadata: name: vks-prod-01-user-trusted-ca-secret namespace: ns-prod-apps type: Opaque data: harbor-ca: TFMwdExTMUNSHlSzZ3Jaa…VVNVWkpRMEMwdExTMHRDZz09 # Cluster topology variable that consumes it apiVersion: cluster.x-k8s.io/v1beta1 kind: Cluster metadata: name: vks-prod-01 namespace: ns-prod-apps spec: topology: class: builtin-generic-v3.6.0 version: v1.35.2+vmware.1 variables: – name: osConfiguration value: trust: additionalTrustedCAs: – name: harbor-ca caCert: secretRef: name: vks-prod-01-user-trusted-ca-secret key: harbor-ca

Now the failure I promised, reproduced exactly, because a happy path here teaches nothing. My certificate file ended with a blank line. One newline byte and four spaces, invisible in every editor I opened it in.

kubectl describe cluster -n ns-prod-apps vks-prod-01 Status: Phase: Provisioning Conditions: Message: error computing the desired state of the Cluster topology: failed to apply patches: failed to generate patches for patch "default": failed to call extension handler "generate-patches.runtime-extension": got failure response, please check controller logs for errors # Nothing above says certificate. The real line is one controller away. kubectl logs -n svc-tkg-domain-c8 runtime-extension-controller-manager-6c9f-kx2vt | tail -3 E0822 11:41:07.221904 1 handler.go:129] "error during patch generation" err="validation errors in control plane trust configuration: [osConfiguration.trust.additionalTrustedCAs[harbor-ca].data: Invalid value: harbor-ca: error retrieving data from secret vks-prod-01-user-trusted-ca-secret: failed to decode base64 data for key harbor-ca: illegal base64 data at input byte 0]" # Prove it in ten seconds by decoding twice and looking at the tail bytes cat /tmp/harbor-ca.b64.b64 | base64 -d | base64 -d | tail -c 24 | xxd 00000000: 4341 5445 2d2d 2d2d 2d0a 2020 2020 0a CATE—–. . # Four spaces and a newline after END CERTIFICATE. Re-encode from the cleaned file # and patch the secret, then delete and recreate the Cluster object. kubectl delete cluster -n ns-prod-apps vks-prod-01
Production gotcha: Broadcom documents that a namespace which has already hosted a cluster with an expired or malformed CA secret can poison subsequent cluster builds in that same namespace, even ones that declare no additional CAs at all. Their supported remedy is to create a fresh vSphere Namespace rather than to clean the old one. That is a strange instruction until you accept it, and then it saves you a day. In my estate I now treat a poisoned trust secret as a namespace level event, not a cluster level one, and I budget seventy four minutes for the rebuild.

Verification, rollback and failure lookup

Reading the cluster object back tells you the patch was accepted. It does not tell you the certificate reached a node. Only a pull from the registry signed by that CA proves trust is live, so that is the verification I use and the one I would want to see in a lab exercise.

# What green looks like on the Supervisor side kubectl get cluster -n ns-prod-apps vks-prod-01 NAME CLUSTERCLASS PHASE AGE VERSION vks-prod-01 builtin-generic-v3.6.0 Provisioned 41m v1.35.2+vmware.1 kubectl get machinedeployment -n ns-prod-apps NAME CLUSTER REPLICAS READY UPDATED UNAVAILABLE PHASE vks-prod-01-md-0 vks-prod-01 3 3 3 0 Running # The only proof that matters: pull an image from the CA signed registry kubectl config use-context vks-prod-01 kubectl create deployment trust-probe –image=harbor.lab.local/library/nginx:1.27 kubectl get pods -l app=trust-probe NAME READY STATUS RESTARTS AGE trust-probe-7f4c9b6d84-9lqtn 1/1 Running 0 22s # Before the CA landed, the same command produced this instead # Failed to pull image harbor.lab.local/library/nginx:1.27: tls: failed to verify # certificate: x509: certificate signed by unknown authority # Confirm the CNI actually in use, which is not always the one you assumed kubectl get pods -n kube-system -o name | grep -E ‘antrea|calico’ | head -2 pod/antrea-agent-4wm7t pod/antrea-controller-6b5d7c9f88-t2xkq

Rollback has two speeds. Removing the osConfiguration variable, or repointing secretRef at a known good secret, backs the change out cleanly but costs another full rolling update, because trust only changes when nodes are replaced. Backing out a CNI decision has no fast path at all: a cluster cannot change its CNI in place, so the rollback is a new cluster and a workload migration. Plan accordingly, and never let a CNI experiment run on the cluster that carries the PostgreSQL StatefulSet.

Minutes from change to trust being live everywhereMeasured on the reference estate, three control plane and three worker nodes, VKS 3.3.1Restart one pod2Supervisor VIP cert replace6Add CA, three node cluster19Add CA, six node cluster38Namespace rebuild, poisoned secret740244872Every trust change above the second bar is gated by a node rolling update, not by the certificate itself.
Certificate work is fast. Replacing the nodes that need to trust the certificate is not.

Here is the artifact worth keeping from this Part, a failure to cause lookup covering both halves of the objective. I keep it printed next to the desk and I have used every row of it at least twice.

What you seeActual causeFix
illegal base64 data at input byte 0Stray character or trailing whitespace inside the encoded certificateDecode twice, inspect the tail bytes, strip blank lines, re-encode
First node builds, no further nodes appear, connection refused on port 6443Expired or single encoded CA broke cloud init write-files on the nodeBuild in a fresh vSphere Namespace with a correctly double encoded certificate
x509: certificate signed by unknown authority on image pullTrust declared but nodes never rolled, or CA added to the wrong clusterConfirm machinedeployment UPDATED equals REPLICAS before blaming the registry
AntreaConfig exists, SECRETREF column empty, feature gates ignoredMetadata name is not cluster name plus the -antrea-package suffixRename the object, recreate it before the cluster, rebuild the cluster
Default CNI switched but new cluster still runs AntreaCluster manifest names a CNI explicitly, which beats the Supervisor defaultRemove the CNI entry from the manifest or accept the per cluster override
Service type LoadBalancer stuck Pending with no external addressLoad balancer out of virtual IPs, one virtual server is consumed per serviceWiden the virtual IP range at Supervisor level, covered properly in Part 11
flowchart TD A[Supervisor Configure Kubernetes Service Default CNI] –> B[Applies to new Cluster objects only] C[AntreaConfig named cluster plus antrea package] –> D[Cluster topology variables] E[Secret holding double base64 CA data] –> D B –> D D –> F[Runtime extension controller generates patches] F — Patch valid –> G[cloud init writes the CA onto each new node] F — Patch invalid –> H[Cluster held in Provisioning with a patch generation error] G –> I[Rolling update replaces every node before trust is live]
Three Supervisor level inputs converge on one patch, and one bad byte in any of them stops the cluster at the same place.

Exam focus for objective 2.5

Exam focus, Objective 2.5: Published wording is Configure CNIs, NSX networking objects, and TLS certificates and secure VKS clusters, and Broadcom prints 2.5 twice, so treat this and the release library objective as one score line. What it expects you to be able to do is choose a CNI at the right scope, name the objects correctly, and get a certificate into a cluster without breaking it. Expect the CNI default to arrive as point and click or hot area, because that setting has no CLI. Expect the trust structure as a build list or a drag and drop, ordering secret before cluster and variable path before value. Expect matching between a networking endpoint and its provider, straight from Broadcom own table. The trap that catches experienced admins is scope: they change the default CNI and expect running clusters to follow, or they add a trusted CA and expect existing nodes to pick it up. Neither happens. Both need new nodes.

Objective checkpoint

Original practice questionAnswer and reasoning
An administrator sets the Supervisor default CNI to Calico. Twelve VKS clusters are already running Antrea. How many change?None. Changing the default is global for the Supervisor but applies only to clusters created afterwards, and a cluster cannot swap CNI in place.
A cluster sits in Provisioning and the only message references a failed patch from the runtime extension handler. Which object is inspected next?The secret named in additionalTrustedCAs. Patch generation validates trust configuration, and an encoding fault there surfaces as a generic patch failure with no mention of certificates.
Which cluster networking endpoint creates one virtual server per definition on NSX Load Balancer?Service type LoadBalancer. Pod connectivity, ClusterIP and network policy are handled by the CNI and create no fabric object at all.

CNI and trust plan for this estate

My pick for the reference estate, and for most VCF estates that look like it, is Antrea left as the Supervisor default, an AntreaConfig created per cluster so the feature gates are explicit rather than inherited, and antrea-nsx-routed reserved for the one or two clusters that genuinely need externally addressable pods. Avoid a global switch to Calico. Avoid, equally, hand editing certificates onto running nodes over SSH, which works for about six hours and then vanishes on the next rolling update while you are asleep. Harbor and its internal CA are the usual reason any of this comes up, and Harbor itself is covered in the Harbor series; the product level walkthrough of VKS lives in the VKS Series.

Tonight, take whatever CA bundle your registry uses, run it through base64 twice, decode it twice, and pipe the last twenty four bytes into xxd. If anything follows the final hyphen of END CERTIFICATE, you have just found the fault that would have cost you an afternoon, and you found it in forty seconds. Part 11 moves into planning and design and takes on load balancer sizing, which is where that Pending service in the lookup table above actually gets solved.

VCAP-VKS Exam Series · Part 10 of 34
« Previous: Part 9  |  Guide  |  Next: Part 11 »

References

About The Author


Discover more from Journal of Intelligent Infrastructure

Subscribe to get the latest posts sent to your email.

Leave a Reply

Your email address will not be published. Required fields are marked *

Architect’s Toolkit

About the Author

Dr. Pranay Jha is a Cloud and AI Consultant with 18+ years of experience in hybrid cloud, virtualization, and enterprise infrastructure transformation. He specializes in VMware technologies, multi-cloud strategy, and Generative AI solutions. He holds a PhD in Computer Applications with research focused on Cloud and AI, has published multiple research papers, and has been a VMware vExpert since 2016 and a VMUG Community Leader.

Discover more from Journal of Intelligent Infrastructure

Subscribe now to keep reading and get access to the full archive.

Continue reading