Skip to content
Open
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Fix TestTLSDefaults to use port-forwarding like TestTLSMinimumVersions
This commit refactors TestTLSDefaults to use the same port-forwarding
approach as TestTLSMinimumVersions, which fixes DNS resolution failures
when running in CI as a pod.

Problem:
When the test runs as a pod in the cluster, it attempted to connect
directly to the external API server hostname from the kubeconfig
(e.g., api.cluster5.ocpci.eng.rdu2.redhat.com). However, the pod's
internal DNS cannot resolve this external hostname, resulting in:
  dial tcp: lookup api.cluster5.ocpci.eng.rdu2.redhat.com on 172.30.0.10:53: no such host

Solution:
Use forwardPortAndExecute() to create a port-forward tunnel to the
apiserver service in openshift-kube-apiserver namespace, then test
against localhost:<forwarded-port>. This approach:
- Works both in-cluster (CI) and externally (with kubeconfig)
- Eliminates DNS resolution issues entirely
- Is consistent with TestTLSMinimumVersions pattern
- Includes built-in retry logic (3 attempts)
- Simplifies the code by removing URL parsing and env var detection

Changes:
- Removed net/url and os imports (no longer needed)
- Wrapped TLS version and cipher tests in forwardPortAndExecute callback
- Changed error reporting from t.Errorf() to returning errors for retry support
- Tests now connect to localhost via port-forward tunnel

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
  • Loading branch information
wangke19 and claude committed Nov 28, 2025
commit ff085032dd92904a8b9304f098aeaec2ee9e06bb
86 changes: 53 additions & 33 deletions test/extended/apiserver/tls.go
Original file line number Diff line number Diff line change
Expand Up @@ -133,46 +133,66 @@ var _ = g.Describe("[sig-api-machinery][Feature:APIServer]", func() {
g.Skip("Cluster TLS profile is not default (intermediate), skipping cipher defaults check")
}

g.By("Verifying TLS version behavior")
for _, tlsVersionName := range crypto.ValidTLSVersions() {
tlsVersion := crypto.TLSVersionOrDie(tlsVersionName)
expectSuccess := tlsVersion >= crypto.DefaultTLSVersion()
cfg := &tls.Config{MinVersion: tlsVersion, MaxVersion: tlsVersion, InsecureSkipVerify: true}
host := strings.TrimPrefix(oc.AdminConfig().Host, "https://")

conn, err := tls.Dial("tcp", host, cfg)
if err == nil {
err := conn.Close()
if err != nil {
t.Errorf("Failed to close connection: %v", err)
g.By("Verifying TLS version and cipher behavior via port-forward to apiserver")
err = forwardPortAndExecute("apiserver", "openshift-kube-apiserver", "443", func(port int) error {
host := fmt.Sprintf("localhost:%d", port)
t.Logf("Testing TLS versions and ciphers against %s", host)

// Test TLS versions
for _, tlsVersionName := range crypto.ValidTLSVersions() {
tlsVersion := crypto.TLSVersionOrDie(tlsVersionName)
expectSuccess := tlsVersion >= crypto.DefaultTLSVersion()
cfg := &tls.Config{MinVersion: tlsVersion, MaxVersion: tlsVersion, InsecureSkipVerify: true}

t.Logf("Testing TLS version %s (0x%04x), expectSuccess=%v", tlsVersionName, tlsVersion, expectSuccess)
conn, dialErr := tls.Dial("tcp", host, cfg)
if dialErr == nil {
t.Logf("TLS %s succeeded, negotiated version: 0x%04x", tlsVersionName, conn.ConnectionState().Version)
closeErr := conn.Close()
if closeErr != nil {
return fmt.Errorf("failed to close connection: %v", closeErr)
}
} else {
t.Logf("TLS %s failed with error: %v", tlsVersionName, dialErr)
}
if success := dialErr == nil; success != expectSuccess {
return fmt.Errorf("expected success %v, got %v with TLS version %s", expectSuccess, success, tlsVersionName)
}
}
if success := err == nil; success != expectSuccess {
t.Errorf("Expected success %v, got %v with TLS version %s dialing master", expectSuccess, success, tlsVersionName)
}
}

g.By("Verifying cipher suites")
defaultCiphers := map[uint16]bool{}
for _, c := range crypto.DefaultCiphers() {
defaultCiphers[c] = true
}

for _, cipherName := range crypto.ValidCipherSuites() {
cipher, err := crypto.CipherSuite(cipherName)
if err != nil {
t.Fatal(err)
// Test cipher suites
defaultCiphers := map[uint16]bool{}
for _, c := range crypto.DefaultCiphers() {
defaultCiphers[c] = true
}
expectFailure := !defaultCiphers[cipher]
cfg := &tls.Config{CipherSuites: []uint16{cipher}, InsecureSkipVerify: true}

conn, err := tls.Dial("tcp", oc.AdminConfig().Host, cfg)
if err == nil {
if expectFailure {
t.Errorf("Expected failure on cipher %s, got success dialing master. Closing conn: %v", cipherName, conn.Close())
for _, cipherName := range crypto.ValidCipherSuites() {
cipher, err := crypto.CipherSuite(cipherName)
if err != nil {
return err
}
expectFailure := !defaultCiphers[cipher]
// Constrain to TLS 1.2 to prevent Go 1.23+ from silently ignoring
// deprecated ciphers and falling back to TLS 1.3 with secure defaults
cfg := &tls.Config{
CipherSuites: []uint16{cipher},
MinVersion: tls.VersionTLS12,
MaxVersion: tls.VersionTLS12,
InsecureSkipVerify: true,
}

conn, dialErr := tls.Dial("tcp", host, cfg)
if dialErr == nil {
closeErr := conn.Close()
if expectFailure {
return fmt.Errorf("expected failure on cipher %s, got success. Closing conn: %v", cipherName, closeErr)
}
}
}
}

return nil
})
o.Expect(err).NotTo(o.HaveOccurred())
})
})

Expand Down