amazon-web-servicesgogremlinamazon-neptune

Neptune throws Bad handshake error while connecting to a IAM Enabled Neptune Instance


I have an IAM Enabled AWS Neptune instance, I am able to perform crud operations without authentication but when I Enabled authentication it's throws Bad Handshake error logs.

Note: Lambda function has Full Neptune permissions

package main

import (
    "fmt"
    "log"
    "net/http"
    "os"
    "time"
    
    "github.com/aws/aws-lambda-go/events"
    "github.com/aws/aws-lambda-go/lambda"
    
    gremlingo "github.com/apache/tinkerpop/gremlin-go/v3/driver"
    "github.com/aws/aws-sdk-go/aws/session"
    v4 "github.com/aws/aws-sdk-go/aws/signer/v4"
    )

func main() {
    lambda.Start(lambdaHandler)
}

func lambdaHandler(ctx context.Context, request events.APIGatewayProxyRequest) (events.APIGatewayProxyResponse, error) {
    driverConn, g = connect()
    result, err = g.AddV("User").Property("userId", "Check").Next()
    if err != nil {
        fmt.Println(err)
    }
}

func connect() {
    awsSess, err := session.NewSesionWithOptions(session.Options{
        SharedCondfigState: session.SharedConfigEnable,
    }),
    if err != nil {
        log.Fatalf("Failed to creating session: %s", err)
    }
    
    db_endpoint := os.Genenv("DB_ENDPOINT")
    connString := "wss://" +db_endpoint+":8182/gremlin"
    
    // Signing Request
    req, _ := http.NewRequest(http.MethodGet, connString, nil)
    signer := v4.NewSigner(awsSess.Config.Credentials)
    headerToUse, err := signer.Sign(req, nil, "neptune", *awsSess.Config.Region, time.Now())
    
    driverRemoteConnection, err := gremlingo.NewDriverRemoteConnection(connString,
        func(settings *gremlingo.driverRemoteConnectionSettings) {
            settings.TraversalSource = "g"
            settings.AuthInfo.Header = headerToUse
        })
    return driverRemoteConnection, traversalSource(driverRemoteConnection)
}

func traversalSource(driverConn *gremlingo.DriverRemoteConnection) *gremlingo.GraphTraversalSource {
    return gremlingo.Traversal_().WithRemote(driverConn)
}

Error Logs: Failed to instantiate the new connection; setting connection state to closed. Error creating new connection for connection pool: websocket: bad handshake 'E0104: no successful connections could be made: websocket: bad handshake'

Note: I am able to execute queries if IAM Authentication is disabled. Please help.

Tried signing request but unable to authentication is failing.


Solution

  • There are a couple of things to fix in the code that should get it working with Neptune IAM, provided all necessary permissions are granted.

    1. The service name in IAM signer for Neptune should be neptune-db instead of neptune.
    2. The type *gremlingo.driverRemoteConnectionSettings should be *gremlingo.DriverRemoteConnectionSettings.
    3. The header to use for settings.AuthInfo.Header is actually not the header returned by the signer, but the header of the original request, so it should be settings.AuthInfo.Header = req.Header.

    To put it together, the chunk of code under //Signing Request would look like this:

        // Signing Request
        req, _ := http.NewRequest(http.MethodGet, connString, nil)
        signer := v4.NewSigner(awsSess.Config.Credentials)
        _, err := signer.Sign(req, nil, "neptune-db", *awsSess.Config.Region, time.Now())
        
        driverRemoteConnection, err := gremlingo.NewDriverRemoteConnection(connString,
            func(settings *gremlingo.DriverRemoteConnectionSettings) {
                settings.TraversalSource = "g"
                settings.AuthInfo.Header = req.Header
            })
    

    One thing to note is gremlin-go currently don't have a way to allow automatic refresh of the auth token, which means a new connection will have to be made after expiry.

    Hopefully this helps.