package main import ( "context" "flag" "fmt" "log" "net/http" "sort" "strings" "sync" "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/client-go/kubernetes/scheme" "k8s.io/client-go/rest" ) // sanCapturingTransport is a transport wrapper that inspects the server's // certificate and prints its Subject Alternative Names (SANs). type sanCapturingTransport struct { mu sync.Mutex roundTripper http.RoundTripper lastServer string reqCount int } func (t *sanCapturingTransport) RoundTrip(req *http.Request) (*http.Response, error) { resp, err := t.roundTripper.RoundTrip(req) // After the request, inspect the TLS connection state. if err == nil && resp.TLS != nil && len(resp.TLS.PeerCertificates) > 0 { cert := resp.TLS.PeerCertificates[0] sort.Strings(cert.DNSNames) dnsNames := strings.Join(cert.DNSNames, ", ") // exclude .atd. and .itd. and .ard. record t.mu.Lock() lastServer := t.lastServer if t.reqCount%1000 == 0 && t.reqCount != 0 { log.Printf("total requests made: %d", t.reqCount) } if lastServer != dnsNames { if t.reqCount != 0 { log.Printf("Connected to a new server after %d requests: %s", t.reqCount, dnsNames) } t.reqCount = 0 t.lastServer = dnsNames } t.reqCount++ t.mu.Unlock() } return resp, err } func main() { var ( host = flag.String("host", "localhost", "Kubernetes API server host") port = flag.String("port", "8080", "Kubernetes API server port") ) flag.Parse() // Create the server URL - always insecure as requested serverURL := fmt.Sprintf("https://%s:%s", *host, *port) // Create REST config for an insecure connection config := &rest.Config{ Host: serverURL, TLSClientConfig: rest.TLSClientConfig{ Insecure: true, }, QPS: -1, Burst: -1, } // Set the WrapTransport to inject our SAN capturing logic. config.WrapTransport = func(rt http.RoundTripper) http.RoundTripper { return &sanCapturingTransport{roundTripper: rt} } // To connect to a root API endpoint like /version, we need to configure the REST client // to hit the root API path with an empty GroupVersion. config.APIPath = "/" config.GroupVersion = &schema.GroupVersion{} config.NegotiatedSerializer = scheme.Codecs // Create a raw REST client restClient, err := rest.RESTClientFor(config) if err != nil { log.Fatalf("Failed to create REST client: %v", err) } ctx := context.Background() for i := 0; i < 1000000; i++ { // Make raw request to /version endpoint and discard the result // This is just to verify the connection is successful result := restClient.Get().AbsPath("/version").Do(ctx) if err := result.Error(); err != nil { log.Printf("Failed to connect to /version endpoint: %v", err) } } }