diff --git a/agent/pkg/controllers/status_controller.go b/agent/pkg/controllers/status_controller.go index e7f5bbc32..2965acf17 100644 --- a/agent/pkg/controllers/status_controller.go +++ b/agent/pkg/controllers/status_controller.go @@ -34,3 +34,13 @@ func PostTappedPods(c *gin.Context) { func GetTappersCount(c *gin.Context) { c.JSON(http.StatusOK, providers.TappersCount) } + +func GetAuthStatus(c *gin.Context) { + authStatus, err := providers.GetAuthStatus() + if err != nil { + c.JSON(http.StatusInternalServerError, err) + return + } + + c.JSON(http.StatusOK, authStatus) +} diff --git a/agent/pkg/providers/auth_provider.go b/agent/pkg/providers/auth_provider.go new file mode 100644 index 000000000..05bfc2d2d --- /dev/null +++ b/agent/pkg/providers/auth_provider.go @@ -0,0 +1,29 @@ +package providers + +import ( + "encoding/json" + "fmt" + "github.com/up9inc/mizu/shared" + "os" +) + +var authStatus *shared.AuthStatus + +func GetAuthStatus() (*shared.AuthStatus, error) { + if authStatus == nil { + authStatus = &shared.AuthStatus{} + + authStatusJson := os.Getenv(shared.AuthStatusEnvVar) + if authStatusJson == "" { + return authStatus, nil + } + + err := json.Unmarshal([]byte(authStatusJson), authStatus) + if err != nil { + authStatus = nil + return nil, fmt.Errorf("failed to marshal auth status, err: %v", err) + } + } + + return authStatus, nil +} diff --git a/agent/pkg/routes/status_routes.go b/agent/pkg/routes/status_routes.go index 4271332b4..8ae559d60 100644 --- a/agent/pkg/routes/status_routes.go +++ b/agent/pkg/routes/status_routes.go @@ -11,4 +11,6 @@ func StatusRoutes(ginApp *gin.Engine) { routeGroup.POST("/tappedPods", controllers.PostTappedPods) routeGroup.GET("/tappersCount", controllers.GetTappersCount) + + routeGroup.GET("/auth", controllers.GetAuthStatus) } diff --git a/cli/auth/authProvider.go b/cli/auth/authProvider.go index 5a9b89a92..f5d7b979c 100644 --- a/cli/auth/authProvider.go +++ b/cli/auth/authProvider.go @@ -23,14 +23,9 @@ const loginTimeoutInMin = 2 var listenPorts = []int{3141, 4001, 5002, 6003, 7004, 8005, 9006, 10007} func IsTokenExpired(tokenString string) (bool, error) { - token, _, err := new(jwt.Parser).ParseUnverified(tokenString, jwt.MapClaims{}) + claims, err := getTokenClaims(tokenString) if err != nil { - return true, fmt.Errorf("failed to parse token, err: %v", err) - } - - claims, ok := token.Claims.(jwt.MapClaims) - if !ok { - return true, fmt.Errorf("can't convert token's claims to standard claims") + return true, err } expiry := time.Unix(int64(claims["exp"].(float64)), 0) @@ -38,6 +33,29 @@ func IsTokenExpired(tokenString string) (bool, error) { return time.Now().After(expiry), nil } +func GetTokenEmail(tokenString string) (string, error) { + claims, err := getTokenClaims(tokenString) + if err != nil { + return "", err + } + + return claims["email"].(string), nil +} + +func getTokenClaims(tokenString string) (jwt.MapClaims, error) { + token, _, err := new(jwt.Parser).ParseUnverified(tokenString, jwt.MapClaims{}) + if err != nil { + return nil, fmt.Errorf("failed to parse token, err: %v", err) + } + + claims, ok := token.Claims.(jwt.MapClaims) + if !ok { + return nil, fmt.Errorf("can't convert token's claims to standard claims") + } + + return claims, nil +} + func Login() error { token, loginErr := loginInteractively() if loginErr != nil { diff --git a/cli/cmd/tapRunner.go b/cli/cmd/tapRunner.go index 2e971facb..27637c47c 100644 --- a/cli/cmd/tapRunner.go +++ b/cli/cmd/tapRunner.go @@ -3,6 +3,7 @@ package cmd import ( "context" "fmt" + "github.com/up9inc/mizu/cli/auth" "path" "regexp" "strings" @@ -48,6 +49,12 @@ func RunMizuTap() { return } + authStatus, err := getAuthStatus() + if err != nil { + logger.Log.Errorf(uiUtils.Error, fmt.Sprintf("Error getting auth status: %v", errormessage.FormatError(err))) + return + } + var mizuValidationRules string if config.Config.Tap.EnforcePolicyFile != "" { mizuValidationRules, err = readValidationRules(config.Config.Tap.EnforcePolicyFile) @@ -103,7 +110,7 @@ func RunMizuTap() { } defer finishMizuExecution(kubernetesProvider) - if err := createMizuResources(ctx, kubernetesProvider, mizuApiFilteringOptions, mizuValidationRules); err != nil { + if err := createMizuResources(ctx, kubernetesProvider, mizuApiFilteringOptions, mizuValidationRules, authStatus); err != nil { logger.Log.Errorf(uiUtils.Error, fmt.Sprintf("Error creating resources: %v", errormessage.FormatError(err))) return } @@ -125,14 +132,14 @@ func readValidationRules(file string) (string, error) { return string(newContent), nil } -func createMizuResources(ctx context.Context, kubernetesProvider *kubernetes.Provider, mizuApiFilteringOptions *api.TrafficFilteringOptions, mizuValidationRules string) error { +func createMizuResources(ctx context.Context, kubernetesProvider *kubernetes.Provider, mizuApiFilteringOptions *api.TrafficFilteringOptions, mizuValidationRules string, authStatus *shared.AuthStatus) error { if !config.Config.IsNsRestrictedMode() { if err := createMizuNamespace(ctx, kubernetesProvider); err != nil { return err } } - if err := createMizuApiServer(ctx, kubernetesProvider, mizuApiFilteringOptions); err != nil { + if err := createMizuApiServer(ctx, kubernetesProvider, mizuApiFilteringOptions, authStatus); err != nil { return err } @@ -153,7 +160,7 @@ func createMizuNamespace(ctx context.Context, kubernetesProvider *kubernetes.Pro return err } -func createMizuApiServer(ctx context.Context, kubernetesProvider *kubernetes.Provider, mizuApiFilteringOptions *api.TrafficFilteringOptions) error { +func createMizuApiServer(ctx context.Context, kubernetesProvider *kubernetes.Provider, mizuApiFilteringOptions *api.TrafficFilteringOptions, authStatus *shared.AuthStatus) error { var err error state.mizuServiceAccountExists, err = createRBACIfNecessary(ctx, kubernetesProvider) @@ -175,6 +182,7 @@ func createMizuApiServer(ctx context.Context, kubernetesProvider *kubernetes.Pro ServiceAccountName: serviceAccountName, IsNamespaceRestricted: config.Config.IsNsRestrictedMode(), MizuApiFilteringOptions: mizuApiFilteringOptions, + AuthStatus: authStatus, MaxEntriesDBSizeBytes: config.Config.Tap.MaxEntriesDBSizeBytes(), Resources: config.Config.Tap.ApiServerResources, ImagePullPolicy: config.Config.ImagePullPolicy(), @@ -215,6 +223,22 @@ func getMizuApiFilteringOptions() (*api.TrafficFilteringOptions, error) { }, nil } +func getAuthStatus() (*shared.AuthStatus, error) { + if config.Config.Tap.Workspace == "" { + return &shared.AuthStatus{}, nil + } + + email, err := auth.GetTokenEmail(config.Config.Auth.Token) + if err != nil { + return nil, err + } + + return &shared.AuthStatus{ + Email: email, + Model: config.Config.Tap.Workspace, + }, nil +} + func updateMizuTappers(ctx context.Context, kubernetesProvider *kubernetes.Provider, mizuApiFilteringOptions *api.TrafficFilteringOptions) error { nodeToTappedPodIPMap := getNodeHostToTappedPodIpsMap(state.currentlyTappedPods) diff --git a/cli/kubernetes/provider.go b/cli/kubernetes/provider.go index 5f361fe73..49dbbd08f 100644 --- a/cli/kubernetes/provider.go +++ b/cli/kubernetes/provider.go @@ -152,6 +152,7 @@ type ApiServerOptions struct { ServiceAccountName string IsNamespaceRestricted bool MizuApiFilteringOptions *api.TrafficFilteringOptions + AuthStatus *shared.AuthStatus MaxEntriesDBSizeBytes int64 Resources configStructs.Resources ImagePullPolicy core.PullPolicy @@ -162,6 +163,12 @@ func (provider *Provider) CreateMizuApiServerPod(ctx context.Context, opts *ApiS if err != nil { return nil, err } + + marshaledAuthStatus, err := json.Marshal(opts.AuthStatus) + if err != nil { + return nil, err + } + configMapVolumeName := &core.ConfigMapVolumeSource{} configMapVolumeName.Name = mizu.ConfigMapName configMapOptional := true @@ -217,6 +224,10 @@ func (provider *Provider) CreateMizuApiServerPod(ctx context.Context, opts *ApiS Name: shared.MizuFilteringOptionsEnvVar, Value: string(marshaledFilteringOptions), }, + { + Name: shared.AuthStatusEnvVar, + Value: string(marshaledAuthStatus), + }, { Name: shared.MaxEntriesDBSizeBytesEnvVar, Value: strconv.FormatInt(opts.MaxEntriesDBSizeBytes, 10), diff --git a/shared/consts.go b/shared/consts.go index 4241c6314..57ba71aec 100644 --- a/shared/consts.go +++ b/shared/consts.go @@ -2,6 +2,7 @@ package shared const ( MizuFilteringOptionsEnvVar = "SENSITIVE_DATA_FILTERING_OPTIONS" + AuthStatusEnvVar = "AUTH_STATUS" HostModeEnvVar = "HOST_MODE" NodeNameEnvVar = "NODE_NAME" TappedAddressesPerNodeDictEnvVar = "TAPPED_ADDRESSES_PER_HOST" diff --git a/shared/models.go b/shared/models.go index 73ab4041c..28c577e5b 100644 --- a/shared/models.go +++ b/shared/models.go @@ -56,6 +56,11 @@ type TLSLinkInfo struct { ResolvedSourceName string `json:"resolvedSourceName"` } +type AuthStatus struct { + Email string `json:"email"` + Model string `json:"model"` +} + func CreateWebSocketStatusMessage(tappingStatus TapStatus) WebSocketStatusMessage { return WebSocketStatusMessage{ WebSocketMessageMetadata: &WebSocketMessageMetadata{