英文:
Neptune throws Bad handshake error while connecting to a IAM Enabled Neptune Instance
问题
我有一个启用了 IAM 的 AWS Neptune 实例,我可以在没有身份验证的情况下执行 CRUD 操作,但是当我启用身份验证时,会出现 Bad Handshake 错误日志。
注意:Lambda 函数具有完整的 Neptune 权限
错误日志:
无法实例化新连接;将连接状态设置为关闭。
为连接池创建新连接时出错:websocket: bad handshake
'E0104: 无法建立成功的连接:websocket: bad handshake'
注意:如果禁用 IAM 身份验证,我可以执行查询。请帮忙解决。
尝试签署请求,但身份验证失败。
英文:
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.
答案1
得分: 3
在代码中有几个需要修复的地方,以便与 Neptune IAM 配合使用,前提是已经授予了所有必要的权限。
- Neptune 的 IAM 签名器中的服务名称应为
neptune-db
,而不是neptune
。 - 类型
*gremlingo.driverRemoteConnectionSettings
应为*gremlingo.DriverRemoteConnectionSettings
。 - 用于
settings.AuthInfo.Header
的标头实际上不是签名器返回的标头,而是原始请求的标头,因此应为settings.AuthInfo.Header = req.Header
。
将它们组合起来,//Signing Request
下的代码块应如下所示:
// 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
})
需要注意的一点是,gremlin-go 目前没有自动刷新身份验证令牌的方法,这意味着在令牌过期后需要建立新的连接。
希望这能有所帮助。
英文:
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.
- The service name in IAM signer for Neptune should be
neptune-db
instead ofneptune
. - The type
*gremlingo.driverRemoteConnectionSettings
should be*gremlingo.DriverRemoteConnectionSettings
. - 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 besettings.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.
答案2
得分: 1
您现在可以通过此pr进行自动刷新:https://github.com/apache/tinkerpop/pull/1989。
因此,这是一个利用新功能的代码示例。
package main
import (
"context"
"crypto/tls"
"fmt"
"net/http"
"strings"
"time"
gremlingo "github.com/apache/tinkerpop/gremlin-go/v3/driver"
v4 "github.com/aws/aws-sdk-go-v2/aws/signer/v4"
"github.com/aws/aws-sdk-go-v2/config"
)
func main() {
ctx := context.Background()
db_endpoint := "a-gremilincluster-1.cluster-ro-randomstring.us-east-1.neptune.amazonaws.com"
connString := "wss://" + db_endpoint + ":8181/gremlin"
// Signing Request
const emptyStringSHA256 = `e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855`
req, err := http.NewRequest(http.MethodGet, connString, strings.NewReader(""))
if err != nil {
return
}
cfg, err := config.LoadDefaultConfig(ctx)
if err != nil {
fmt.Println(fmt.Errorf("unable to load AWS SDK config: %w", err))
}
cr, err := cfg.Credentials.Retrieve(ctx)
if err != nil {
fmt.Println(fmt.Errorf("unable to retrieve AWS credentials: %w", err))
}
signer := v4.NewSigner()
gen := func() gremlingo.AuthInfoProvider {
err := signer.SignHTTP(ctx, cr, req, emptyStringSHA256, "neptune-db", "us-east-1", time.Now())
if err != nil {
fmt.Println(err)
}
return gremlingo.HeaderAuthInfo(req.Header)
}
auth := gremlingo.NewDynamicAuth(gen)
driverRemoteConnection, err := gremlingo.NewDriverRemoteConnection(connString,
func(settings *gremlingo.DriverRemoteConnectionSettings) {
settings.TraversalSource = "g"
settings.AuthInfo = auth
//settings.TlsConfig = &tls.Config{InsecureSkipVerify: true} Use this only if you're on a Mac running Go 1.18+ doing local dev. See https://github.com/golang/go/issues/51991
})
if err != nil {
fmt.Println(err)
return
}
// Cleanup
defer driverRemoteConnection.Close()
// Creating graph traversal
g := gremlingo.Traversal().WithRemote(driverRemoteConnection)
// Add a vertex with properties to the graph with the terminal step Iterate()
promise := g.AddV("gremlin").Property("language", "go").Iterate()
// The returned promised is a go channel to wait for all submitted steps to finish execution and return error.
err = <-promise
if err != nil {
fmt.Println(err)
return
}
// Get the value of the property
result, err := g.V().HasLabel("gremlin").Values("language").ToList()
if err != nil {
fmt.Println(err)
return
}
// Print the result
for _, r := range result {
fmt.Println(r.GetString())
}
}
英文:
You can now perform automatic refresh thanks to this pr: https://github.com/apache/tinkerpop/pull/1989.
As such, here's a code sample that takes advantage of the new functionality.
package main
import (
"context"
"crypto/tls"
"fmt"
"net/http"
"strings"
"time"
gremlingo "github.com/apache/tinkerpop/gremlin-go/v3/driver"
v4 "github.com/aws/aws-sdk-go-v2/aws/signer/v4"
"github.com/aws/aws-sdk-go-v2/config"
)
func main() {
ctx := context.Background()
db_endpoint := "a-gremilincluster-1.cluster-ro-randomstring.us-east-1.neptune.amazonaws.com"
connString := "wss://" + db_endpoint + ":8181/gremlin"
// Signing Request
const emptyStringSHA256 = `e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855`
req, err := http.NewRequest(http.MethodGet, connString, strings.NewReader(""))
if err != nil {
return
}
cfg, err := config.LoadDefaultConfig(ctx)
if err != nil {
fmt.Println(fmt.Errorf("unable to load AWS SDK config: %w", err))
}
cr, err := cfg.Credentials.Retrieve(ctx)
if err != nil {
fmt.Println(fmt.Errorf("unable to retrieve AWS credentials: %w", err))
}
signer := v4.NewSigner()
gen := func() gremlingo.AuthInfoProvider {
err := signer.SignHTTP(ctx, cr, req, emptyStringSHA256, "neptune-db", "us-east-1", time.Now())
if err != nil {
fmt.Println(err)
}
return gremlingo.HeaderAuthInfo(req.Header)
}
auth := gremlingo.NewDynamicAuth(gen)
driverRemoteConnection, err := gremlingo.NewDriverRemoteConnection(connString,
func(settings *gremlingo.DriverRemoteConnectionSettings) {
settings.TraversalSource = "g"
settings.AuthInfo = auth
//settings.TlsConfig = &tls.Config{InsecureSkipVerify: true} Use this only if you're on a Mac running Go 1.18+ doing local dev. See https://github.com/golang/go/issues/51991
})
if err != nil {
fmt.Println(err)
return
}
// Cleanup
defer driverRemoteConnection.Close()
// Creating graph traversal
g := gremlingo.Traversal_().WithRemote(driverRemoteConnection)
// Add a vertex with properties to the graph with the terminal step Iterate()
promise := g.AddV("gremlin").Property("language", "go").Iterate()
// The returned promised is a go channel to wait for all submitted steps to finish execution and return error.
err = <-promise
if err != nil {
fmt.Println(err)
return
}
// Get the value of the property
result, err := g.V().HasLabel("gremlin").Values("language").ToList()
if err != nil {
fmt.Println(err)
return
}
// Print the result
for _, r := range result {
fmt.Println(r.GetString())
}
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论