sshtunnel forwarding and mysql connection on google cloud function - python

I am trying to connect to a MySQL server through ssh tunnel on one of my google cloud functions. This works fine in my home environment. I assume it is some port issue on cloud function.
Edit: For clarification the MySQL server sits on a Namecheap shared hosting web server. Not Google Cloud SQL
Every time I run this I timeout with "unknown error". The tunnel appears to be successful. I am however unable to get the mysql connection to work.
import base64
import sshtunnel
import mysql.connector
def testing(event, context):
"""
Testing function
"""
with sshtunnel.SSHTunnelForwarder(
("server address", port),
ssh_username="user",
ssh_password="password",
remote_bind_address=("127.0.0.1",3306),
) as server:
print(server.local_bind_port)
with mysql.connector.connect(
user="user",
password="password",
host="localhost",
database="database",
port=server.local_bind_port
) as connection:
print(connection)

There's too many steps to list, but I'm wondering if the "connector" setup plays a difference even for SSH. Maybe you have to create a connector as shown here (notice how the instructions in "Private IP" tab are different than on your local computer). Then, configure Cloud Functions to use that connector. Make sure you also use the right port.
A Serverless VPC Access connector handles communication to your VPC
network. To connect directly with private IP, you need to:
Make sure that the Cloud SQL instance created above has a private IP
address. If you need to add one, see the Configuring private IP page
for instructions.
Create a Serverless VPC Access connector in the same
VPC network as your Cloud SQL instance. Unless you're using Shared
VPC, a connector must be in the same project and region as the
resource that uses it, but the connector can send traffic to resources
in different regions. Serverless VPC Access supports communication to VPC networks connected via Cloud VPN and VPC Network Peering. Serverless VPC Access does not support legacy networks.
Configure Cloud Functions to use the connector.
Connect using your
instance's private IP and port 3306.
Keep in mind, this "unknown" error could also very well be due to the Cloud SQL Admin API not being enabled here. As a matter of fact, make sure you follow that entire page as it's a broad question.
Let us know what worked for this type of error.

Related

Connecting to Cloud SQL postgres instance with SSL in python

I am trying to connect to a postgres instance I have in cloud sql. I have everything set up and am able to connect to it if ssl encryption is turned off. But now that I have it on I am trying to connect but running into some error.
def run():
connector = Connector()
def getconn():
conn = connector.connect(
os.getenv("CONNECTION_NAME"),
"pg8000",
user = os.getenv('DB_USERNAME'),
password = os.getenv("DB_PASSWORD"),
db=os.getenv('DB_NAME'),
ip_type= IPTypes.PRIVATE
)
return conn
pool = sqlalchemy.create_engine(
"postgresql+pg8000://",
creator=getconn,
pool.execute("CREATE TABLE........;")
All the certs are stored in secret manager as strings so I am using env variables to grab them, which is why I used cadata for example. But running into this error cadata does not contain a certificate why is this error coming up?
I'd recommend using the Cloud SQL Python Connector to connect to Cloud SQL from Python as it will generate the SSL context for you, meaning no need to manage SSL certificates! It also has additional benefits of not needing to authorize networks etc.
You can find a code sample for the Python Connector similar to the one you are using for establishing a TCP connection.
There is also an interactive getting started Colab Notebook that will walk you through using the Python Connector without you needing to change a single line of code!
It makes connecting to Cloud SQL both easy and secure.

AWS Lambda to RDS PostgreSQL

Hello fellow AWS contributors, I’m currently working on a project to set up an example of connecting a Lambda function to our PostgreSQL database hosted on RDS. I tested my Python + SQL code locally (in VS code and DBeaver) and it works perfectly fine with including only basic credentials(host, dbname, username password). However, when I paste the code in Lambda function, it gave me all sorts of errors. I followed this template and modified my code to retrieve the credentials from secret manager instead.
I’m currently using boto3, psycopg2, and secret manager to get credentials and connect to the database.
List of errors I’m getting-
server closed the connection unexpectedly. This probably means the server terminated abnormally before or while processing the request
could not connect to server: Connection timed out. Is the server running on host “db endpoint” and accepting TCP/IP connections on port 5432?
FATAL: no pg_hba.conf entry for host “ip:xxx”, user "userXXX", database "dbXXX", SSL off
Things I tried -
RDS and Lambda are in the same VPC, same subnet, same security group.
IP address is included in the inbound rule
Lambda function is set to run up to 15 min, and it always stops before it even hits 15 min
I tried both database endpoint and database proxy endpoint, none of it works.
It doesn’t really make sense to me that when I run the code locally, I only need to provide the host, dbname, username, and password, that’s it, and I’m able to write all the queries and function I want. But when I throw the code in lambda function, it’s requiring all these secret manager, VPC security group, SSL, proxy, TCP/IP rules etc. Can someone explain why there is a requirement difference between running it locally and on lambda?
Finally, does anyone know what could be wrong in my setup? I'm happy to provide any information in related to this, any general direction to look into would be really helpful. Thanks!
Following the directions at the link below to build a specific psycopg2 package and also verifying the VPC subnets and security groups were configured correctly solved this issue for me.
I built a package for PostgreSQL 10.20 using psycopg2 v2.9.3 for Python 3.7.10 running on an Amazon Linux 2 AMI instance. The only change to the directions I had to make was to put the psycopg2 directory inside a python directory (i.e. "python/psycopg2/") before zipping it -- the import psycopg2 statement in the Lambda function failed until I did that.
https://kalyanv.com/2019/06/10/using-postgresql-with-python-on-aws-lambda.html
This the VPC scenario I'm using. The Lambda function is executing inside the Public Subnet and associated Security Group. Inbound rules for the Private Subnet Security Group only allow TCP connections to 5432 for the Public Subnet Security Group.
https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/USER_VPC.Scenarios.html#USER_VPC.Scenario1

Error while using Python to connect to Amazon RDS Postgresql database

I'm trying to connect to Amazon RDS Postgresql database with this python code
import psycopg2
engine = psycopg2.connect(
database="vietop2database",
user="postgres",
password="07041999",
host="vietop2.cf4afg8yq42c.us-east-1.rds.amazonaws.com",
port='5433'
)
cursor = engine.cursor()
print('opened database successfully')
I encountered an error:
could not connect to server: Connection timed out
Is the server running on host "vietop2.cf4afg8yq42c.us-east-1.rds.amazonaws.com" (54.161.159.194) and accepting
TCP/IP connections on port 5433?
I consulted this trouble shooting on amazon and I already make sure the DB instance's public accessibility is set to Yes to allow external connections. I also changed port to 5433 and set VPC security to default. Yet, I fail to connect to the database. What might be the reasons? Please help me. Thank you very much
Below are the database connectivity and configuration information
I found the answer. I need to add new inbound rule allowing all traffic of IPv4 type

Config for using psycopg2 to access to Cloud SQL instance

I am using a PostgreSQL in Cloud SQL along with psycopg2 library to connect to database from my python code. The current one that I have is associated with a VPC network in which my google compute engines also in that VPC. So, in this case, my config to connect to this cloud sql instance can use private ip and my config look like this:
config['db-cloudsql'] = {
"host" : "10.x.x.x" # cloud sql private ip address
"user" : "postgres"
"password" :"xxxxx"
"database" : "postgres"
}
But now I have another vm instance from another VPC network that need to access to this cloud sql instance. I know that I can access to the cloud sql instance using public ip. (by adding my vm to authorised network) But this vm need to access to the cloud sql instance very often. So I am not sure that the cost from accessing with public ip will be higher compared with accessing with private ip (cannot find any related document about this). I tried peering 2 vpc networks for accessing with private ip but just found that I cannot use this method to connect to sql with private ip from this document
I have found from the document that I can use instance connection name as a host for my config so it should be something like:
config['db-cloudsql'] = {
"host" : "project-name:asia-southeast1:mydbname" #instance connection name
"user" : "postgres"
"password" :"xxxxx"
"database" : "postgres"
}
I haven't try this method yet, it might not working but if it somehow works, how will it differ from using public ip addess in term of cost?
Thank you
It seems like your question boils down into two parts:
Are there any alternatives to public IP or private IP?
No. You have to use one or the other to connect to your Cloud SQL instance. Private IP allows access from a VPC, Public IP is used pretty much everywhere else.
Cost of public IP vs private IP
You can find a breakdown of the costs here. In short, there is not really any extra charges with a Public IP. You do have to pay $.01 per hour while the instance is idle (to reserve the public IP address), and just like private IPs, you are responsible for costs of the Network Egress between regions.
I can use instance connection name as a host for my config
This is incorrect. If you are using the Cloud SQL Proxy to connect, it can create a Unix domain socket (at /cloudsql/INSTANCE_CONNECTION_NAME) that can be used to connect to your instance. However the proxy only authenticates your connection - it still needs a valid connection path (Public vs Private).
As you can see in this PostgreSQL pricing documentation there is no difference in the pricing as you use the public IP or the connection name on the Cloud SQL side. If you want to keep the cost as low as possible you can try to keep your Compute Engine instances in the same region, or at least in the same continent as your Cloud SQL instance.

Connect AWS RDS (psql) in AWS Lambda

I wrote a simple lambda function in python to fetch some data from AWS RDS. PostgreSQL is the database engines.
conn = psycopg2.connect(host=hostname, user=username, password=password, dbname=db_name, connect_timeout=50)
I did like this. But it didn't work. Always returns an error like this
Response:
{
"errorMessage": "2018-06-06T11:28:53.775Z Task timed out after 3.00 seconds"
}
How can I resolve this??
It is most probably timing-out because the network connection cannot be established.
If you wish to connect to the database via a public IP address, then your Lambda function should not be connected to the VPC. Instead, the connection will go from Lambda, via the internet, into the VPC and to the Amazon RDS instance.
If you wish to connect to the database via a private IP address, then your Lambda function should be configured to use the same VPC as the Amazon RDS instance.
In both cases, the connection should be established using the DNS Name of the RDS instance, but it will resolve differently inside and outside of the VPC.
Finally, the Security Group associated with the Amazon RDS instance needs to allow the incoming connection. This, too, will vary depending upon whether the request is coming from public or private space. You can test by opening the security group to 0.0.0.0/0 and, if it works, then try to restrict it to the minimum possible range.

Categories

Resources