SSH Tunnel using Google Cloud Function - python

Is there a way to do something like the following in GCF?
import pymysql
import paramiko
from sshtunnel import SSHTunnelForwarder
def hello_world(request, data=''):
with SSHTunnelForwarder(ssh_address_or_host='56.48.28.32', ssh_username='ubuntu', ssh_pkey='id_rsa', remote_bind_address=('aval.myixal.net', 3306)) as tunnel:
conn = pymysql.connect(host='127.0.0.1', user='xian', passwd='bwQi', db='avails', port=tunnel.local_bind_port)
cursor = conn.cursor()
cursor.execute('SELECT * FROM global_event LIMIT 10')
data = str(cursor.fetchone())
conn.close()
return data
I have included the id_rsa key and the requirements. This will work locally, but I'm guessing the whole 'port-forwarding' thing might be a non-starter on GCF. Is there a way to do something like the above?

Totally possible. Quick test i did:
import io
import pymysql
import paramiko
from sshtunnel import SSHTunnelForwarder
def hello_world(request):
k = '''-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAB
...
zLFzhIqql0Av4K4XKQAAABVqYWJic29uQHRlc3QtaW5zdGFuY2UBAgME
-----END OPENSSH PRIVATE KEY-----'''
key = paramiko.RSAKey.from_private_key(io.StringIO(k))
with SSHTunnelForwarder(ssh_address_or_host='<ssh-ip-address>', ssh_username='<ssh-user-name>', ssh_pkey=key, remote_bind_address=('127.0.0.1', 3306)) as tunnel:
conn = pymysql.connect(host='127.0.0.1', user='<mysql-user>', passwd='<mysql-pass>', port=tunnel.local_bind_port)
cursor = conn.cursor()
cursor.execute('SELECT NOW();')
data = str(cursor.fetchone())
conn.close()
return data
result:
gcurl https://us-central1-my-project.cloudfunctions.net/function-1
(datetime.datetime(2021, 5, 13, 5, 4, 16),)
make sure not to hardcode your values like I did, instead use env variables.

Related

Open SSH Tunnel with private key stored in S3

If I run the following code, my SSH Tunnel works perfectly.
from sshtunnel import SSHTunnelForwarder
tunnel = SSHTunnelForwarder(
ssh_host=(SSH_JUMPHOST, SSH_PORT),
ssh_username=SSH_USERNAME,
ssh_pkey="/path/to/key/in/my/machine",
remote_bind_address=(
REMOTE_HOST,
REMOTE_PORT,
),
local_bind_address=("127.0.0.1", 12345),
ssh_private_key_password=SSH_PKEY_PASSWORD,
)
tunnel.start()
# Things happen in the tunnel...
However, I want to read a .pem key that is stored in an S3 bucket. How can I read and pass the key to the SSHTunnelForwarder constructor?
from sshtunnel import SSHTunnelForwarder
S3_BUCKET = "the_bucket"
S3_KEY_PATH = "the_key.pem"
tunnel = SSHTunnelForwarder(
ssh_host=(SSH_JUMPHOST, SSH_PORT),
ssh_username=SSH_USERNAME,
ssh_pkey=??????, ################ What should I include here?
remote_bind_address=(
REMOTE_HOST,
REMOTE_PORT,
),
local_bind_address=("127.0.0.1", 12345),
ssh_private_key_password=SSH_PKEY_PASSWORD,
)
tunnel.start()
# Things happen in the tunnel...
In the end, I surrendered to Furas suggestion since I couldn't find an alternative way to get it done.
The idea is to download the key file and point to the downloaded copy. With the following code, it can be structured to leave the file available for the shortest amount of time possible and ensure to best ability that it gets deleted after the tunnel has been opened.
from sshtunnel import SSHTunnelForwarder
S3_BUCKET = "the_bucket"
S3_KEY_PATH = "the_key.pem"
try:
s3.download_file(S3_BUCKET_NAME, S3_KEY_PATH , "temp")
tunnel = SSHTunnelForwarder(
ssh_host=(SSH_JUMPHOST, SSH_PORT),
ssh_username=SSH_USERNAME,
ssh_pkey="temp",
remote_bind_address=(
DW_HOST,
DW_PORT,
),
local_bind_address=("127.0.0.1", DW_PORT),
ssh_private_key_password=SSH_PKEY_PASSWORD,
)
except Exception as e:
raise e
finally:
# No matter what happens above, we always delete the temp copy of the key
os.remove("temp")
tunnel.start()
# Things happen in the tunnel...

How can we connect from server to mysql using paramiko? [duplicate]

I'm using MySqldb with Python 2.7 to allow Python to make connections to another MySQL server
import MySQLdb
db = MySQLdb.connect(host="sql.domain.com",
user="dev",
passwd="*******",
db="appdb")
Instead of connecting normally like this, how can the connection be made through a SSH tunnel using SSH key pairs?
The SSH tunnel should ideally be opened by Python. The SSH tunnel host and the MySQL server are the same machine.
Only this worked for me
import pymysql
import paramiko
import pandas as pd
from paramiko import SSHClient
from sshtunnel import SSHTunnelForwarder
from os.path import expanduser
home = expanduser('~')
mypkey = paramiko.RSAKey.from_private_key_file(home + pkeyfilepath)
# if you want to use ssh password use - ssh_password='your ssh password', bellow
sql_hostname = 'sql_hostname'
sql_username = 'sql_username'
sql_password = 'sql_password'
sql_main_database = 'db_name'
sql_port = 3306
ssh_host = 'ssh_hostname'
ssh_user = 'ssh_username'
ssh_port = 22
sql_ip = '1.1.1.1.1'
with SSHTunnelForwarder(
(ssh_host, ssh_port),
ssh_username=ssh_user,
ssh_pkey=mypkey,
remote_bind_address=(sql_hostname, sql_port)) as tunnel:
conn = pymysql.connect(host='127.0.0.1', user=sql_username,
passwd=sql_password, db=sql_main_database,
port=tunnel.local_bind_port)
query = '''SELECT VERSION();'''
data = pd.read_sql_query(query, conn)
conn.close()
I'm guessing you'll need port forwarding. I recommend sshtunnel.SSHTunnelForwarder
import mysql.connector
import sshtunnel
with sshtunnel.SSHTunnelForwarder(
(_host, _ssh_port),
ssh_username=_username,
ssh_password=_password,
remote_bind_address=(_remote_bind_address, _remote_mysql_port),
local_bind_address=(_local_bind_address, _local_mysql_port)
) as tunnel:
connection = mysql.connector.connect(
user=_db_user,
password=_db_password,
host=_local_bind_address,
database=_db_name,
port=_local_mysql_port)
...
from sshtunnel import SSHTunnelForwarder
import pymysql
import pandas as pd
tunnel = SSHTunnelForwarder(('SSH_HOST', 22), ssh_password=SSH_PASS, ssh_username=SSH_UNAME,
remote_bind_address=(DB_HOST, 3306))
tunnel.start()
conn = pymysql.connect(host='127.0.0.1', user=DB_UNAME, passwd=DB_PASS, port=tunnel.local_bind_port)
data = pd.read_sql_query("SHOW DATABASES;", conn)
credits to https://www.reddit.com/r/learnpython/comments/53wph1/connecting_to_a_mysql_database_in_a_python_script/
If your private key file is encrypted, this is what worked for me:
mypkey = paramiko.RSAKey.from_private_key_file(<<file location>>, password='password')
sql_hostname = 'sql_hostname'
sql_username = 'sql_username'
sql_password = 'sql_password'
sql_main_database = 'sql_main_database'
sql_port = 3306
ssh_host = 'ssh_host'
ssh_user = 'ssh_user'
ssh_port = 22
with SSHTunnelForwarder(
(ssh_host, ssh_port),
ssh_username=ssh_user,
ssh_pkey=mypkey,
ssh_password='ssh_password',
remote_bind_address=(sql_hostname, sql_port)) as tunnel:
conn = pymysql.connect(host='localhost', user=sql_username,
passwd=sql_password, db=sql_main_database,
port=tunnel.local_bind_port)
query = '''SELECT VERSION();'''
data = pd.read_sql_query(query, conn)
print(data)
conn.close()
You may only write the path to the private key file: ssh_pkey='/home/userName/.ssh/id_ed25519' (documentation is here: https://sshtunnel.readthedocs.io/en/latest/).
If you use mysql.connector from Oracle you must use a construction
cnx = mysql.connector.MySQLConnection(...
Important: a construction
cnx = mysql.connector.connect(...
does not work via an SSh! It is a bug.
(The documentation is here: https://dev.mysql.com/doc/connector-python/en/connector-python-connectargs.html).
Also, your SQL statement must be ideal. In case of an error on SQL server side, you do not receive an error message from SQL-server.
import sshtunnel
import numpy as np
with sshtunnel.SSHTunnelForwarder(ssh_address_or_host='ssh_host',
ssh_username="ssh_username",
ssh_pkey='/home/userName/.ssh/id_ed25519',
remote_bind_address=('localhost', 3306),
) as tunnel:
cnx = mysql.connector.MySQLConnection(user='sql_username',
password='sql_password',
host='127.0.0.1',
database='db_name',
port=tunnel.local_bind_port)
cursor = cnx.cursor()
cursor.execute('SELECT * FROM db_name.tableName;')
arr = np.array(cursor.fetchall())
cursor.close()
cnx.close()
This works for me:
import mysql.connector
import sshtunnel
with sshtunnel.SSHTunnelForwarder(
('ip-of-ssh-server', 'port-in-number-format'),
ssh_username = 'ssh-username',
ssh_password = 'ssh-password',
remote_bind_address = ('127.0.0.1', 3306)
) as tunnel:
connection = mysql.connector.connect(
user = 'database-username',
password = 'database-password',
host = '127.0.0.1',
port = tunnel.local_bind_port,
database = 'databasename',
)
mycursor = connection.cursor()
query = "SELECT * FROM datos"
mycursor.execute(query)
Someone said this in another comment. If you use the python mysql.connector from Oracle then you must use a construction cnx = mysql.connector.MySQLConnection(....
Important: a construction cnx = mysql.connector.connect(... does not work via an SSH! This bug cost me a whole day trying to understand why connections were being dropped by the remote server:
with sshtunnel.SSHTunnelForwarder(
(ssh_host,ssh_port),
ssh_username=ssh_username,
ssh_pkey=ssh_pkey,
remote_bind_address=(sql_host, sql_port)) as tunnel:
connection = mysql.connector.MySQLConnection(
host='127.0.0.1',
port=tunnel.local_bind_port,
user=sql_username,
password=sql_password)
query = 'select version();'
data = pd.read_sql_query(query, connection)
print(data)
connection.close()
If you are using python, and all the username, password, host and port are correct then there is just one thing left, that is using the argument (use_pure=True). This argument uses python to parse the details and password. You can see the doc of mysql.connector.connect() arguments.
with sshtunnel.SSHTunnelForwarder(
(ssh_host,ssh_port),
ssh_username=ssh_username,
ssh_pkey=ssh_pkey,
remote_bind_address=(sql_host, sql_port)) as tunnel:
connection = mysql.connector.MySQLConnection(
host='127.0.0.1',
port=tunnel.local_bind_port,
user=sql_username,
password=sql_password,
use_pure='True')
query = 'select version();'
data = pd.read_sql_query(query, connection)
print(data)
connection. Close()
Paramiko is the best python module to do ssh tunneling. Check out the code here:
https://github.com/paramiko/paramiko/blob/master/demos/forward.py
As said in comments this one works perfect.
SSH Tunnel for Python MySQLdb connection
Best practice is to parameterize the connection variables.
Here is how I have implemented. Works like charm!
import mysql.connector
import sshtunnel
import pandas as pd
import configparser
config = configparser.ConfigParser()
config.read('c:/work/tmf/data_model/tools/config.ini')
ssh_host = config['db_qa01']['SSH_HOST']
ssh_port = int(config['db_qa01']['SSH_PORT'])
ssh_username = config['db_qa01']['SSH_USER']
ssh_pkey = config['db_qa01']['SSH_PKEY']
sql_host = config['db_qa01']['HOST']
sql_port = int(config['db_qa01']['PORT'])
sql_username = config['db_qa01']['USER']
sql_password = config['db_qa01']['PASSWORD']
with sshtunnel.SSHTunnelForwarder(
(ssh_host,ssh_port),
ssh_username=ssh_username,
ssh_pkey=ssh_pkey,
remote_bind_address=(sql_host, sql_port)) as tunnel:
connection = mysql.connector.connect(
host='127.0.0.1',
port=tunnel.local_bind_port,
user=sql_username,
password=sql_password)
query = 'select version();'
data = pd.read_sql_query(query, connection)
print(data)
connection.close()

Issues with connecting to Postgres DB via SSH in Python

I've been given a postgres DB in my uni project in which I have to SSH into the network from which I can then access the DB. I've set up the connection in DBeaver using the SSH tab and it works perfectly fine. However, using Python, I can connect to the SSH just fine, but cannot connect to the DB itself. I've checked with another DB that doesn't require SSH and that works just fine. Here is my code. Note: I've already tried using SSHTunnel, too, to no avail. Also, ignore my quick hack to anonymize my SSH login data, as I didn't find how to use a proper config file with paramiko late at night yesterday...
import os
from psycopg2 import connect, Error
from paramiko import SSHClient
from config import config
with open("ssh_config.txt", "r") as f:
lines = f.readlines()
hostname = lines[0].strip()
username = lines[1].strip()
password = lines[2].strip()
ssh = SSHClient()
ssh.load_host_keys(os.path.expanduser('~/.ssh/known_hosts'))
ssh.connect(hostname=hostname, username=username, password=password)
print("SSH connected.")
try:
params = config()
conn = connect(**params)
cursor = conn.cursor()
print("DB connected.")
# Print PostgreSQL connection properties.
print(conn.get_dsn_parameters(), "\n")
# Print PostgreSQL version.
cursor.execute("SELECT version();")
record = cursor.fetchone()
print("You are connected to - ", record, "\n")
except (Exception, Error) as error:
print("Error while connecting to PostgreSQL", error)
Any help would be appreciated. Thanks!
I've figured it out myself. Here is the updated code. Basically, I had to forward the remote address to localhost and then connect to localhost instead of the DB address.
from psycopg2 import connect, Error
from sshtunnel import SSHTunnelForwarder
from config import config
with open("ssh_config.txt", "r") as f:
lines = f.readlines()
hostname = lines[0].strip()
username = lines[1].strip()
password = lines[2].strip()
remote_bind_address = lines[3].strip()
try:
with SSHTunnelForwarder(
(hostname, 22),
ssh_username=username,
ssh_password=password,
remote_bind_address=(remote_bind_address, 5432),
local_bind_address=("localhost", 8080)) \
as tunnel:
tunnel.start()
print("SSH connected.")
params = config()
conn = connect(**params)
cursor = conn.cursor()
print("DB connected.")
# Print PostgreSQL connection properties.
print(conn.get_dsn_parameters(), "\n")
# Print PostgreSQL version.
cursor.execute("SELECT version();")
record = cursor.fetchone()
print("You are connected to - ", record, "\n")
cursor.close()
conn.close()
tunnel.close()
print("DB disconnected.")
except (Exception, Error) as error:
print("Error while connecting to DB", error)

How would one connect an SQL db securely to an external client?

I'm attempting to connect a database, located on a web server, to a robot but I do not know how to connect the database to the robot. I would like the robot to run SELECT and UPDATE queries from the robot. The other issue is that I do not intend on using C-languages or Java; I plan on using python in the main control system.
I do know:
PHP
VBScript
Batch
Python
If anyone knows how to connect the DB to a bot it would be a great help.
So basically how to connect to an SQL DB in python? I'm working on a virtual bot right now doing the same thing. Look into the module , SQL-connector! http://www.mysqltutorial.org/python-connecting-mysql-databases/
You would start with creating a config.ini with your credentials
[mysql]
host = localhost
database = python_mysql
user = root
password =
Read Config.ini and return a dictionary
from configparser import ConfigParser
def read_db_config(filename='config.ini', section='mysql'):
""" Read database configuration file and return a dictionary object
:param filename: name of the configuration file
:param section: section of database configuration
:return: a dictionary of database parameters
"""
# create parser and read ini configuration file
parser = ConfigParser()
parser.read(filename)
# get section, default to mysql
db = {}
if parser.has_section(section):
items = parser.items(section)
for item in items:
db[item[0]] = item[1]
else:
raise Exception('{0} not found in the {1} file'.format(section, filename))
return db
and connect to MYSQL database
from mysql.connector import MySQLConnection, Error
from python_mysql_dbconfig import read_db_config
def connect():
""" Connect to MySQL database """
db_config = read_db_config()
try:
print('Connecting to MySQL database...')
conn = MySQLConnection(**db_config)
if conn.is_connected():
print('connection established.')
else:
print('connection failed.')
except Error as error:
print(error)
finally:
conn.close()
print('Connection closed.')
if __name__ == '__main__':
connect()
and update statement would look like the following
def update_book(book_id, title):
# read database configuration
db_config = read_db_config()
# prepare query and data
query = """ UPDATE books
SET title = %s
WHERE id = %s """
data = (title, book_id)
try:
conn = MySQLConnection(**db_config)
# update book title
cursor = conn.cursor()
cursor.execute(query, data)
# accept the changes
conn.commit()
except Error as error:
print(error)
finally:
cursor.close()
conn.close()
if __name__ == '__main__':
update_book(37, 'The Giant on the Hill *** TEST ***')

PyMySQL Error inserting values into table. - Python

I am trying to make a login system with python and mysql. I connected to the database, but when I try to insert values into a table, it fails. I'm not sure what's wrong. I am using python 3.5 and the PyMySQL module.
#!python3
import pymysql, sys, time
try:
print('Connecting.....')
time.sleep(1.66)
conn = pymysql.connect(user='root', passwd='root', host='127.0.0.1', port=3306, database='MySQL')
print('Connection suceeded!')
except:
print('Connection failed.')
sys.exit('Error.')
cursor = conn.cursor()
sql = "INSERT INTO login(USER, PASS) VALUES('test', 'val')"
try:
cursor.execute(sql)
conn.commit()
except:
conn.rollback()
print('Operation failed.')
conn.close()
I think it may have to do with the order of the statements in the connection. According to the PyMySQL github (found here) the correct order is host, port, user, passwd, db.
Like this :
user = input("User: ")
pass = input("Pass: ")
sql = "INSERT INTO login(USER, PASS) VALUES('%s', '%s')"%(user, pass)
btw you should connect like this :
conn = pymysql.connect(
host='127.0.0.1',
user='root',
passwd='root',
db='MySQL
)

Categories