ipn/store/kubestore,kube: fix cert error in admin UI (#16717)

Also adds a test to kube/kubeclient to defend against the error type
returned by the client changing in future.

Fixes tailscale/corp#30855

Change-Id: Id11d4295003e66ad5c29a687f1239333c21226a4

Signed-off-by: Tom Proctor <tomhjp@users.noreply.github.com>
This commit is contained in:
Tom Proctor
2025-07-30 13:39:59 +01:00
committed by GitHub
parent aa6a2d1e56
commit eed3e5dc61
3 changed files with 101 additions and 0 deletions

View File

@@ -9,6 +9,7 @@ import (
"fmt"
"log"
"net"
"net/http"
"os"
"strings"
"time"
@@ -203,6 +204,23 @@ func (s *Store) ReadTLSCertAndKey(domain string) (cert, key []byte, err error) {
// that wraps ipn.ErrStateNotExist here.
return nil, nil, ipn.ErrStateNotExist
}
st, ok := err.(*kubeapi.Status)
if ok && st.Code == http.StatusForbidden && (s.certShareMode == "ro" || s.certShareMode == "rw") {
// In cert share mode, we read from a dedicated Secret per domain.
// To get here, we already had a cache miss from our in-memory
// store. For write replicas, that means it wasn't available on
// start and it wasn't written since. For read replicas, that means
// it wasn't available on start and it hasn't been reloaded in the
// background. So getting a "forbidden" error is an expected
// "not found" case where we've been asked for a cert we don't
// expect to issue, and so the forbidden error reflects that the
// operator didn't assign permission for a Secret for that domain.
//
// This code path gets triggered by the admin UI's machine page,
// which queries for the node's own TLS cert existing via the
// "tls-cert-status" c2n API.
return nil, nil, ipn.ErrStateNotExist
}
return nil, nil, fmt.Errorf("getting TLS Secret %q: %w", domain, err)
}
cert = secret.Data[keyTLSCert]