Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unable to connect to AWS Aurora MySQL 3.04.0 (MySQL 8.0.28) over TLS #129

Open
GrahamCampbell opened this issue Aug 2, 2023 · 5 comments
Labels

Comments

@GrahamCampbell
Copy link

GrahamCampbell commented Aug 2, 2023

Code to make the connection pool:

            $config = [/* OMITTED */];

            $tlsContext = (new ClientTlsContext())
                ->withCaFile($config['options'][PDO::MYSQL_ATTR_SSL_CA] ?? null);

            return new MysqlConnectionPool(
                new MysqlConfig(
                    $config['host'],
                    (int) $config['port'],
                    $config['username'],
                    $config['password'],
                    $config['database'],
                    (new ConnectContext())->withTlsContext($tlsContext),
                    $config['charset'],
                    $config['collation'],
                ),
            );

Then, the folowing code hangs forever trying to establish a connection, despite the default connect timeout being 10 seconds.

        foreach ($this->db->query('SELECT 1 AS value') as $row) {
            var_dump($row['value']);
        }

Digging into the code, we're getting stuck at:

                        $connection = (
                            $this->future = async(fn () => $this->connector->connect($this->config))
                        )->await();

on line 243 of Amp\Sql\CommonConnectionPool.

Digging further, it's the call to Amp\Mysql\SocketMysqlConnection::initialize which is hanging. Indeed, the $future->await() call on line 228 of Amp\Mysql\Internal\ConnectionProcessor::connect.


Installed versions:

PHP 8.2.8 (cli) (built: Jul  6 2023 10:57:44) (NTS)
Copyright (c) The PHP Group
Zend Engine v4.2.8, Copyright (c) Zend Technologies
    with Zend OPcache v8.2.8, Copyright (c), by Zend Technologies

amphp/amp                          v3.0.0
amphp/byte-stream                  v2.0.1
amphp/cache                        v2.0.0
amphp/dns                          v2.0.1
amphp/mysql                        v3.0.0-beta.6
amphp/parser                       v1.1.0
amphp/pipeline                     v1.0.0
amphp/process                      v2.0.1
amphp/serialization                v1.0.0
amphp/socket                       v2.1.0
amphp/sql                          v2.0.0-beta.4
amphp/sql-common                   v2.0.0-beta.6
amphp/sync                         v2.0.0
amphp/windows-registry             v1.0.0
@GrahamCampbell
Copy link
Author

It looks like the server side is complaining of a bad handshake from the client.

[Note] [MY-010914] [Server] Bad handshake

@GrahamCampbell
Copy link
Author

GrahamCampbell commented Aug 2, 2023

It looks like stream_socket_enable_crypto inside of the call to setupTls keeps returning 0.

            EventLoop::queue(function () use ($payload): void {
                try {
                    $this->write(\implode($payload));

                    $this->socket->setupTls();

                    $this->sendHandshake(true);
                } catch (\Throwable $e) {
                    $this->free($e);
                }
            });

@GrahamCampbell
Copy link
Author

GrahamCampbell commented Aug 2, 2023

It looks like we end up hanging forever because $suspension->suspend(); waits forever after a couple of trips around the while, I guess because the server is done sending bytes, after deciding the client is not behaving itself.

    while (true) {
        $cancellation->throwIfRequested();

        $suspension = EventLoop::getSuspension();

        // Watcher is guaranteed to be created, because we throw above if cancellation has already been requested
        $cancellationId = $cancellation->subscribe(static function ($e) use ($suspension, &$callbackId): void {
            EventLoop::cancel($callbackId);

            $suspension->throw($e);
        });

        $callbackId = EventLoop::onReadable($socket, static function () use (
            $suspension,
            $cancellation,
            $cancellationId,
        ): void {
            $cancellation->unsubscribe($cancellationId);

            $suspension->resume();
        });

        try {
            $suspension->suspend();
        } finally {
            EventLoop::cancel($callbackId);
        }

        try {
            \set_error_handler($errorHandler);
            $result = \stream_socket_enable_crypto($socket, enable: true);
            if ($result === false) {
                $message = \feof($socket) ? 'Connection reset by peer' : 'Unknown error';
                throw new TlsException('TLS negotiation failed: ' . $message);
            }
        } finally {
            \restore_error_handler();
        }

        // If $result is 0, just wait for the next invocation
        if ($result === true) {
            break;
        }
    }

@trowski
Copy link
Member

trowski commented Dec 19, 2023

@bwoebi Do you have any idea what might be going on here with TLS?

@trowski trowski added the bug label Dec 19, 2023
@trowski
Copy link
Member

trowski commented Dec 19, 2023

@GrahamCampbell I realize it's been quite some time since you opened this issue, but would you be able to try again with the latest dev-3.x. I found an issue with connecting with TLS which may have been preventing a proper handshake.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Development

No branches or pull requests

2 participants