-
Notifications
You must be signed in to change notification settings - Fork 56
/
token_reviewer.go
79 lines (65 loc) · 1.91 KB
/
token_reviewer.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
package authorization
import (
"context"
"errors"
"fmt"
"strings"
"code.cloudfoundry.org/korifi/api/apierrors"
authv1 "k8s.io/api/authentication/v1"
rbacv1 "k8s.io/api/rbac/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"sigs.k8s.io/controller-runtime/pkg/client"
)
//+kubebuilder:rbac:groups=authentication.k8s.io,resources=tokenreviews,verbs=create
const (
serviceAccountsGroup = "system:serviceaccounts"
serviceAccountNamePrefix = "system:serviceaccount:"
)
type TokenReviewer struct {
privilegedClient client.Client
}
func NewTokenReviewer(privilegedClient client.Client) *TokenReviewer {
return &TokenReviewer{privilegedClient: privilegedClient}
}
func (r *TokenReviewer) WhoAmI(ctx context.Context, token string) (Identity, error) {
tokenReview := &authv1.TokenReview{
ObjectMeta: metav1.ObjectMeta{
Name: "tokenReview",
},
Spec: authv1.TokenReviewSpec{
Token: token,
},
}
err := r.privilegedClient.Create(ctx, tokenReview)
if err != nil {
return Identity{}, fmt.Errorf("failed to create token review: %w", apierrors.FromK8sError(err, "TokenReview"))
}
if !tokenReview.Status.Authenticated {
return Identity{}, apierrors.NewInvalidAuthError(errors.New("not authenticated"))
}
idKind := rbacv1.UserKind
idName := tokenReview.Status.User.Username
if isServiceAccount(tokenReview.Status.User) {
idKind = rbacv1.ServiceAccountKind
if !strings.HasPrefix(idName, serviceAccountNamePrefix) {
return Identity{}, fmt.Errorf("invalid serviceaccount name: %q", idName)
}
nameSegments := strings.Split(idName, ":")
idName = nameSegments[len(nameSegments)-1]
}
return Identity{
Name: idName,
Kind: idKind,
}, nil
}
func isServiceAccount(subject authv1.UserInfo) bool {
return contains(subject.Groups, serviceAccountsGroup)
}
func contains(groups []string, soughtGroup string) bool {
for _, group := range groups {
if group == soughtGroup {
return true
}
}
return false
}