I am trying to connect to a mongo database hosted in azure using the .crt file.
I am successfully able to connect from my linux machine terminal using command:
mongo mongodb://username:password#prod-replicaset-0.com:27017,prod-replicaset-1.com:27017,prod-replicaset-2.com:27017/ --tls --tlsCAFile rootca.crt --tlsAllowInvalidCertificates
I am also able to connect from mongo UI client like robo3T by setting "Use SSL protocol" and using Auth Mechanism as "SCRAM-SHA-256".
[If I set Auth Mechanism to any other value, results in Authentication Failure]
But I am not able to connect to that database in Go lang code.
Here is a sample of code I am using:
package main
import (
"crypto/tls"
"crypto/x509"
"io/ioutil"
"log"
"net"
"github.com/globalsign/mgo"
)
func InitMongo() error {
rootCerts := x509.NewCertPool()
ca, err := ioutil.ReadFile("./rootca.crt")
if err != nil {
log.Fatalf("failed to read file : %s", err.Error())
return err
}
success := rootCerts.AppendCertsFromPEM(ca)
if !success {
log.Printf("rootcert failed")
}
connStr := "mongodb://username:password#prod-replicaset-0.com:27017,prod-replicaset-1.com:27017,prod-replicaset-2.com:27017/?ssl=true"
dbDialInfo, err := mgo.ParseURL(connStr)
if err != nil {
log.Fatal("unable to parse url - " + err.Error())
}
dbDialInfo.DialServer = func(addr *mgo.ServerAddr) (net.Conn, error) {
return tls.Dial("tcp", addr.String(), &tls.Config{
RootCAs: rootCerts,
InsecureSkipVerify: true,
})
}
// dbDialInfo.Mechanism = "SCRAM-SHA-256"
_session, err := mgo.DialWithInfo(dbDialInfo)
if err != nil {
log.Fatalf("failed to creating db session : %s", err.Error())
return err
}
log.Printf("Created session - %v", _session)
return nil
}
When I run this code, I get error:
failed to creating db session : "server returned error on SASL authentication step: Authentication failed."
If I set [dbDialInfo.Mechanism = "SCRAM-SHA-256"] before creating session, I get error:
failed to creating db session : "SASL support not enabled during build (-tags sasl)"
Please let me know what is causing this issue, how can I connect to the database.
Currently I am using "github.com/globalsign/mgo", if it required to use any other library, that's totally fine for me.
I just want to get connected to the db.
rootca.crt file looks something like:
-----BEGIN CERTIFICATE-----
MIIGLjCCBBagAwIBAgIUbxINX1qe6W+7kolWGp+MX8NbYj8wDQYJKoZIhvcNAQEL
<blah> <blah> <blah> <blah> <blah> <blah> <blah> <blah> <blah>
jCZAGGHmbrR3zeIsOY8yKau0IXqRp5Wy6NQ0poOTcma9BfwNUVc4/ixsCkEVYbgW
eMs=
-----END CERTIFICATE-----
Thank you.
After researching a lot, I was not able to find a way to connect to mongodb using .crt file using globalsign library.
However I was successfully able to do this using mongo-driver library.
here connection string can be of format:
mongodb://user:password#replicaset-0.com:27017,replicaset-1.com:27017,replicaset-2.com:27017/?ssl=true&tlsCAFile=./ca.crt&tlsCertificateKeyFile=./ca.pem&authSource=admin&replicaSet=replicaset
Sample code:
import (
"context"
"log"
"os"
// "github.com/globalsign/mgo"
mgo "go.mongodb.org/mongo-driver/mongo"
mongoOptions "go.mongodb.org/mongo-driver/mongo/options"
)
func InitMongo() (error) {
connStr := os.Getenv("MONGODB_CONN_STR")
dbName := os.Getenv("MONGODB_DATABASE")
clientOpts := mongoOptions.Client().ApplyURI(connStr)
if err := clientOpts.Validate(); err != nil {
log.Print("unable to parse url")
log.Fatal(err)
}
client, err := mgo.Connect(context.TODO(), clientOpts)
if err != nil {
log.Print("unable to connect into database")
log.Fatal(err)
}
if err := client.Ping(context.TODO(), nil); err != nil {
log.Print("database ping failed")
log.Fatal(err)
}
//client.Database(dbName)
return nil
}
Related
I'm trying to use pgx to make a TLS connection to a postgres 10 db.
My connection string is similar to: "host='my-host.com' port='5432' dbname='my-db' user='my-db-user' sslmode='verify-full' sslcert='/path/to/db_user.crt' sslkey='/path/to/db_user.key' sslrootcert='/path/to/ca_roots.pem'"
When I run this directly with psql on the command-line, it works, so the cert and key files must be valid. db_user.crt and db_user.key are both PEM files. (the command-line also works with sslmode='verify-full', so the rootcert should also be ok)
But when I initialize a pgx pool with that connection string, it fails with:
FATAL: connection requires a valid client certificate (SQLSTATE 28000)
Is go expecting something other than PEM? Or is there a different way ssl cert and key pair is supposed to be initialized with pgx?
Code
import (
"context"
"fmt"
"os"
"github.com/jackc/pgx/v4"
"github.com/jackc/pgx/v4/pgxpool"
)
type mockLogger struct{}
func (ml *mockLogger) Log(ctx context.Context, level pgx.LogLevel, msg string, data map[string]interface{}) {
fmt.Printf("[%s] %s : %+v\n", level.String(), msg, data)
}
func connect() error {
connStr := "host='my-host.com' port='5432' dbname='my-db' user='my-db-user' sslmode='verify-full' sslcert='/path/to/db_user.crt' sslkey='/path/to/db_user.key' sslrootcert='/path/to/ca_roots.pem'"
poolCfg, err := pgxpool.ParseConfig(connStr)
if err != nil {
return err
}
poolCfg.ConnConfig.Logger = &mockLogger{}
poolCfg.ConnConfig.LogLevel = pgx.LogLevelTrace
fmt.Printf("using connection string: \"%s\"\n", poolCfg.ConnString())
connPool, err := pgxpool.ConnectConfig(context.TODO(), poolCfg)
if err != nil {
return err
}
connPool.Close()
return nil
}
func main() {
if err := connect(); err != nil {
fmt.Printf("%+v\n", err)
os.Exit(1)
}
}
Output from calling connect():
using connection string: "host='my-host.com' port='5432' dbname='my-db' user='my-db-user' sslmode='require' sslcert='/path/to/db_user.crt' sslkey='/path/to/db_user.key' sslrootcert='/path/to/ca_roots.pem'"
[info] Dialing PostgreSQL server : map[host:my-host.com]
[error] connect failed : map[err:failed to connect to `host=my-host.com user=my-db-user database=my-db`: server error (FATAL: connection requires a valid client certificate (SQLSTATE 28000))]
failed to connect to `host=my-host.com user=my-db-user database=my-db`: server error (FATAL: connection requires a valid client certificate (SQLSTATE 28000))
Summary
Turns out for go, the cert pointed to by sslcert needed to contain the full client cert chain.
When /path/to/db_user.crt contained the client cert followed by client cert chain, the pgx connection worked.
Whereas the psql command worked in both cases:
when sslcert was just the leaf client cert without the chain
when sslcert contained client cert + chain
Not sure why psql was fine without the full chain, but it works now.
Details
Under-the-hood, pgx uses the pgconn module to create the connection. That, in turn, is just calling tls.X509KeyPair on the contents of the sslcert and sslkey files.
pgconn/config.go:
func configTLS(settings map[string]string, thisHost string, parseConfigOptions ParseConfigOptions) ([]*tls.Config, error) {
[...]
sslcert := settings["sslcert"]
sslkey := settings["sslkey"]
[...]
if sslcert != "" && sslkey != "" {
[...]
certfile, err := ioutil.ReadFile(sslcert)
if err != nil {
return nil, fmt.Errorf("unable to read cert: %w", err)
}
cert, err := tls.X509KeyPair(certfile, pemKey)
if err != nil {
return nil, fmt.Errorf("unable to load cert: %w", err)
}
tlsConfig.Certificates = []tls.Certificate{cert}
I'm trying to connect to my mongo db atlas database, but I'm getting an error that I can't solve it within mongo+go forums.
The code:
package main
import (
"context"
"log"
"time"
"fmt"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
"go.mongodb.org/mongo-driver/mongo/readpref"
"go.mongodb.org/mongo-driver/bson"
)
func main(){
client, err := mongo.NewClient(options.Client().ApplyURI("mongodb://my-user:<my-pass>#datalake0-lesz0.a.query.mongodb.net/my-db?ssl=true&authSource=admin"))
if err != nil {
log.Fatal(err)
}
ctx, _ := context.WithTimeout(context.Background(), 10*time.Second)
err = client.Connect(ctx)
if err != nil {
log.Fatal(err)
}
defer client.Disconnect(ctx)
err = client.Ping(ctx, readpref.Primary())
if err != nil {
log.Fatal(err)
}
databases, err := client.ListDatabaseNames(ctx, bson.M{})
if err != nil {
log.Fatal(err)
}
fmt.Println(databases)
}
The error:
connection() error occured during connection handshake: auth error: sasl conversation error: unable to authenticate using mechanism "SCRAM-SHA-1": (AuthenticationFailed) authentication failed, correlationID = 167bc5ba18415510a4144b7a
exit status 1
If the URI in the connect string is verbatim, then this is your problem:
mongodb://my-user:<my-pass> is incorrect, <my-pass> should be substituted with your password
You've probably cut and pasted the provided URI on completion of DB setup but this connect string does not include items like your password, also you gave my-user which, unless you set up the username my-user that also needs changing.
I'm trying to connect a Go application with postgresql.
The app import postgresql driver:
"crypto/tls"
"database/sql"
"fmt"
"log"
"os"
"os/signal"
...
_ "github.com/go-sql-driver/mysql"
_ "github.com/lib/pq"
_ "github.com/mattn/go-sqlite3"
and uses like it to connect to the database:
driver, cnxn := dbFromURI(dbURI)
db, err := sql.Open(driver, cnxn)
if err != nil {
panic(err)
}
and the dbFromUri method just split the info
func dbFromURI(uri string) (string, string) {
parts := strings.Split(uri, "://")
return parts[0], parts[1]
}
My URI works locally when i run the command : psql postgresql://user:user#172.20.0.1:5432/lcp
But in go i Go, I got
./lcpserver
2021/03/07 02:00:42 Reading config /root/lcp-server-install/lcp-home/config/config.yaml
panic: pq: SSL is not enabled on the server
I tried this URI for Go without success : psql postgresql://user:user#172.20.0.1:5432/lcp?sslmode=disable
Do you have any idea why i can't connect ?
I tried with my aws rds postgres database, and got same result. Thnaks for the help.
complete code of the server
https://github.com/readium/readium-lcp-server/blob/master/lcpserver/lcpserver.go
I change the typo and the demo provided i succeed the connexion. But in the lcp server i style got the same issue.
postgres://user:user#172.20.0.1:5432/lcp?sslmode=disable
EDIT 2:
The error is due to the fact that the script tries prepare command. I update the minimal example and it fails too.
package main
import (
"database/sql"
"fmt"
"strings"
_ "github.com/lib/pq"
)
func dbFromURI(uri string) (string, string) {
parts := strings.Split(uri, "://")
return parts[0], parts[1]
}
func main() {
driver, cnxn := dbFromURI("postgres://user:user#172.20.0.1:5432/lcp?sslmode=disable")
fmt.Println("The driver " + driver)
fmt.Println("The cnxn " + cnxn)
db, err := sql.Open(driver, cnxn)
_, err = db.Prepare("SELECT id,encryption_key,location,length,sha256,type FROM content WHERE id = ? LIMIT 1")
if err != nil {
fmt.Println("Prepare failed")
fmt.Println(err)
}
if err == nil {
fmt.Println("Successfully connected")
} else {
panic(err)
}
}
I got :
prepare failed
pq: SSL is not enabled on the server
2021/03/07 17:20:13 This panic 3
panic: pq: SSL is not enabled on the server
The first problem is a typo in the connection string: postgresql://user:user#172.20.0.1:5432/lcp?sslmode=disable. In Go code it should be postgres://user:user#172.20.0.1:5432/lcp?sslmode=disable.
We also need to pass the full connection string as the second argument to sql.Open. For now, the dbFromURI function returns user:user#172.20.0.1:5432/lcp?sslmode=disable, but we need postgres://user:user#172.20.0.1:5432/lcp?sslmode=disable, because pq is waiting for this prefix to parse it.
After fixing this, I was able to establish a connection using a minimal postgres client based on your code.
To try this yourself, start the server with the following command:
docker run --rm -p 5432:5432 -e POSTGRES_PASSWORD=some_password postgres
And try to connect using the following client code:
package main
import (
"database/sql"
"fmt"
_ "github.com/lib/pq"
)
func main() {
cnxn := "postgres://postgres:some_password#127.0.0.1:5432/lcp?sslmode=disable"
_, err := sql.Open("postgres", cnxn)
if err != nil {
panic(err)
}
_, err = db.Prepare("SELECT id,encryption_key,location,length,sha256,type FROM content WHERE id = ? LIMIT 1")
if err != nil {
fmt.Println("Prepare failed")
panic(err)
}
}
I am trying to connect MongoDB by the native MongoDB driver with go language
(ref).
Here is my snapcode.
package main
import (
"context"
"fmt"
"log"
"time"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)
const (
account = "rootAdmin"
password = "12345678"
iP = "127.0.0.1"
port = 27017
tlsCertificateKeyFile = "D:/cert/wa.pem"
)
type mongoStuff struct {
ctx context.Context
client *mongo.Client
cancel context.CancelFunc
}
func connectToMongoDB() *mongoStuff {
uri := fmt.Sprintf("mongodb://%v:%v#%v:%v/?authSource=admin&tlsCertificateKeyFile=%v&tls=true",
account,
password,
iP,
port,
tlsCertificateKeyFile)
credential := options.Credential{
AuthMechanism: "MONGODB-X509",
Username: account,
Password: password,
}
log.Println(uri)
clientOpts := options.Client().ApplyURI(uri).SetAuth(credential)
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
client, err := mongo.Connect(ctx, clientOpts)
if err != nil {
log.Println("Dead connect")
log.Fatal(err)
}
return &mongoStuff{ctx, client, cancel}
}
func disconnectMongoDB(mongodb *mongoStuff) {
cancel := mongodb.cancel
client := mongodb.client
ctx := mongodb.ctx
defer cancel()
defer func() {
if err := client.Disconnect(ctx); err != nil {
log.Println("Dead disconnect")
panic(err)
}
}()
}
func insertExamples(mongodb *mongoStuff) {
ctx := mongodb.ctx
var db *mongo.Database = mongodb.client.Database("documentation_examples")
coll := db.Collection("inventory_insert")
err := coll.Drop(ctx)
if err != nil {
log.Println("Dead drop")
log.Fatal(err)
}
{
result, err := coll.InsertOne(
ctx,
bson.D{
{"item", "canvas"},
{"qty", 100},
{"tags", bson.A{"cotton"}},
{
"size", bson.D{
{"h", 28},
{"w", 35.5},
{"uom", "cm"},
}},
})
if err != nil {
log.Println("Dead insertone")
log.Fatal(err)
}
log.Printf("insertone success. id=%v", result.InsertedID)
}
}
func main() {
mongodb := connectToMongoDB()
defer disconnectMongoDB(mongodb)
insertExamples(mongodb)
}
Whenever I run the code, it just comes up with the below error.
connection() error occured during connection handshake: auth error: round trip error: (AuthenticationFailed) No user name provided
I can't figure out what's going on.
To authenticate with x.509, the username should be either the common name of the certificate or empty. You seem to be attempting some mix of password and x.509 authentication.
All required options can be provided in the URI. See How can I connect with X509 by putting all options in the connection string in node.js driver for mongodb?.
If you insist on specifying credentials not in a URI, reference driver documentation that describes how to do that for x509 credentials.
I'm trying to connect a go client to mongodb server running with ssl enabled. I get a clear error message indicating that the hand shake failed due to ssl error. I use a self signed certificate on the client side.
Got below from the mongodb server:
2017-05-13T04:38:53.910+0000 I NETWORK [thread1] connection accepted from 172.17.0.1:51944 #10 (1 connection now open)
2017-05-13T04:38:53.911+0000 E NETWORK [conn10] SSL: error:14094412:SSL routines:SSL3_READ_BYTES:sslv3 alert bad certificate
2017-05-13T04:38:53.911+0000 I - [conn10] end connection
Error from Go client:
Could not connect to mongodb_s1.dev:27017 x509: certificate signed by unknown authority (possibly because of "crypto/rsa: verification error" while trying to verify candidate authority certificate "XYZ")
Tried multiple options, but didn't help
You can skip TLS security checks using InsecureSkipVerify = true. This allows you to use self-signed certificates. See the code from compose help below.
Instead of skipping security checks, it is advisable to add the CA used to sign your certificates to the list of trusted CAs of the system.
package main
import (
"crypto/tls"
"fmt"
"net"
"os"
"strings"
"gopkg.in/mgo.v2"
)
func main() {
uri := os.Getenv("MONGODB_URL")
if uri == "" {
fmt.Println("No connection string provided - set MONGODB_URL")
os.Exit(1)
}
uri = strings.TrimSuffix(uri, "?ssl=true")
Here:
tlsConfig := &tls.Config{}
tlsConfig.InsecureSkipVerify = true
dialInfo, err := mgo.ParseURL(uri)
if err != nil {
fmt.Println("Failed to parse URI: ", err)
os.Exit(1)
}
And here:
dialInfo.DialServer = func(addr *mgo.ServerAddr) (net.Conn, error) {
conn, err := tls.Dial("tcp", addr.String(), tlsConfig)
return conn, err
}
session, err := mgo.DialWithInfo(dialInfo)
if err != nil {
fmt.Println("Failed to connect: ", err)
os.Exit(1)
}
defer session.Close()
dbnames, err := session.DB("").CollectionNames()
if err != nil {
fmt.Println("Couldn't query for collections names: ", err)
os.Exit(1)
}
fmt.Println(dbnames)
}