Skip to content

Commit

Permalink
Merge pull request #2 from computate/kruizeproject
Browse files Browse the repository at this point in the history
Add support for exported_namespace GPU metrics filter and better logging to prom-keycloak-proxy
  • Loading branch information
computate authored Jul 19, 2024
2 parents 28fad56 + d8e7554 commit 3979240
Show file tree
Hide file tree
Showing 3 changed files with 99 additions and 23 deletions.
25 changes: 18 additions & 7 deletions queries/parse.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ func InjectMatcher(q url.Values, matcher *labels.Matcher) error {
return nil
}

func AppendMatcher(queryValues url.Values, queryValuesForAuth url.Values, key string, defaultValue string) error {
func AppendMatcher(queryValues url.Values, queryValuesForAuth url.Values, key string, authKey string, defaultValue string) (string, string, error) {
value := defaultValue
matchers := queryValues[QueryParam]
for _, matcher := range matchers {
Expand All @@ -76,21 +76,32 @@ func AppendMatcher(queryValues url.Values, queryValuesForAuth url.Values, key st
}
}
matcher := &labels.Matcher{
Name: key,
Name: authKey,
Type: labels.MatchRegexp,
Value: LabelValuesToRegexpString([]string{value}),
}
err := InjectMatcher(queryValuesForAuth, matcher)
return err
return authKey, value, err
}

func ParseAuthorizations(queryValues url.Values) url.Values {
func ParseAuthorizations(queryValues url.Values) (url.Values, []string, []string) {
queryValuesForAuth := make(url.Values)

AppendMatcher(queryValues, queryValuesForAuth, "cluster", "all clusters")
AppendMatcher(queryValues, queryValuesForAuth, "namespace", "all namespaces")
var keys []string
var values []string
cluster_key, cluster, _ := AppendMatcher(queryValues, queryValuesForAuth, "cluster", "cluster", "all clusters")
keys = append(keys, cluster_key)
values = append(values, cluster)

return queryValuesForAuth
exported_namespace_key, exported_namespace, _ := AppendMatcher(queryValues, queryValuesForAuth, "exported_namespace", "namespace", "all namespaces")
keys = append(keys, exported_namespace_key)
values = append(values, exported_namespace)

namespace_key, namespace, _ := AppendMatcher(queryValues, queryValuesForAuth, "namespace", "namespace", exported_namespace)
keys = append(keys, namespace_key)
values = append(values, namespace)

return queryValuesForAuth, keys, values
}

func QueryPrometheus(prometheusTlsCertPath string, prometheusTlsKeyPath string,
Expand Down
96 changes: 81 additions & 15 deletions services/authService.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"crypto/tls"
"encoding/json"
"net/http"
"slices"
"strings"

"github.com/OCP-on-NERC/prom-keycloak-proxy/errors"
Expand Down Expand Up @@ -66,6 +67,27 @@ func Protect(gocloakClient *gocloak.GoCloak, authRealm string, authClientId stri
return
}

userInfo, err := gocloakClient.GetUserInfo(context.Background(), accessToken, authRealm)
if err != nil {
log.Warn().
Int("status", 401).
Str("method", r.Method).
Str("path", r.RequestURI).
Str("ip", r.RemoteAddr).
Str("client-id", authClientId).
Str("query", query).
Msg("Unauthorized")

w.WriteHeader(401)
json.NewEncoder(w).Encode(errors.BadRequestError(err.Error()))
return
}
username := *userInfo.PreferredUsername
var userClientId string = ""
if strings.Contains(username, "service-account-") {
userClientId = strings.ReplaceAll(username, "service-account-", "")
}

isTokenValid := *rptResult.Active

if !isTokenValid {
Expand All @@ -74,7 +96,8 @@ func Protect(gocloakClient *gocloak.GoCloak, authRealm string, authClientId stri
Str("method", r.Method).
Str("path", r.RequestURI).
Str("ip", r.RemoteAddr).
Str("client-id", authClientId).
Str("username", username).
Str("client-id", userClientId).
Str("query", query).
Msg("Unauthorized")

Expand All @@ -84,7 +107,7 @@ func Protect(gocloakClient *gocloak.GoCloak, authRealm string, authClientId stri
}

queryValues := r.URL.Query()
queryValuesForAuth := queries.ParseAuthorizations(queryValues)
queryValuesForAuth, keys, values := queries.ParseAuthorizations(queryValues)
matchers := queryValuesForAuth[queries.QueryParam]
var permissions []string

Expand All @@ -107,15 +130,16 @@ func Protect(gocloakClient *gocloak.GoCloak, authRealm string, authClientId stri
},
)

if err != nil || len(*rpp) < 2 {
if err != nil {
log.Warn().
Int("status", 403).
Str("method", r.Method).
Str("path", r.RequestURI).
Str("ip", r.RemoteAddr).
Str("client-id", authClientId).
Str("username", username).
Str("client-id", userClientId).
Str("query", query).
Msg("Forbidden")
Msg(err.Error())

w.WriteHeader(403)
json.NewEncoder(w).Encode(errors.UnauthorizedError())
Expand All @@ -129,7 +153,8 @@ func Protect(gocloakClient *gocloak.GoCloak, authRealm string, authClientId stri
Str("method", r.Method).
Str("path", r.RequestURI).
Str("ip", r.RemoteAddr).
Str("client-id", authClientId).
Str("username", username).
Str("client-id", userClientId).
Str("query", query).
Msg("Bad Request")

Expand All @@ -138,15 +163,56 @@ func Protect(gocloakClient *gocloak.GoCloak, authRealm string, authClientId stri
return
}

log.Info().
Int("status", 200).
Str("method", r.Method).
Str("path", r.RequestURI).
Str("ip", r.RemoteAddr).
Str("client-id", authClientId).
Str("query", query).
RawJSON("permissions", out).
Msg("OK")
var final_result bool = true
var unauthorized_key string = ""
var unauthorized_value string = ""
for i, key := range keys {
value := values[i]
current_result := false
for _, permission := range *rpp {
if key == *permission.ResourceName && slices.Contains(*permission.Scopes, value) {
current_result = true
break
}
}
if !current_result {
final_result = false
unauthorized_key = key
unauthorized_value = value
break
}
}

if final_result {
log.Info().
Int("status", 200).
Str("method", r.Method).
Str("path", r.RequestURI).
Str("ip", r.RemoteAddr).
Str("username", username).
Str("client-id", userClientId).
Str("query", query).
RawJSON("permissions", out).
Msg("OK")
} else {
message := "You are not authorized to access the resource \"" + unauthorized_key + "\" with scope \"" + unauthorized_value + "\""
log.Warn().
Int("status", 403).
Str("method", r.Method).
Str("path", r.RequestURI).
Str("ip", r.RemoteAddr).
Str("username", username).
Str("client-id", userClientId).
Str("query", query).
Msg(message)

w.WriteHeader(403)
json.NewEncoder(w).Encode(errors.HttpError{
Code: 403,
Error: "Forbidden",
Message: message})
return
}

// Our middleware logic goes here...
next.ServeHTTP(w, r)
Expand Down
1 change: 0 additions & 1 deletion services/promService.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ func PromQueryHandler(gocloakClient *gocloak.GoCloak, authRealm string, authClie

queryValues := r.URL.Query()
matchers := queryValues[queries.QueryParam]
//v := make(url.Values)
for _, matcher := range matchers {
expr, _ := parser.ParseExpr(matcher)
queryValues.Set(queries.QueryParam, expr.String())
Expand Down

0 comments on commit 3979240

Please sign in to comment.