Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
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
13 changes: 8 additions & 5 deletions pkg/server/plugin/nodeattestor/k8spsat/psat.go
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,7 @@ func (p *AttestorPlugin) Attest(stream nodeattestorv1.NodeAttestor_AttestServer)

namespace, serviceAccountName, err := k8s.GetNamesFromTokenStatus(tokenStatus)
if err != nil {
return status.Errorf(codes.Internal, "fail to parse username from token review status for cluster %q: %v", attestationData.Cluster, err)
return status.Errorf(codes.Internal, "failed to parse username from token review status for cluster %q: %v", attestationData.Cluster, err)
}
fullServiceAccountName := fmt.Sprintf("%v:%v", namespace, serviceAccountName)

Expand All @@ -212,22 +212,25 @@ func (p *AttestorPlugin) Attest(stream nodeattestorv1.NodeAttestor_AttestServer)

podName, err := k8s.GetPodNameFromTokenStatus(tokenStatus)
if err != nil {
return status.Errorf(codes.Internal, "fail to get pod name from token review status for cluster %q: %v", attestationData.Cluster, err)
return status.Errorf(codes.Internal, "failed to get pod name from token review status for cluster %q: %v", attestationData.Cluster, err)
}

podUID, err := k8s.GetPodUIDFromTokenStatus(tokenStatus)
if err != nil {
return status.Errorf(codes.Internal, "fail to get pod UID from token review status for cluster %q: %v", attestationData.Cluster, err)
return status.Errorf(codes.Internal, "failed to get pod UID from token review status for cluster %q: %v", attestationData.Cluster, err)
}

pod, err := cluster.client.GetPod(stream.Context(), namespace, podName)
if err != nil {
return status.Errorf(codes.Internal, "fail to get pod from k8s API server for cluster %q: %v", attestationData.Cluster, err)
return status.Errorf(codes.Internal, "failed to get pod from k8s API server for cluster %q: %v", attestationData.Cluster, err)
}
if string(pod.UID) != podUID {
return status.Errorf(codes.PermissionDenied, "pod UID mismatch for cluster %q", attestationData.Cluster)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm wondering if we could include a bit more context in this error to help operators diagnose a rejection. Including the pod name and the token's UID, for example pod UID mismatch for pod %q in cluster %q: token bound to pod UID %q, would make it clearer which pod was involved, while keeping the error limited to values the caller already presented in its token.

}

node, err := cluster.client.GetNode(stream.Context(), pod.Spec.NodeName)
if err != nil {
return status.Errorf(codes.Internal, "fail to get node from k8s API server for cluster %q: %v", attestationData.Cluster, err)
return status.Errorf(codes.Internal, "failed to get node from k8s API server for cluster %q: %v", attestationData.Cluster, err)
}

nodeUID := string(node.UID)
Expand Down
38 changes: 27 additions & 11 deletions pkg/server/plugin/nodeattestor/k8spsat/psat_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ func (s *AttestorSuite) TestAttestFailsWithMissingNamespaceClaim() {
s.apiServerClient.SetTokenStatus(token, createTokenStatus(tokenData, true, defaultAudience))
s.requireAttestError(makePayload("FOO", token),
codes.Internal,
"nodeattestor(k8s_psat): fail to parse username from token review status")
"nodeattestor(k8s_psat): failed to parse username from token review status")
}

func (s *AttestorSuite) TestAttestFailsWithMissingServiceAccountNameClaim() {
Expand All @@ -176,7 +176,7 @@ func (s *AttestorSuite) TestAttestFailsWithMissingServiceAccountNameClaim() {
s.apiServerClient.SetTokenStatus(token, createTokenStatus(tokenData, true, defaultAudience))
s.requireAttestError(makePayload("FOO", token),
codes.Internal,
"nodeattestor(k8s_psat): fail to parse username from token review status")
"nodeattestor(k8s_psat): failed to parse username from token review status")
}

func (s *AttestorSuite) TestAttestFailsWithMissingPodNameClaim() {
Expand All @@ -189,7 +189,7 @@ func (s *AttestorSuite) TestAttestFailsWithMissingPodNameClaim() {
s.apiServerClient.SetTokenStatus(token, createTokenStatus(tokenData, true, defaultAudience))
s.requireAttestError(makePayload("FOO", token),
codes.Internal,
"nodeattestor(k8s_psat): fail to get pod name from token review status")
"nodeattestor(k8s_psat): failed to get pod name from token review status")
}

func (s *AttestorSuite) TestAttestFailsWithMissingPodUIDClaim() {
Expand All @@ -202,7 +202,7 @@ func (s *AttestorSuite) TestAttestFailsWithMissingPodUIDClaim() {
s.apiServerClient.SetTokenStatus(token, createTokenStatus(tokenData, true, defaultAudience))
s.requireAttestError(makePayload("FOO", token),
codes.Internal,
"nodeattestor(k8s_psat): fail to get pod UID from token review status")
"nodeattestor(k8s_psat): failed to get pod UID from token review status")
}

func (s *AttestorSuite) TestAttestFailsIfServiceAccountNotAllowed() {
Expand Down Expand Up @@ -230,7 +230,7 @@ func (s *AttestorSuite) TestAttestFailsIfCannotGetPod() {
s.apiServerClient.SetTokenStatus(token, createTokenStatus(tokenData, true, defaultAudience))
s.requireAttestError(makePayload("FOO", token),
codes.Internal,
"nodeattestor(k8s_psat): fail to get pod from k8s API server")
"nodeattestor(k8s_psat): failed to get pod from k8s API server")
}

func (s *AttestorSuite) TestAttestFailsIfCannotGetNode() {
Expand All @@ -242,10 +242,10 @@ func (s *AttestorSuite) TestAttestFailsIfCannotGetNode() {
}
token := s.signToken(s.fooSigner, tokenData)
s.apiServerClient.SetTokenStatus(token, createTokenStatus(tokenData, true, defaultAudience))
s.apiServerClient.SetPod(createPod("NS1", "PODNAME", "NODENAME", "172.16.0.1"))
s.apiServerClient.SetPod(createPod("NS1", "PODNAME", "PODUID", "NODENAME", "172.16.0.1"))
s.requireAttestError(makePayload("FOO", token),
codes.Internal,
"nodeattestor(k8s_psat): fail to get node from k8s API server")
"nodeattestor(k8s_psat): failed to get node from k8s API server")
}

func (s *AttestorSuite) TestAttestFailsIfNodeUIDIsEmpty() {
Expand All @@ -257,13 +257,28 @@ func (s *AttestorSuite) TestAttestFailsIfNodeUIDIsEmpty() {
}
token := s.signToken(s.fooSigner, tokenData)
s.apiServerClient.SetTokenStatus(token, createTokenStatus(tokenData, true, defaultAudience))
s.apiServerClient.SetPod(createPod("NS1", "PODNAME", "NODENAME", "172.16.0.1"))
s.apiServerClient.SetPod(createPod("NS1", "PODNAME", "PODUID", "NODENAME", "172.16.0.1"))
s.apiServerClient.SetNode(createNode("NODENAME", ""))
s.requireAttestError(makePayload("FOO", token),
codes.Internal,
"node UID is empty")
}

func (s *AttestorSuite) TestAttestFailsIfPodUIDDoesNotMatchTokenStatus() {
tokenData := &TokenData{
namespace: "NS1",
serviceAccountName: "SA1",
podName: "PODNAME",
podUID: "PODUID",
}
token := s.signToken(s.fooSigner, tokenData)
s.apiServerClient.SetTokenStatus(token, createTokenStatus(tokenData, true, defaultAudience))
s.apiServerClient.SetPod(createPod("NS1", "PODNAME", "OTHER-PODUID", "NODENAME", "172.16.0.1"))
s.requireAttestError(makePayload("FOO", token),
codes.PermissionDenied,
"pod UID mismatch")
}

func (s *AttestorSuite) TestAttestSuccess() {
// Success with FOO signed token
tokenData := &TokenData{
Expand All @@ -274,7 +289,7 @@ func (s *AttestorSuite) TestAttestSuccess() {
}
token := s.signToken(s.fooSigner, tokenData)
s.apiServerClient.SetTokenStatus(token, createTokenStatus(tokenData, true, defaultAudience))
s.apiServerClient.SetPod(createPod("NS1", "PODNAME-1", "NODENAME-1", "172.16.10.1"))
s.apiServerClient.SetPod(createPod("NS1", "PODNAME-1", "PODUID-1", "NODENAME-1", "172.16.10.1"))
s.apiServerClient.SetNode(createNode("NODENAME-1", "NODEUID-1"))

result, err := s.attestor.Attest(context.Background(), makePayload("FOO", token), expectNoChallenge)
Expand Down Expand Up @@ -303,7 +318,7 @@ func (s *AttestorSuite) TestAttestSuccess() {
}
token = s.signToken(s.barSigner, tokenData)
s.apiServerClient.SetTokenStatus(token, createTokenStatus(tokenData, true, []string{"AUDIENCE"}))
s.apiServerClient.SetPod(createPod("NS2", "PODNAME-2", "NODENAME-2", "172.16.10.2"))
s.apiServerClient.SetPod(createPod("NS2", "PODNAME-2", "PODUID-2", "NODENAME-2", "172.16.10.2"))
s.apiServerClient.SetNode(createNode("NODENAME-2", "NODEUID-2"))

// Success with BAR signed token
Expand Down Expand Up @@ -462,11 +477,12 @@ func createTokenStatus(tokenData *TokenData, authenticated bool, audience []stri
}
}

func createPod(namespace, podName, nodeName string, hostIP string) *corev1.Pod {
func createPod(namespace, podName, podUID, nodeName, hostIP string) *corev1.Pod {
return &corev1.Pod{
ObjectMeta: metav1.ObjectMeta{
Namespace: namespace,
Name: podName,
UID: types.UID(podUID),
Labels: map[string]string{
"PODLABEL-A": "A",
"PODLABEL-B": "B",
Expand Down
Loading