Skip to content

fix(tap): only match allowed names against the verified client cert - #15743

Open
musthaf-bughunter wants to merge 1 commit into
linkerd:mainfrom
musthaf-bughunter:tap-allowed-names-leaf-only
Open

musthaf-bughunter wants to merge 1 commit into
linkerd:mainfrom
musthaf-bughunter:tap-allowed-names-leaf-only

Conversation

@musthaf-bughunter

Copy link
Copy Markdown

The tap APIServer checks requestheader-allowed-names against every
certificate in req.TLS.PeerCertificates. Only the first one, the leaf,
is verified against requestheader-client-ca-file; the rest are
whatever the client chose to send after it. A client holding any
certificate signed by that CA can append a self-signed certificate with
CN front-proxy-client (or any other allowed name) and pass
validate(). From there it controls X-Remote-User and
X-Remote-Group, so it can tap any workload as any user, for example
system:masters.

This matters where the requestheader CA also issues other client
certificates, which is the case requestheader-allowed-names exists to
guard against.

Match the allowed names against PeerCertificates[0] only. With
RequireAndVerifyClientCert that is the certificate Go verified against
the client CA, and it is the same certificate the Kubernetes
requestheader authenticator checks.

Validation: added TestValidate_IgnoresUnverifiedPeerCertificates,
which does a real TLS handshake with a CA-signed leaf
(CN=name-untrusted) followed by a self-signed CN=name-trusted
certificate. It is accepted on main and rejected with this change. The
existing TestValidate* cases are unchanged and pass. go test ./viz/tap/..., go vet, goimports and golangci-lint are clean.

The tap APIServer checks `requestheader-allowed-names` against every
certificate in `req.TLS.PeerCertificates`. Only the first one, the leaf,
is verified against `requestheader-client-ca-file`; the rest are
whatever the client chose to send after it. A client holding any
certificate signed by that CA can append a self-signed certificate with
CN `front-proxy-client` (or any other allowed name) and pass
`validate()`. From there it controls `X-Remote-User` and
`X-Remote-Group`, so it can tap any workload as any user, for example
`system:masters`.

This matters where the requestheader CA also issues other client
certificates, which is the case `requestheader-allowed-names` exists to
guard against.

Match the allowed names against `PeerCertificates[0]` only. With
`RequireAndVerifyClientCert` that is the certificate Go verified against
the client CA, and it is the same certificate the Kubernetes
requestheader authenticator checks.

Validation: added `TestValidate_IgnoresUnverifiedPeerCertificates`,
which does a real TLS handshake with a CA-signed leaf
(CN=name-untrusted) followed by a self-signed CN=name-trusted
certificate. It is accepted on main and rejected with this change. The
existing `TestValidate*` cases are unchanged and pass. `go test
./viz/tap/...`, `go vet`, goimports and golangci-lint are clean.

Signed-off-by: mushtaf saheb <musthaf@medios.digiscrypt.com>
@musthaf-bughunter
musthaf-bughunter requested a review from a team as a code owner October 22, 2026 13:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant