diff --git a/go.mod b/go.mod index 2ec5f8c6..614c2308 100644 --- a/go.mod +++ b/go.mod @@ -15,6 +15,7 @@ require ( github.com/stretchr/testify v1.8.4 go.infratographer.com/x v0.3.2 go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.42.0 + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.42.0 go.opentelemetry.io/otel v1.16.0 go.opentelemetry.io/otel/trace v1.16.0 go.uber.org/zap v1.24.0 @@ -32,6 +33,7 @@ require ( github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/envoyproxy/protoc-gen-validate v0.10.1 // indirect + github.com/felixge/httpsnoop v1.0.3 // indirect github.com/fsnotify/fsnotify v1.6.0 // indirect github.com/garsue/watermillzap v1.2.0 // indirect github.com/go-logr/logr v1.2.4 // indirect diff --git a/go.sum b/go.sum index 3df1228a..92c0f67c 100644 --- a/go.sum +++ b/go.sum @@ -95,6 +95,8 @@ github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go. github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/envoyproxy/protoc-gen-validate v0.10.1 h1:c0g45+xCJhdgFGw7a5QAfdS4byAbud7miNWJ1WwEVf8= github.com/envoyproxy/protoc-gen-validate v0.10.1/go.mod h1:DRjgyB0I43LtJapqN6NiRwroiAU2PaFuvk/vjgh61ss= +github.com/felixge/httpsnoop v1.0.3 h1:s/nj+GCswXYzN5v2DpNMuMQYe+0DDwt5WVCU6CWBdXk= +github.com/felixge/httpsnoop v1.0.3/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/frankban/quicktest v1.14.4 h1:g2rn0vABPOOXmZUj+vbmUp0lPoXEMuhTpIluN0XL9UY= github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= @@ -335,6 +337,8 @@ go.opentelemetry.io/contrib/instrumentation/github.com/labstack/echo/otelecho v0 go.opentelemetry.io/contrib/instrumentation/github.com/labstack/echo/otelecho v0.42.0/go.mod h1:5Ll2ndRzg9UNUrj1n+v4ZCcrD/SYy7BnVrlCQXECowA= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.42.0 h1:ZOLJc06r4CB42laIXg/7udr0pbZyuAihN10A/XuiQRY= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.42.0/go.mod h1:5z+/ZWJQKXa9YT34fQNx5K8Hd1EoIhvtUygUQPqEOgQ= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.42.0 h1:pginetY7+onl4qN1vl0xW/V/v6OBZ0vVdH+esuJgvmM= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.42.0/go.mod h1:XiYsayHc36K3EByOO6nbAXnAWbrUxdjUROCEeeROOH8= go.opentelemetry.io/contrib/propagators/b3 v1.17.0 h1:ImOVvHnku8jijXqkwCSyYKRDt2YrnGXD4BbhcpfbfJo= go.opentelemetry.io/otel v1.16.0 h1:Z7GVAX/UkAXPKsy94IU+i6thsQS4nb7LviLpnaNeW8s= go.opentelemetry.io/otel v1.16.0/go.mod h1:vl0h9NUa1D5s1nv3A5vZOYWn8av4K8Ml6JDeHrT/bx4= diff --git a/pkg/permissions/permissions.go b/pkg/permissions/permissions.go index ec70085c..8bc72541 100644 --- a/pkg/permissions/permissions.go +++ b/pkg/permissions/permissions.go @@ -13,6 +13,10 @@ import ( "github.com/pkg/errors" "go.infratographer.com/x/echojwtx" "go.infratographer.com/x/gidx" + "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp" + "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/codes" "go.uber.org/zap" ) @@ -37,8 +41,11 @@ var ( } defaultClient = &http.Client{ - Timeout: defaultClientTimeout, + Timeout: defaultClientTimeout, + Transport: otelhttp.NewTransport(http.DefaultTransport), } + + tracer = otel.GetTracerProvider().Tracer("go.infratographer.com/permissions-api/pkg/permissions") ) // Checker defines the checker function definition @@ -92,6 +99,15 @@ func (p *Permissions) Middleware() echo.MiddlewareFunc { func (p *Permissions) checker(c echo.Context, actor, token string) Checker { return func(ctx context.Context, resource gidx.PrefixedID, action string) error { + ctx, span := tracer.Start(ctx, "permissions.checkAccess") + defer span.End() + + span.SetAttributes( + attribute.String("permissions.actor", actor), + attribute.String("permissions.action", action), + attribute.String("permissions.resource", resource.String()), + ) + logger := p.logger.With("actor", actor, "resource", resource.String(), "action", action) values := url.Values{} @@ -103,6 +119,7 @@ func (p *Permissions) checker(c echo.Context, actor, token string) Checker { req, err := http.NewRequestWithContext(ctx, http.MethodGet, url.String(), nil) if err != nil { + span.SetStatus(codes.Error, errors.WithStack(err).Error()) logger.Errorw("failed to create checker request", "error", err) return errors.WithStack(err) @@ -128,8 +145,10 @@ func (p *Permissions) checker(c echo.Context, actor, token string) Checker { switch { case errors.Is(err, ErrPermissionDenied): logger.Warnw("unauthorized access to resource") + span.AddEvent("permission denied") case errors.Is(err, ErrBadResponse): logger.Errorw("bad response from server", "error", err, "response.status_code", resp.StatusCode, "response.body", string(body)) + span.SetStatus(codes.Error, errors.WithStack(err).Error()) } return err