I'm running a Rails 3.2 app on the Cedar stack at Heroku.
I'm using Amazon RDS for my MySQL database, and I have the proper DATABASE_URL setup in the Heroku config vars.
How do I get Heroku to use SSL in its connection to Amazon RDS?
Normally this would be specified as a value in database.yml, but since Heroku generates database.yml for us, I'm not sure how to control this setting.
Thanks!
You can specify some mysql2 SSL params through the DATABASE_URL config. They will get added as items to the dynamic database.yml that is generated during the Heroku build process, and so they'll be passed when mysql2 connections are created.
The only param you need to pass for this to work is sslca (not to be confused with sslcapath).
1. Download the Amazon RDS CA certificate and bundle it with your app.
(Edit) Amazon will be rotating this certificate in March 2015. You'll need the new file from that page instead of this one.
curl https://s3.amazonaws.com/rds-downloads/mysql-ssl-ca-cert.pem > ./config/amazon-rds-ca-cert.pem
2. Add the file to git, and redeploy to Heroku.
3. Change DATABASE_URL to pass sslca:
heroku config:add DATABASE_URL="mysql2://username:password#hostname/dbname?sslca=config/amazon-rds-ca-cert.pem -a <app_id>
The relative path there is important—see below.
That's it! Now that you have SSL working, you may want to enforce that all connections with that user only allow SSL:
GRANT USAGE ON dbname.* TO 'username'#'%' REQUIRE SSL;
Troubleshooting
Make sure to pass a relative path to sslca! Otherwise, rake assets:precompile may break with an SSL error. If you receive an error like:
SSL connection error: ASN: bad other signature confirmation
or even just:
SSL connection error
...then there is likely something wrong with how the CA cert file is referenced.
From looking at the injected database.yml (see bottom of http://neilmiddleton.com/sharing-databases-between-heroku-applications/) you can pass in extra configuration as part of the db URL as query params.
In theory, this should let you configure it how you want although I've not tried it.
Related
I'm trying to connect to the MySQL server on PlanetScale, but can't as it requires SSL.
Here's their doc for that, but it's unclear what it says.
https://planetscale.com/docs/concepts/secure-connections
Here's the connection URL: DATABASE_URL='mysql://co30rXXXXXXX:pscale_pw_XXXXXXX#hoqx01444p30.us-east-4.psdb.cloud/restaurant?ssl={"rejectUnauthorized":true}'
Here's what I see from my terminal when I run yarn run migration-run
yarn run v1.22.18 $ npx prisma migrate dev Environment variables
loaded from .env Prisma schema loaded from prisma/schema.prisma
Datasource "db": MySQL database "restaurant" at
"hoqx0XXXXX.us-east-4.psdb.cloud:3306"
Error: Migration engine error: unknown error: Code: UNAVAILABLE server
does not allow insecure connections, client must use SSL/TLS
error Command failed with exit code 1. info Visit
https://yarnpkg.com/en/docs/cli/run for documentation about this
command.
Is there anyone who has tried to connect to PlanetScale DB from Node.js on localhost? I have tried some other suggestions from Stackoverflow, but don't seem to work.
?ssl={"rejectUnauthorized":false}&sslcert=/etc/ssl/certs/ca-certificates.crt
Adding these params at the end of the connection link, the issue has been fixed. :)
SSL ISSUE ON WINDOWS
If you're working on a Windows machine and using a .env file for your connection string, here is what worked for me to run locally (windows does not have a default /etc/ssl/certs/ reference as answered here).
You get your connection string from the PlanetScale console, via "overview" > "connect"
This will look something like:
DATABASE_URL='mysql://xxxxxx:*****#aws-eu-west-1.connect.psdb.cloud/dbName?ssl={"rejectUnauthorized":true}'
When plainly using this you will most likley get the follow error message (as the question states):
Code: UNAVAILABLE server does not allow insecure connections, client must use SSL/TLS
You therefore need to provide a local cert, one can be downloaded from the following trusted location:
https://curl.se/docs/caextract.html
Next, you need to save this file to a logical location on disk that can be referenced in your connection string, for example c:/temp/cacert.pem
Once saved you can then append then following to your connection string:
&sslcert=C:\\temp\\cacert.pem
Restart your server and you should be all set! 🎉
The equivelant ssl cert update in NodeJs would look as follows:
const connection = mysql.createConnection({
host: 'hostNameHere',
user: 'userNameHere',
password: 'passwordHere',
database: 'dbHere',
ssl: {
ca: fs.readFileSync('C:\\temp\\cacert.pem')
}
});
I upgraded my plan from the free tier to a dedicated 25 plan.
When I updated and tested locally I am ABLE to connect. Same with workbench, I could query my data.
When I updated my Env vars in Heroku tho, it fails to establish a connection without any real error. I restarted all the dynos but still no luck. I believe this is a networking issue with Heroku maybe. ANYTHING HELPS
org.springframework.jdbc.CannotGetJdbcConnectionException: Failed to obtain JDBC Connection; nested exception is java.sql.SQLException: Access denied for user 'b3b4204cd59615'#'ip-x-x-x-x.ec2.internal' (using password: YES)] with root cause
java.sql.SQLException: Access denied for user 'b3b4204cd59615'#'ip-x-x-x-x.ec2.internal' (using password: YES)
My MySQL version: 'MySQL Community Server (GPL) version 5.6.50'
And using the most up to date version of 'mysql-connector-java'
implementation 'mysql:mysql-connector-java:8.0.28'
OKAY I FIGURED IT OUT! It's not anything obvs so you have to know a back story.
When you add clearDB to the project it automatically creates a ENV var of 'CLEARDB_DATABASE_URL' and that is a string that has username, password, and url data stored in it. Then they show you a way to make a DataSource obj in their documentation with a config file. Expecting you to follow that exactly I guess.
Well I didn't want to make a config but rather have spring do the work for me with setting them in application.properties and then injecting that with env vars dedicated to each value. ie 'db.url', 'db.password', and 'db.username' and it worked.
so when I upgraded, it gave me a new ENV VAR that had the new URL as username and password remained the same. ("CLEARDB_CYAN_CLEARDB_HOSTNAME_1")
so I wasn't using 'CLEARDB_DATABASE_URL' anymore but my own env vars. (like this)
spring:
datasource:
driverClassName: com.mysql.cj.jdbc.Driver
username: ${db.username}
password: ${db.password}
url: ${db.url}
Well, I'm pretty sure they are some behind the scenes networking permissions going on that looks at that value and allows access to it or something, as what I did to fix my issue is although I'm not using that var anymore, I took the new URL value and replaced the old with it to point at my new Datasource connection in the ENV var of 'CLEARDB_DATABASE_URL' and once I restarted my dynos again, It was able to connect successfully deployed.
so example:
mysql://b3b4204cdxxxxxx:password#us-xxxx-xxxx-03.cleardb.com/heroku_XXXXXXXXXXXXX?reconnect=true
became:
mysql://b3b4204cdxxxxxx:password#us-mm-xxx-xxxxxxxxxx.g5.cleardb.net/heroku_XXXXXXXXXXXXX?reconnect=true
Again even though my source code makes no use of this -- IT HAS TO BE UPDATED
I set up a new MySQL instance on AWS RDS (Aurora). I added a user that requires SSL, and downloaded the combined ca bundle as described here and here: SSL Connection error, and I can connect via command line and confirm that the user is securely connected. I also turned off the SSL requirement for the user temporarily and was able to connect with MySQL Workbench with SSL turned off.
The problem is that both MySQL Workbench and my Rails app expect three separate files: SSL CA, SSL Cert, and SSL Key.
I'm sure there has to be an easy solution to it, but much Googling is not finding the answer, including this unanswered one on the AWS forums. I appreciate the help.
You don't need any other files. When it comes to the MySQL Workbench you need to provide "SSL CA File" and "Use SSL" ("Require" or "Require and Verify CA").
After that you can verify your connection by using the following command:
SHOW SESSION STATUS LIKE 'Ssl_cipher';
I'm trying to connect my server code running as a Docker container in our Kubernetes cluster (hosted on Google Container Engine) to a Google Cloud SQL managed MySQL 5.7 instance. The issue I'm running into is that every connection is being rejected by the database server with Access denied for user 'USER'#'IP' (using password: YES). The database credentials (username, password, database name, and SSL certificates) are all correct and work when connecting via other MySQL clients or the same application running as a container on a local instance.
I've verified that all credentials are the same on the local and the server-hosted versions of the app and that the user I'm connecting with has the wildcard % host specified. Not really sure what to check next here, to be honest...
An edited version of the connection code is below:
let connectionCreds = {
host: Config.SQL.HOST,
user: Config.SQL.USER,
password: Config.SQL.PASSWORD,
database: Config.SQL.DATABASE,
charset: 'utf8mb4',
};
if (Config.SQL.SSL_ENABLE) {
connectionCreds['ssl'] = {
key: fs.readFileSync(Config.SQL.SSL_CLIENT_KEY_PATH),
cert: fs.readFileSync(Config.SQL.SSL_CLIENT_CERT_PATH),
ca: fs.readFileSync(Config.SQL.SSL_SERVER_CA_PATH)
}
}
this.connection = MySQL.createConnection(connectionCreds);
Additional information: the server application is built in Node using the mysql2 library to connect to the database. There are no special firewall rules in place that are causing network issues, and that's confirmed by the fact that the library IS connecting, but failing to authenticate.
After setting up Cloud SQL Proxy I managed to figure out what the actual error was: somewhere between the secret and the pod configuration an extra newline was being added to the database name, causing any connection attempt to fail. With the proxy set up this was made clear because there was an actual error message to that effect displayed.
(notably all of my logging around the credentials that I was using to validate that the credentials were accurate didn't explicitly display the newline and was disguised by the fact that the console display added line breaks to wrap the display, and it happened to line up exactly with where the database name ended)
Have you read the documentation on https://cloud.google.com/sql/docs/mysql/connect-container-engine ?
In Container Engine, you need to set up a Cloud SQL Proxy container alongside your application pod and talk to it. The Cloud SQL Proxy will then make the actual call to Cloud SQL service.
If the container worked locally, I assume you have Application Default Credentials set on your development machine. It could be failing because those credentials are not on your container as a Service Account file. Try configuring a Service Account file, or create your GKE cluster with --scopes argument that gives your instances access to Cloud SQL.
I have created a free instance of Heroku cleardb instance for my app. I set the database URL as:
heroku config:set DATABASE_URL='mysql://user:pass#us-cdbr-iron-east-03.cleardb.net/heroku_database?reconnect=true'
I'm trying to connect using a Go app. But when I try to access my application, it gives the following mysql error:
default addr for network 'us-cdbr-iron-east-03.cleardb.net' unknown
I tried to set the database url with protocol and port as well:
heroku config:set DATABASE_URL='mysql://user:pass#tcp(us-cdbr-iron-east-03.cleardb.net:3306)/heroku__database?reconnect=true'
This changes the errror to:
Access denied for user
which i'm guessing is because direct access to port is disallowed. Does anybody know what is the issue here?
This is a Go specific problem. Three changes are required:
Go's sql.Open already takes scheme as its first parameter so it needs to be stripped off of DATABASE_URL.
Connection string shouldn't have any query parameters (remove ?reconnect=true).
Protocol (tcp) and port (3306 for MySQL) number are required.
Thus final database URL would be:
DATABASE_URL='user:pass#tcp(us-cdbr-iron-east-03.cleardb.net:3306)/your_heroku_database'