Skip to content

Commit

Permalink
Add health endpoints on the order and stocks service
Browse files Browse the repository at this point in the history
  • Loading branch information
kchiranjewee63 committed Jul 18, 2024
1 parent a580ff5 commit 0317bb9
Show file tree
Hide file tree
Showing 9 changed files with 62 additions and 21 deletions.
5 changes: 0 additions & 5 deletions deploy/alpha-stocks-dev/deploy.sh
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,5 @@ envsubst < ./deployments/gateway-deployment.yaml | kubectl apply -f -

if [ "$ENABLE_TRATS" = "true" ]; then
kubectl apply -f tratteria/kubernetes
fi


if [ "$ENABLE_TRATS" = "true" ]; then
sleep 20
kubectl apply -f trats
fi
1 change: 1 addition & 0 deletions order/cmd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ func main() {
}

func (a *App) initializeRoutes(handlers *handler.Handlers) {
a.Router.HandleFunc("/health", handlers.HealthCheckHandler).Methods("GET")
a.Router.HandleFunc("/api/order", handlers.OrderHandler).Methods("POST")
a.Router.HandleFunc("/api/order/{id}", handlers.GetOrderDetailsHandler).Methods("GET")
}
8 changes: 8 additions & 0 deletions order/handler/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,14 @@ type OrderRequest struct {
Quantity int `json:"quantity"`
}

func (h *Handlers) HealthCheckHandler(w http.ResponseWriter, r *http.Request) {
h.Logger.Info("Health check request received.")

w.WriteHeader(http.StatusOK)
w.Header().Set("Content-Type", "application/json")
w.Write([]byte(`{"status":"healthy"}`))
}

func (h *Handlers) OrderHandler(w http.ResponseWriter, r *http.Request) {
h.Logger.Info("Order request received.")

Expand Down
6 changes: 6 additions & 0 deletions order/pkg/authz/policies.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@ import (
"github.com/spiffe/go-spiffe/v2/spiffeid"
)

func GetPublicEndpoints() []string {
return []string{
"/health",
}
}

func GetSpiffeAccessControlPolicies(orderConfig *config.OrderConfig) map[spiffeid.ID]map[string][]string {
return map[spiffeid.ID]map[string][]string{
orderConfig.SpiffeIDs.Gateway: {
Expand Down
24 changes: 16 additions & 8 deletions order/pkg/middleware/spiffemiddleware.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package middleware

import (
"net/http"
"slices"
"strings"

"github.com/gorilla/mux"
Expand All @@ -14,10 +15,25 @@ import (
)

func spiffeMiddleware(orderConfig *config.OrderConfig, spireJwtSource *workloadapi.JWTSource, logger *zap.Logger) func(http.Handler) http.Handler {
publicEndpoints := authz.GetPublicEndpoints()
policies := authz.GetSpiffeAccessControlPolicies(orderConfig)

return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
routePath, err := mux.CurrentRoute(r).GetPathTemplate()
if err != nil {
logger.Error("Error retrieving the route path template:", zap.Error(err))
http.Error(w, "Internal Server Error", http.StatusInternalServerError)

return
}

if slices.Contains(publicEndpoints, routePath) {
next.ServeHTTP(w, r)

return
}

token := strings.TrimPrefix(r.Header.Get("Authorization"), "Bearer ")
if token == "" {
logger.Error("JWT-SVID token not provided.")
Expand All @@ -36,14 +52,6 @@ func spiffeMiddleware(orderConfig *config.OrderConfig, spireJwtSource *workloada

logger.Info("Successfully authenticated a request.", zap.String("spiffeID", svid.ID.String()))

routePath, err := mux.CurrentRoute(r).GetPathTemplate()
if err != nil {
logger.Error("Error retrieving the route path template:", zap.Error(err))
http.Error(w, "Internal Server Error", http.StatusInternalServerError)

return
}

if !authz.IsSpiffeIDAuthorized(svid.ID, r.Method, routePath, policies) {
logger.Error("Unauthorized access attempt.", zap.String("spiffeID", svid.ID.String()), zap.String("path", routePath), zap.String("method", r.Method))
http.Error(w, "Forbidden: Access not permited to the resource", http.StatusForbidden)
Expand Down
1 change: 1 addition & 0 deletions stocks/cmd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ func main() {
}

func (a *App) initializeRoutes(handlers *handler.Handlers) {
a.Router.HandleFunc("/health", handlers.HealthCheckHandler).Methods("GET")
a.Router.HandleFunc("/api/stocks/search", handlers.SearchStocksHandler).Methods("GET")
a.Router.HandleFunc("/api/stocks/holdings", handlers.GetUserHoldingsHandler).Methods("GET")
a.Router.HandleFunc("/api/stocks/details/{id}", handlers.GetStockDetailsHandler).Methods("GET")
Expand Down
8 changes: 8 additions & 0 deletions stocks/handler/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,14 @@ type UpdateRequest struct {
Quantity int `json:"quantity"`
}

func (h *Handlers) HealthCheckHandler(w http.ResponseWriter, r *http.Request) {
h.Logger.Info("Health check request received.")

w.WriteHeader(http.StatusOK)
w.Header().Set("Content-Type", "application/json")
w.Write([]byte(`{"status":"healthy"}`))
}

func (h *Handlers) SearchStocksHandler(w http.ResponseWriter, r *http.Request) {
query := r.URL.Query().Get("query")
if query == "" {
Expand Down
6 changes: 6 additions & 0 deletions stocks/pkg/authz/policies.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@ import (
"github.com/spiffe/go-spiffe/v2/spiffeid"
)

func GetPublicEndpoints() []string {
return []string{
"/health",
}
}

func GetSpiffeAccessControlPolicies(stocksConfig *config.StocksConfig) map[spiffeid.ID]map[string][]string {
return map[spiffeid.ID]map[string][]string{
stocksConfig.SpiffeIDs.Gateway: {
Expand Down
24 changes: 16 additions & 8 deletions stocks/pkg/middleware/spiffemiddleware.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package middleware

import (
"net/http"
"slices"
"strings"

"github.com/gorilla/mux"
Expand All @@ -14,10 +15,25 @@ import (
)

func getSpiffeMiddleware(stocksConfig *config.StocksConfig, spireJwtSource *workloadapi.JWTSource, logger *zap.Logger) func(http.Handler) http.Handler {
publicEndpoints := authz.GetPublicEndpoints()
policies := authz.GetSpiffeAccessControlPolicies(stocksConfig)

return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
routePath, err := mux.CurrentRoute(r).GetPathTemplate()
if err != nil {
logger.Error("Error retrieving the route path template:", zap.Error(err))
http.Error(w, "Internal Server Error", http.StatusInternalServerError)

return
}

if slices.Contains(publicEndpoints, routePath) {
next.ServeHTTP(w, r)

return
}

token := strings.TrimPrefix(r.Header.Get("Authorization"), "Bearer ")
if token == "" {
logger.Error("JWT-SVID token not provided.")
Expand All @@ -36,14 +52,6 @@ func getSpiffeMiddleware(stocksConfig *config.StocksConfig, spireJwtSource *work

logger.Info("Successfully authenticated a request.", zap.String("spiffeID", svid.ID.String()))

routePath, err := mux.CurrentRoute(r).GetPathTemplate()
if err != nil {
logger.Error("Error retrieving the route path template:", zap.Error(err))
http.Error(w, "Internal Server Error", http.StatusInternalServerError)

return
}

if !authz.IsSpiffeIDAuthorized(svid.ID, r.Method, routePath, policies) {
logger.Error("Unauthorized access attempt", zap.String("spiffeID", svid.ID.String()), zap.String("path", routePath), zap.String("method", r.Method))
http.Error(w, "Forbidden: Access not permited to the resource", http.StatusForbidden)
Expand Down

0 comments on commit 0317bb9

Please sign in to comment.