-
Notifications
You must be signed in to change notification settings - Fork 15
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
NETOBSERV-870 implement TokenReview (#283)
* NETOBSERV-870 implement TokenReview Requires operator PR to grant permission for TokenReviews - 3 auth modes: check for cluster-admin, check for any user, no check (insecure; only for debugging/dev mode) - add tests - fix broken dev mode * Merge check implementations * Add 'auto' mode Auto mode acts either as admin or authenticated depending on the loki authtoken mode (forward => authenticated) Also improve loki errors hanfling
- Loading branch information
Showing
18 changed files
with
415 additions
and
1,621 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,123 @@ | ||
package auth | ||
|
||
import ( | ||
"context" | ||
"errors" | ||
"fmt" | ||
"net/http" | ||
"strings" | ||
|
||
"github.com/netobserv/network-observability-console-plugin/pkg/kubernetes/client" | ||
"github.com/sirupsen/logrus" | ||
authv1 "k8s.io/api/authentication/v1" | ||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||
) | ||
|
||
var hlog = logrus.WithField("module", "handler.auth") | ||
|
||
type CheckType string | ||
|
||
const ( | ||
AuthHeader = "Authorization" | ||
CheckAuthenticated CheckType = "authenticated" | ||
CheckAdmin CheckType = "admin" | ||
CheckNone CheckType = "none" | ||
) | ||
|
||
type Checker interface { | ||
CheckAuth(ctx context.Context, header http.Header) error | ||
} | ||
|
||
func NewChecker(typez CheckType, apiProvider client.APIProvider) (Checker, error) { | ||
switch typez { | ||
case CheckNone: | ||
return &NoopChecker{}, nil | ||
case CheckAuthenticated: | ||
return &BearerTokenChecker{apiProvider: apiProvider, predicates: []tokenReviewPredicate{mustBeAuthenticated}}, nil | ||
case CheckAdmin: | ||
return &BearerTokenChecker{apiProvider: apiProvider, predicates: []tokenReviewPredicate{mustBeAuthenticated, mustBeClusterAdmin}}, nil | ||
} | ||
return nil, fmt.Errorf("auth checker type unknown: %s. Must be one of %s, %s, %s", typez, CheckAdmin, CheckAuthenticated, CheckNone) | ||
} | ||
|
||
type NoopChecker struct { | ||
Checker | ||
} | ||
|
||
func (b *NoopChecker) CheckAuth(ctx context.Context, header http.Header) error { | ||
hlog.Debug("noop auth checker: ignore auth") | ||
return nil | ||
} | ||
|
||
func getUserToken(header http.Header) (string, error) { | ||
authValue := header.Get(AuthHeader) | ||
if authValue != "" { | ||
parts := strings.Split(authValue, "Bearer ") | ||
if len(parts) != 2 { | ||
return "", errors.New("missing Bearer token in Authorization header") | ||
} | ||
return parts[1], nil | ||
} | ||
return "", errors.New("missing Authorization header") | ||
} | ||
|
||
func runTokenReview(ctx context.Context, apiProvider client.APIProvider, token string, preds []tokenReviewPredicate) error { | ||
client, err := apiProvider() | ||
if err != nil { | ||
return err | ||
} | ||
|
||
rvw, err := client.CreateTokenReview(ctx, &authv1.TokenReview{ | ||
Spec: authv1.TokenReviewSpec{ | ||
Token: token, | ||
}, | ||
}, &metav1.CreateOptions{}) | ||
if err != nil { | ||
return err | ||
} | ||
for _, predFunc := range preds { | ||
if err = predFunc(rvw); err != nil { | ||
return err | ||
} | ||
} | ||
return nil | ||
} | ||
|
||
type tokenReviewPredicate func(*authv1.TokenReview) error | ||
|
||
func mustBeAuthenticated(rvw *authv1.TokenReview) error { | ||
if !rvw.Status.Authenticated { | ||
return errors.New("user not authenticated") | ||
} | ||
return nil | ||
} | ||
|
||
func mustBeClusterAdmin(rvw *authv1.TokenReview) error { | ||
for _, group := range rvw.Status.User.Groups { | ||
if group == "system:cluster-admins" { | ||
return nil | ||
} | ||
} | ||
return errors.New("user not in cluster-admins group") | ||
} | ||
|
||
type BearerTokenChecker struct { | ||
Checker | ||
apiProvider client.APIProvider | ||
predicates []tokenReviewPredicate | ||
} | ||
|
||
func (c *BearerTokenChecker) CheckAuth(ctx context.Context, header http.Header) error { | ||
hlog.Debug("Checking authenticated user") | ||
token, err := getUserToken(header) | ||
if err != nil { | ||
return err | ||
} | ||
hlog.Debug("Checking auth: token found") | ||
if err = runTokenReview(ctx, c.apiProvider, token, c.predicates); err != nil { | ||
return err | ||
} | ||
|
||
hlog.Debug("Checking auth: passed") | ||
return nil | ||
} |
Oops, something went wrong.