4

I am using the node-mysql2 library in combination with AWS.RDS.signer.

I have the following function, which creates a connection pool for reusing connections:

const createPool = () => new Promise((resolve, reject) => {
    signer.getAuthToken({
        region: '...',
        hostname: '...',
        port: '...',
        username: '...'
    }, (err, token) => {
        if (err) reject(err)
        const pool = mysql.createPool({
            host: '...',
            port: '...',
            user: '...',
            database: '...',
            password: token,
            ssl: 'Amazon RDS'
            authSwitchHandler: (data, cb) => {
                if (data.pluginName === 'mysql_clear_password') cb(null, Buffer.from(token + '\0'))
            }
        })
        resolve(pool)
    })
})

It works great... for awhile. Then I suddenly start getting this error:

Error: Access denied for user '...'@'...' (using password: YES)

So, what I think is happening, is that the token returned by the aws signer is only valid for a short time, and cannot be used to continuously re-establish connections in a pool.

There is no way to configure the ttl of the rds token using the aws sdk, that I can see. So the only other option I can think of, is to completely end and recreate the pool at a certain fixed interval.

I am wondering if there is anyone out there who may have wrestled with this, and who may have some insight into the best way to solve this problem? Is there a better way to use the rds signer in combination with connection pools?

user1031947
  • 6,294
  • 16
  • 55
  • 88

2 Answers2

3

For node-mysql2 version >= 2.0.0

mysql.createPool({
    ...,
    ssl: 'Amazon RDS',
    authPlugins: {
        mysql_clear_password: () => () =>
            signer.getAuthToken({
                region: '...',
                hostname: '...',
                port: '...',
                username: '...'
            })
    }
});

For node-mysql2 version < 2.0.0

mysql.createPool({
    ...,
    ssl: 'Amazon RDS',
    authSwitchHandler: (data, cb) => {
        if (data.pluginName === 'mysql_clear_password') {
            signer.getAuthToken({
                    region: '...',
                    hostname: '...',
                    port: '...',
                    username: '...'
                },
                (err, token) => {
                    if (err) {
                        cb(err);
                    } else {
                        cb(null, Buffer.from(token + '\0'));
                    }
                }
            );
        } else {
            cb(new Error(`Authentication method ${data.pluginName} is not supported`));
        }
    }
});

See also https://github.com/sidorares/node-mysql2/issues/1017

David Krásný
  • 112
  • 3
  • 10
  • I created the answer (below) initially a comment, but it is impossible to read, so I typed this instead and created an answer. – Terris Mar 07 '20 at 22:34
0

This is a comment.

Amazon has been planning for quite some time to change their certificates for RDS, at least for mySQL.

If your RDS server has been so upgraded (which Amazon will apparently complete in June 2020) and is running and old version of mySQL (<=5.6), when attempting IAM token login, you may get the error:

Error: 139965154551680:error:1425F102:SSL routines:ssl_choose_client_version:unsupported protocol:../deps/openssl/openssl/ssl/statem/statem_lib.c:1929:

To solve this, if you are using NodeJS 12+, start node with --tls-min-v1.0.

Terris
  • 887
  • 1
  • 10
  • 15