⚠️ WARNING: ⚠️ this document is mostly wrong. I mixed up the paramater
audiences=
with the correctaudience=
. Since Vault doesn't validate parameters (at least not in the Kubernetes plugin), I didn't realize thataudiences=
was ignored entirely. Thanks to Tom Proctor for finding this out (comment).
tl;dr: Vault 1.12 and below have a bug that prevents checking the JWT audience. The issue is documented in vault-plugin-auth-kubernetes#175. If you configure a Kubernetes auth role with the parameter audience
set to vault
, that parameter won't do anything. Any audience will be accepted by the role:
Context: as part of The Vault issuer can now be given a serviceAccountRef (PR 5502), I had a doubt: does Vault verify the audience (aud
value in the JWT) when using the Kubernetes auth method?
The Vault documentation says:
audience
(string: "") - Optional Audience claim to verify in the JWT.
This suggests that Vault checks the audience, probably by passing the audience
parameter to the TokenReview request. When the parameter audiences
is left empty, we can assume that the TokenReview is performed with audiences: []
, meaning that the audience is expected to be https://kubernetes.default.svc.cluster.local
for example.
The TokenReview documentation makes it clear that in case of an empty audiences
array, the aud
is matched with the Kubernetes API server's audience:
audiences
, string array: Audiences is a list of the identifiers that the resource server presented with the token identifies as. Audience-aware token authenticators will verify that the token was intended for at least one of the audiences in this list. If no audiences are provided, the audience will default to the audience of the Kubernetes apiserver.
To check that the TokenReview API works this way, let us create a token with some audience:
Then, let's review that token with an empty audiences
, which reproduces what Vault does when audiences
is left empty:
As suspected, the TokenReview fails:
invalid bearer token, token audiences ["vault"] is invalid for the target audiences ["https://kubernetes.default.svc.cluster.local"].
Now, let's see how Vault behaves when the parameter audiences=
isn't used when configuring the role. First, I install Vault:
Let's create a role without using the audiences
parameter:
Let's get a token with some audience:
From the above results, we should get an error since "no audience in token review call = the audience must be the Kubernetes API server's audience".
But the TokenReview works:
Now, let's see if a mismatching audience is caught:
It works too… Vault seems to be ignoring when the audience doesn't match.
Now, let's see what is happening behind the scene using mitmproxy. In one shell session, run mitmproxy:
Let us create a service account that Vault will use to do the TokenReview requests:
Let us run Vault in another shell session:
Now, configure Vault:
Finally, let us trigger a token review:
The response is positive:
As you can see, Vault does not pass the mismatch
audience to the TokenReview request. Instead, it copies whatever aud
is in the JWT into the TokenReview request.
It seems there is a bug. The code in path_login.go goes something like this:
Vault is checking that the audience in the JWT matches the audience in the JWT, instead of checking that the audience in the JWT matches the role's audience.