Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Propagate the bearer token to the gRPC plugin server #1822

Merged
33 changes: 33 additions & 0 deletions plugin/storage/grpc/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -112,3 +112,36 @@ There are more logger options that can be used with `hclog` listed on [godoc](ht

Note: Setting the `Output` option to `os.Stdout` can confuse the `go-plugin` framework and lead it to consider the plugin
errored.

Bearer token propagation from the UI
------------------------------------
When using `--query.bearer-token-propagation=true`, the bearer token will be properly passed on to the gRPC plugin server. To get access to the bearer token in your plugin, use a method similar to:

```golang
import (
// ... other imports
"fmt"
"github.com/jaegertracing/jaeger/storage/spanstore"
"google.golang.org/grpc/metadata"
)

// ... spanReader type declared here

func (r *spanReader) extractBearerToken(ctx context.Context) (string, bool) {
if md, ok := metadata.FromIncomingContext(ctx); ok {
values := md.Get(spanstore.BearerTokenKey)
if len(values) > 0 {
return values[0], true
}
}
return "", false
}

// ... spanReader interface implementation

func (r *spanReader) GetServices(ctx context.Context) ([]string, error) {
str, ok := r.extractBearerToken(ctx)
fmt.Println(fmt.Sprintf("spanReader.GetServices: bearer-token: '%s', wasGiven: '%t'" str, ok))
// ...
}
```
25 changes: 20 additions & 5 deletions plugin/storage/grpc/shared/grpc_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"time"

"github.com/pkg/errors"
"google.golang.org/grpc/metadata"

"github.com/jaegertracing/jaeger/model"
"github.com/jaegertracing/jaeger/proto-gen/storage_v1"
Expand All @@ -34,6 +35,20 @@ type grpcClient struct {
depsReaderClient storage_v1.DependenciesReaderPluginClient
}

// upgradeContextWithBearerToken turns the context into a gRPC outgoing context with bearer token
// in the request metadata, if the original context has bearer token attached.
// Otherwise returns original context.
func upgradeContextWithBearerToken(ctx context.Context) context.Context {
bearerToken, hasToken := spanstore.GetBearerToken(ctx)
if hasToken {
requestMetadata := metadata.New(map[string]string{
spanstore.BearerTokenKey: bearerToken,
})
return metadata.NewOutgoingContext(ctx, requestMetadata)
}
return ctx
}

// DependencyReader implements shared.StoragePlugin.
func (c *grpcClient) DependencyReader() dependencystore.Reader {
return c
Expand All @@ -51,7 +66,7 @@ func (c *grpcClient) SpanWriter() spanstore.Writer {

// GetTrace takes a traceID and returns a Trace associated with that traceID
func (c *grpcClient) GetTrace(ctx context.Context, traceID model.TraceID) (*model.Trace, error) {
stream, err := c.readerClient.GetTrace(ctx, &storage_v1.GetTraceRequest{
stream, err := c.readerClient.GetTrace(upgradeContextWithBearerToken(ctx), &storage_v1.GetTraceRequest{
TraceID: traceID,
})
if err != nil {
Expand All @@ -74,7 +89,7 @@ func (c *grpcClient) GetTrace(ctx context.Context, traceID model.TraceID) (*mode

// GetServices returns a list of all known services
func (c *grpcClient) GetServices(ctx context.Context) ([]string, error) {
resp, err := c.readerClient.GetServices(ctx, &storage_v1.GetServicesRequest{})
resp, err := c.readerClient.GetServices(upgradeContextWithBearerToken(ctx), &storage_v1.GetServicesRequest{})
if err != nil {
return nil, errors.Wrap(err, "plugin error")
}
Expand All @@ -84,7 +99,7 @@ func (c *grpcClient) GetServices(ctx context.Context) ([]string, error) {

// GetOperations returns the operations of a given service
func (c *grpcClient) GetOperations(ctx context.Context, service string) ([]string, error) {
resp, err := c.readerClient.GetOperations(ctx, &storage_v1.GetOperationsRequest{
resp, err := c.readerClient.GetOperations(upgradeContextWithBearerToken(ctx), &storage_v1.GetOperationsRequest{
Service: service,
})
if err != nil {
Expand All @@ -96,7 +111,7 @@ func (c *grpcClient) GetOperations(ctx context.Context, service string) ([]strin

// FindTraces retrieves traces that match the traceQuery
func (c *grpcClient) FindTraces(ctx context.Context, query *spanstore.TraceQueryParameters) ([]*model.Trace, error) {
stream, err := c.readerClient.FindTraces(context.Background(), &storage_v1.FindTracesRequest{
yurishkuro marked this conversation as resolved.
Show resolved Hide resolved
stream, err := c.readerClient.FindTraces(upgradeContextWithBearerToken(ctx), &storage_v1.FindTracesRequest{
Query: &storage_v1.TraceQueryParameters{
ServiceName: query.ServiceName,
OperationName: query.OperationName,
Expand Down Expand Up @@ -134,7 +149,7 @@ func (c *grpcClient) FindTraces(ctx context.Context, query *spanstore.TraceQuery

// FindTraceIDs retrieves traceIDs that match the traceQuery
func (c *grpcClient) FindTraceIDs(ctx context.Context, query *spanstore.TraceQueryParameters) ([]model.TraceID, error) {
resp, err := c.readerClient.FindTraceIDs(context.Background(), &storage_v1.FindTraceIDsRequest{
resp, err := c.readerClient.FindTraceIDs(upgradeContextWithBearerToken(ctx), &storage_v1.FindTraceIDsRequest{
Query: &storage_v1.TraceQueryParameters{
ServiceName: query.ServiceName,
OperationName: query.OperationName,
Expand Down
4 changes: 3 additions & 1 deletion storage/spanstore/token_propagation.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@ import "context"

type contextKey string

const bearerToken = contextKey("bearer.token")
// BearerTokenKey is the string literal used internally in the implementation of this context.
const BearerTokenKey = "bearer.token"
yurishkuro marked this conversation as resolved.
Show resolved Hide resolved
const bearerToken = contextKey(BearerTokenKey)

// StoragePropagationKey is a key for viper configuration to pass this option to storage plugins.
const StoragePropagationKey = "storage.propagate.token"
Expand Down