kube-apiserver is the only component that touches the cluster's database; every other component, kubectl 5,150 included, is an HTTPS client of it. Each object has a REST path, and kubectl's verbose mode shows the call:
kubectl get nodes -v=6 2>&1 | grep '"Response"' | sed 's/.*] //'
kubectl get --raw='/readyz?verbose' | grep -E 'etcd|rbac|readyz'"Response" verb="GET" url="https://127.0.0.1:37181/api/v1/nodes?limit=500" status="200 OK" milliseconds=8 [+]etcd ok [+]etcd-readiness ok [+]poststarthook/rbac/bootstrap-roles ok readyz check passed
kind 14,561 publishes port 6443 on a random localhost port (37181 here). Every write passes the same pipeline: authentication (a client certificate, a ServiceAccount token or an OIDC token), authorization (kind runs --authorization-mode=Node,RBAC, RBAC and Service Accounts), admission control, which may mutate the object and then accept or reject it (Pod Security, Pod Security and Policies), and finally schema validation and a write to etcd 137,357 with a new resourceVersion. The API server also serves watches, long-lived requests that stream every change; the scheduler, controllers and kubelets all run on watches rather than polling (Watches and Informers).