繁体   English   中英

使用 Python 中的私钥通过 SSH 连接和查询 Mongo 数据库

[英]Connect and query Mongo database over SSH with private key in Python

我有一个代码文件mongo.py如下所示,可以使用username host password连接 n 查询 mongo 及其工作,但是我如何使用 ssh address username和身份验证方法private_key连接到 ssh? 另一个文件中的private_key

这是我使用 ssh 的示例config

sql_local = {'mongomdm':{'host':'xx.xxx.xxx.xx', 'user':'aaa', 'pkey':'/Users/satu/dua/tiga/config/settings/googlecloud_dev_rsa'}}

我已经准备好一些参考资料,应该像这样导入库吗?

from paramiko import SSHClient, AutoAddPolicy, RSAKey
from paramiko.auth_handler import AuthenticationException
from scp import SCPClient, SCPException
from io import StringIO

这是我的代码文件mongo.py

import csv                                                                              
import pandas as pd
from pymongo import MongoClient
from pymongo.errors import ConnectionFailure
import config.config as cfg
import config.modules.common as comm
from bson.objectid import ObjectId

class mongoFunc:
def __init__(self):
    self.types = 'mongodb'
    self.host = cfg.sql_local[self.types]['host']
    self.user = cfg.sql_local[self.types]['user']
    self.password = cfg.sql_local[self.types]['password']
    self.uri = 'mongodb://{user}:{password}@{host}'.format(user = self.user, password = self.password, host = self.host)

def connection(self):
    try:
        client= MongoClient(self.uri)
        client.server_info()
        print('Connection Established')
    except ConnectionFailure as err:
        raise(err)
    return client

def get_collection(self, client, database, collection):
    self.client= client
    self.database= database
    self.collection= collection

    db= self.client[self.database]
    return db[self.collection]

def get_query(self,id_data= None,start_date=None,end_date=None,query=None):
    self.id = ObjectId(id_data)
    self.start_date = start_date
    self.end_date = end_date
    self.query = query
    
    if self.end_date:
        script= {'date':{'$gt':self.start_date,'$lte':self.end_date}}
    if self.end_date is None:
        script= {'date':{'$gt':self.start_date}}
    if self.id:
        script = {'_id':{'$gt':self.id}}
    if self.query:
        script.update(self.query)
    return script

def get_data_to_pandas(self, database, collection, query, skip, limit=None):
    self.database = database
    self.collection = collection
    self.query = query
    self.limit = limit
    self.skip = skip

    self.client = self.connection()
    self.collection = self.get_collection(self.client,self.database,self.collection)

    if limit:   
        cursor = self.collection.find(self.query).skip(self.skip).limit(self.limit)
    if not limit :
        cursor = collection.find(self.query).skip(self.skip)
    df = pd.DataFrame(list(cursor))
    return df

编辑:

def connection(self):
    try:
        print('Establishing SSH Connection')
        self.client = paramiko.SSHClient()
        self.client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
        if (self.password == ''):
            private_key = paramiko.RSAKey.from_private_key_file(self.pkey)
            self.client.connect(hostname=self.host, port=self.port, username=self.user, pkey=private_key, allow_agent=False,look_for_keys=False)
            print("Connected to the server"),self.host
        else:
            self.client.connect(hostname=self.host, port=self.port, username=self.user, password=self.password, allow_agent=False,look_for_keys=False)    
            print("Connected to the server"),self.host
    except paramiko.AuthenticationException:
        print("Authentication failed, please verify your credentials")
        result_flag = False
    except paramiko.SSHException as sshException:
        print("Could not establish SSH connection: %s") % sshException
        result_flag = False
    else:
        result_flag = True
    return result_flag

def get_collection(self, client, database, collection):
    self.client= client
    self.database= database
    self.collection= collection

    db= self.client[self.database]
    return db[self.collection]`

我收到一个错误:

line 64, in get_collection
    db= self.client[self.database]
TypeError: 'bool' object is not subscriptable

我应该怎么办?

除非 MongoClient 模块自己支持 SSH 隧道(我不知道),否则您必须明确实现端口转发。

使用 Python Paramiko 修改来自嵌套 SSH的代码进行数据库隧道,您会得到如下代码:

ssh_client = paramiko.SSHClient()
# ...

ssh_client.connect(hostname=ssh_hostname, username=ssh_username, key_filename=ssh_key)

transport = ssh_client.get_transport()
dest_addr = (mongo_host, mongo_port)
local_unique_port = 4000 # any unused local port
local_host = 'localhost'
local_addr = (local_host, local_unique_port)
vmchannel = vmtransport.open_channel("direct-tcpip", dest_addr, local_addr)

self.uri = 'mongodb://{user}:{password}@{local_host}:{port}'.
    format(user=mongo_user, password=mongo_password, local_host=local_host,
           port=local_unique_port)

如果 Mongo 数据库在 SSH 服务器本身上运行,那么它通常只会在环回接口上侦听。 在这种情况下mongo_host应该设置为localhost


关于 PostgreSQL 的相同问题:使用 Paramiko设置 SSH 隧道以访问 PostgreSQL

这对我有用。 我检查了上面的 paramiko 示例,但不明白并发现了这一点。 我从这里获取了代码,并根据我的需要进行了一些修改。

def data_call(collection_name, query={}):
    from sshtunnel import SSHTunnelForwarder
    import pymongo

    MONGO_HOST = 'HOST' 
    SERVER_USER   = 'server_user'
    PRIVATE_KEY ='pem.txt'

    MONGO_USER='user_mongo'
    MONGO_PASS ='pass_mongo'

    MONGO_DB = "db"

    # define ssh tunnel
    server = SSHTunnelForwarder(
        MONGO_HOST,
        ssh_username=SERVER_USER,
        ssh_pkey=PRIVATE_KEY,
        remote_bind_address=('127.0.0.1', 27017)
    )

    # start ssh tunnel
    server.start()

    connection = pymongo.MongoClient('127.0.0.1', server.local_bind_port)
    db = connection[MONGO_DB]

    data = db[collection_name].find(query)
    return data

在您的连接信息中:

sql_local = {
    'mongomdm': {
        'host':'xx.xxx.xxx.xx',
        'user':'aaa', 
        'pkey':'/Users/satu/dua/tiga/config/settings/googlecloud_dev_rsa'}}

您可以pip install ssh-pymongo ,然后:

from ssh_pymongo import MongoSession

session = MongoSession('xx.xxx.xxx.xx', 
    user='aaa',
    key='/Users/satu/dua/tiga/config/settings/googlecloud_dev_rsa',
    uri='mongodb://{mongo-user}:{mongo-password}@{host}:{local-port}'
)

db = session.connection['db-name']

有关另一篇文章的更多信息: 如何将远程 mongodb 与 pymongo 连接

只是改进了其他一些实际上对我有帮助的答案

添加了行 db.authenticate(MONGO_USER, MONGO_PASS)

回忆:“在 MONGO 上进行授权!!!!”

并转换为 pandas dataframe 如果它对任何人有用(对我来说是这样)

from sshtunnel import SSHTunnelForwarder
import pymongo
import pandas as pd


def data_call(collection_name, query={}):
    MONGO_HOST = 'ip.add.res'
    SERVER_USER = 'user'
    PRIVATE_KEY = 'PATH TO/id_rsa'

    MONGO_USER = 'mongouser'
    MONGO_PASS = 'mongopass'
    MONGO_DB = "dbname"
    # define ssh tunnel
    server = SSHTunnelForwarder(
        MONGO_HOST,
        ssh_username=SERVER_USER,
        ssh_pkey=PRIVATE_KEY,
        remote_bind_address=('127.0.0.1', dbport)
    )
    # start ssh tunnel
    server.start()

    
    connection = pymongo.MongoClient('localhost', server.local_bind_port)
    db = connection[MONGO_DB]
    db.authenticate(MONGO_USER, MONGO_PASS)


    data = pd.DataFrame(list(db[collection_name].find(query))).drop(columns=['_id'])

    return data
`def connection(self):
    try:
        print('Establishing SSH Connection')
        self.client = paramiko.SSHClient()
        self.client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
        if (self.password == ''):
            private_key = paramiko.RSAKey.from_private_key_file(self.pkey)
            self.client.connect(hostname=self.host, port=self.port, username=self.user, pkey=private_key, allow_agent=False,look_for_keys=False)
            print("Connected to the server"),self.host
        else:
            self.client.connect(hostname=self.host, port=self.port, username=self.user, password=self.password, allow_agent=False,look_for_keys=False)    
            print("Connected to the server"),self.host
    except paramiko.AuthenticationException:
        print("Authentication failed, please verify your credentials")
        result_flag = False
    except paramiko.SSHException as sshException:
        print("Could not establish SSH connection: %s") % sshException
        result_flag = False
    else:
        result_flag = True
    return result_flag

def get_collection(self, client, database, collection):
    self.client= client
    self.database= database
    self.collection= collection

    db= self.client[self.database]
    return db[self.collection]`

line 64, in get_collection db= self.client[self.database] TypeError: 'bool' object is not subscriptable

我应该怎么做?

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM