yxes has asked for the wisdom of the Perl Monks concerning the following question:

Desired Outcome: establish an SSL connection to Amazon's RDS system using MySQL.

Here's the docs according to Amazon.

http://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/UsingWithRDS.SSL.html

After creating a user that requires SSL with the above instructions, I can easily connect using the command line:

mysql -u myuser -p -h myhost.us-east-1.rds.amazonaws.com --ssl-ca=cert/rds-combined-ca-bundle.pem --ssl-verify-server-cert

I just want to point out that I'm NOT using SSL to authenticate. Just to establish a secure link and verify the server, hence the need to enter my user/pass.

use DBI; my $dbh = DBI->connect( "DBI:mysql:Test:myhost.us-east-1.rds.amazonaws.com:3306;mysql_ssl=1 +", "myuser","****") || die DBI->errstr; $dbh->disconnect;

The relevant docs for DBD::mysql are located here: DBD::mysql#mysql_ssll

Considering that I'm not authenticating, I thought maybe I could get away with just setting mysql_ssl=1 and according to this post:

http://forums.mysql.com/read.php?38,520999,525084

that should be all I need (but it's using a language I will not mention here).

when that returned

Access denied for user 'myuser'@'xx.x.x.xxx'

I tried various combinations of:

DBI:mysql:Test:myhost.us-east-1.rds.amazonaws.com:3306;mysql_ssl=1;mysql_ssl_ca_file=./cert/rds-combined-ca-bundle.pem

and

DBI:mysql:Test:myhost.us-east-1.rds.amazonaws.com:3306;mysql_ssl=1;mysql_ssl_ca_file=rds-combined-ca-bundle.pem;mysql_ssl_ca_path=./cert/

to no avail even after changing the settings to use full paths instead of relative ones.

Turning off SSL for myuser on MySQL and removing mysql_ssl=1 from the DBI connection works perfectly, but I'm stumped as to why I'm unable to connect with SSL. Advice has run the gamut from using Expect with mysql-client to writing a proxy server in some other language to forgetting about SSL completely...

Has anyone had luck with using DBI and connecting to MySQL on Amazon's RDS via SSL? If so, I beg of you to impart your vast wisdom in the ways of the... TIA :)

Replies are listed 'Best First'.
Re: AWS RDS MySQL SSL
by hotchiwawa (Scribe) on Jan 02, 2016 at 18:29 UTC
    Hi yxes,

    Have you try Paws?
    https://metacpan.org/pod/Paws

    I saw this module today :D
    Normally you can access all Amazon services.

    Peace

      Paws looks very thorough but it's functionality allows for setting/configuring AWS components. All I'm trying to do is connect to an existing MySQL setup via SSL, whereas Paws would allow me to setup / teardown a database.

      Having said that, I usually use a more snake-like language to make those types of connections, but I might switch with your discovery. :)

        haha great, keep us informed :)
Re: AWS RDS MySQL SSL
by Chefboyardei (Initiate) on Sep 29, 2016 at 15:51 UTC
    I've been pulling my hair out over the same exact issue all week. Did you end up finding a working method?

      Nearly 4 years later and I have a solution (and another problem for another day)

        STEPS:
      1. Get a root certificate from Amazon https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/UsingWithRDS.SSL.html
      2. Tack this on to your DBD ;mysql_ssl=1;mysql_ssl_ca_file=<path to your>rds-combined-ca-bundle.pem
      3. run your script

      In my case to get the pem file I used the command: wget https://s3.amazonaws.com/rds-downloads/rds-ca-2019-root.pem

      At this point (assuming you connected) you're asking yourself, how the heck you know you've connected securely. I can't speak for windows but this helped me on unix.

      sudo tcpdump -nn -s2048 -X host <IP TO YOUR DB>

      Assuming that you only have Amazon's long hostname you can find IP TO YOUR DB

      dig <AMAZON's LONG RDS HOSTNAME>

      If you run some calls to your database you will see it's encrypted.

      So this is great, you have an SSL connection to your RDS system ~~ this was relatively painless.

      Here's the complete code (assuming you put your .pem in the local directory)

      #!/usr/bin/perl use strict; use warnings; use v5.10; # for say() function use DBI; say "Perl MySQL Connect Demo"; # MySQL database configuration my $dsn = 'DBI:mysql:information_schema:<AWS RDS HOST NAME>;mysql_ssl= +1;mysql_ssl_ca_file=./rds-combined-ca-bundle.pem'; my $username = '<MYSQL USER>'; my $password = '<MYSQL PASS>'; my %attr = ( PrintError=>0, # turn off error reporting via warn() RaiseError=>1 ); # turn on error reporting via die() my $dbh = DBI->connect($dsn,$username,$password, \%attr); say "Connected to the MySQL database.";

      As programmers painless just isn't our thing. Let's really pile it on.

      Start by using AWS's Authentication Plugin with your MySQL database. This is really secure as you can control the accounts directly from Amazon's IAM and passwords are generated instead of recorded. They also require an SSL connection (of course).

      https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/UsingWithRDS.IAMDBAuth.DBAccounts.html

      Now instead of reinventing the wheel here's an article (complete with perl) outlining how to make the connection.

      https://www.capside.com/labs/rds-aurora-database-with-iam-authentication/

      I submit that as an example, don't retype all that. Instead use this package to generate your password.

      use Signer::AWSv4::RDS

      However, it's incomplete. You'll want to take that output and prepend it with your AWS RDS Hostname and port.

      my $password = $host . ':3306/?' . $pass_gen->signed_qstring

      Armed with that you have everything you need to make an AWSAuthenicationPlugin connection and you'll be so excited you'll decide to plug it into your catalyst server.

      It's really a simple matter of overriding the connection subroutine in your Schema.pm like so

      before 'connection' => sub { .. }

      you can generate your password and add a $_[1]->{password} = $password to the result. Fire up catalyst and you're good to go...

      straight to programming hell

      We have a memory leak so when a child process exceeds it's allocated memory we give it a suicide signal (-HUP) and it completes what it was doing before it dies. The parent realizing it died restarts a new child and passes over the db credentials. However, fifteen minutes later the password has expired and the child can't connect.

      I have no idea how to get in the middle of the connection to tell the parent to generate a new password, or tell the child that when they can't connect, they should generate a new password and I'm out of hair to pull out so I gave up and went with my first option - just use SSL.

      I'm happy to clarify anything if it helps someone else. This should probably be a post somewhere.

        At this point (assuming you connected) you're asking yourself, how the heck you know you've connected securely.

        I would check the session variables. eg:

        my $sth = $dbh->prepare (q#SHOW SESSION STATUS LIKE ?#); $sth->execute ('Ssl_version'); (undef, my $sslver) = $sth->fetchrow_array; die "SSL version $sslver insecure" unless $sslver =~ /^TLSv1\.[123]/; $sth->execute ('Ssl_cipher'); (undef, my $cipher) = $sth->fetchrow_array; die "SSL cipher $cipher insecure" if $cipher =~ /NULL/;

        Obviously you can adjust these checks depending on your own personal level of paranoia.