GCE(Google Compute Engine)インスタンスからSSL経由でGoogle CloudSQLを使用しようとしています。私の問題は、SSL経由でCloudSQLインスタンスに接続できないことです。
mysqlコマンドは正常に機能します。認定ファイルを使用してCloudSQLインスタンスに接続できます。
mysql -uroot -p -h [IP Address] --ssl-ca=/home/user/.cert/server-ca.pem --ssl-cert=/home/user/.cert/client-cert.pem --ssl-key=/home/user/.cert/client-key.pem
しかし、PHPプログラムからアクセスすると、次のような警告と致命的なエラーが発生しました。
<?php
$pdo = new PDO('mysql:Host=[IP Address];dbname=testdb', 'root', 'test', array(
PDO::MYSQL_ATTR_SSL_KEY =>'/home/user/.cert/client-key.pem',
PDO::MYSQL_ATTR_SSL_CERT=>'/home/user/.cert/client-cert.pem',
PDO::MYSQL_ATTR_SSL_CA =>'/home/user/.cert/server-ca.pem'
)
);
$stmt = $pdo->query("SHOW TABLES;");
$row = $stmt->fetch(PDO::FETCH_ASSOC);
print_r($row);
?>
PHP Warning: PDO::__construct(): Peer certificate CN=`[GCP project name]:[Cloud SQL instance name]' did not match expected CN=`[IP Address]' in /tmp/mysql.php on line 7
Fatal error: Uncaught exception 'PDOException' with message 'SQLSTATE[HY000] [2002] ' in /tmp/mysql.php on line 7
Mysqliを使用したときに同じエラーが発生しました。
$mysqli = mysqli_init();
mysqli_options($mysqli, MYSQLI_OPT_SSL_VERIFY_SERVER_CERT, true);
$mysqli->ssl_set('/home/user/.cert/client-key.pem',
'/home/user/.cert/client-cert.pem',
'/home/user/.cert/server-ca.pem',
NULL,NULL);
$mysqli->real_connect('[IP Address]', 'root', 'test', 'testdb', 3306, NULL, MYSQLI_CLIENT_SSL);
PHP Warning: mysqli::real_connect(): Peer certificate CN=`[GCP project name]:[Cloud SQL instance name]' did not match expected CN=`[IP Address]' in /tmp/mysql3.php on line 30
Warning: mysqli::real_connect(): (HY000/2002): in /tmp/mysql3.php on line 30
この質問は私の場合に関連しているように見えますが、まだ答えはありません。 PHPでMysqlに接続するためのSSL自己署名証明書
誰かが解決策について知っていますか?
アップデート1
バグが報告されています。 https://bugs.php.net/bug.php?id=710
ここで非常によく似た質問。 Google Cloud SQL SSLはピア証明書の検証に失敗します
私のPHPバージョンは5.6.14です。MYSQLI_CLIENT_SSL_DONT_VERIFY_SERVER_CERTを使用するように5.6.16に更新します。
アップデート2
Mysqliを使用すると修正されました
私がしたことは次のとおりです。
1 PHPを5.6.20に更新しました
Sudo apt-get install php5
2MYSQLI_CLIENT_SSL_DONT_VERIFY_SERVER_CERTオプションを次のように配置します。
$mysqli->real_connect('[IP Address]', 'root', 'test', 'testdb', 3306, NULL, MYSQLI_CLIENT_SSL_DONT_VERIFY_SERVER_CERT);
私のアプリケーションは、いくつかの理由でmysqliとPDOの両方を使用しています。私は今、PDOのソリューションを探しています。
アップデート3
このバグレポートは、PDOのケースについて示しています。まだ修正されていないようです。
https://bugs.php.net/bug.php?id=71845
私の知る限り、PDOを解決する方法はありません。
アップデート4
一部の人々はグーグルのCN名のデザインを非難します(私は実際にそれらに同意します..)
最悪なのは、不可能なCN名(:)を使用することです。 CNにコロンがない場合は、ホストファイルのIPとCNをマップして、ピア検証が実行されたときに合格できるようにすることができます。コロンを使用すると、phpはホストでありポートであると見なします
とグーグルのスタッフ?問題を理解します。
IPで接続するのは理想的ではないという現状を理解しています。
しかし、彼らは「プロキシ」と呼ばれるソリューションを提供しているようです。
https://groups.google.com/forum/#!topic/google-cloud-sql-discuss/gAzsuCzPla
私はCloudSQLの第2世代を使用しており、アプリケーションはGCEでホストされています。だから私はプロキシの方法を使うことができると思います。今からやってみます。
アップデート5
プロキシアクセスを設定します。 PDOとmysqliの両方のアクセスを解決しました。
Ubuntuにプロキシをインストールする
$ wget https://dl.google.com/cloudsql/cloud_sql_proxy.linux.AMD64
$ mv cloud_sql_proxy.linux.AMD64 cloud_sql_proxy
$ chmod +x cloud_sql_proxy
$ Sudo mkdir /cloudsql; Sudo chmod 777 /cloudsql
$ ./cloud_sql_proxy -dir=/cloudsql -instances=<project name>:us-central1:mydb
PDO
<?php
$pdo = new pdo('mysql:unix_socket=/cloudsql/<project name>:us-central1:mydb;dbname=testdb','root','test');
$stmt = $pdo->query("SHOW TABLES;");
$row = $stmt->fetch(PDO::FETCH_ASSOC);
print_r($row);
?>
mysqli
$mysqli = mysqli_connect('localhost', 'root', 'test', 'testdb', 3306, '/cloudsql/<project name>:us-central1');
$sql = "SELECT id FROM users";
if ($result = $mysqli->query($sql)) {
while ($row = $result->fetch_assoc()) {
echo $row["id"] . "\n";
}
$result->close();
}
$mysqli->close();
refs(日本語)
http://blog.hrendoh.com/connecting-to-google-cloud-sql-using-mysql-client/http://blog.hrendoh.com/google-appengine -php-using-cloud-sql /
Google Cloudを使用しない、またはプロキシソリューションの恩恵を受けられないPDO接続の場合、バグが修正され、現在マージされています。現在、これには定数があります(2017年4月から):
PDO::MYSQL_ATTR_SSL_VERIFY_SERVER_CERT => false,
http://git.php.net/?p=php-src.git;a=commit;h=247ce052cd0fc7d0d8ea1a0e7ea2075e9601766a
つまり、PDOとmysqliの両方からアクセスする必要がある場合は、Cloud SQLProxyを使用してください。あなたは選択肢がありません。
Mysqliの場合、以下を追加します。
MYSQLI_CLIENT_SSL_DONT_VERIFY_SERVER_CERT
to real_connect()この問題の私のインスタンスを解決しました。
例(必要に応じて、ホスト、ユーザー、パスワード、およびデータベースを置き換えます):
$db_connection->real_connect('ip address or Host', 'user', 'password', 'database', 3306, NULL, MYSQLI_CLIENT_SSL_DONT_VERIFY_SERVER_CERT);
完全なphpmysqli SSL接続スクリプト:
// check if openssl is enabled on server
if(!extension_loaded('openssl')) {
throw new Exception('This app needs the Open SSL PHP extension and it is missing.');
}
// start connection
$db_connection = mysqli_init();
// set ssl config (update with your certs location)
$db_connection->ssl_set('/etc/my.cnf.d/certs/client-key.pem','/etc/my.cnf.d/certs/client-cert.pem', '/etc/my.cnf.d/certs/ca-cert.pem', NULL, NULL);
// connect (update with your Host, db and credentials)
$db_connection->real_connect('ip address or Host', 'user', 'password', 'database', 3306, NULL, MYSQLI_CLIENT_SSL_DONT_VERIFY_SERVER_CERT);
作成クラスターでホストされているMySQLデータベースでも同じ問題が発生しました。
何時間も検索してテストした後、最善の解決策は、MYSQLI_CLIENT_SSL_DONT_VERIFY_SERVER_CERT
フラグを使用してサーバーから提供された証明書のテストを無効にすることであることがわかりました。
私はそれをPDOでテストしていませんが、mysqli
インターフェースでそれは私のために働いています。一般に、この問題は、クラスターサーバーでホストされているデータベースで発生します。
CakePHP 3.5.x + PHP 7.1.x + SQL Google Cloud + SSLの例
Config /app.phpのファイルを変更します
...
...
/**
* The test connection is used during the test suite.
*/
'default' => [
'className' => 'Cake\Database\Connection',
'driver' => 'Cake\Database\Driver\Mysql',
'persistent' => false,
'Host' => 'xx.xxx.xxx.xxx',
//'port' => 'non_standard_port_number',
'username' => 'user_name_x',
'password' => 'pass_x',
'database' => 'bd_name_x',
'encoding' => 'utf8',
'timezone' => 'UTC',
'cacheMetadata' => true,
'quoteIdentifiers' => false,
'log' => false,
'flags' => [
PDO::MYSQL_ATTR_SSL_KEY => CONFIG.'client-key.pem',
PDO::MYSQL_ATTR_SSL_CERT => CONFIG.'client-cert.pem',
PDO::MYSQL_ATTR_SSL_CA => CONFIG.'server-ca.pem',
PDO::MYSQL_ATTR_SSL_VERIFY_SERVER_CERT => false
],
//'ssl_key' => CONFIG.'client-key.pem',
//'ssl_cert' => CONFIG.'client-cert.pem',
//'ssl_ca' => CONFIG.'server-ca.pem',
//'init' => ['SET GLOBAL innodb_stats_on_metadata = 0'],
],
],
...
...
例PHP純粋+ PDO + SSL:
$ssl_key = CONFIG.'client-key.pem';
$ssl_cert = CONFIG.'client-cert.pem';
$ssl_ca = CONFIG.'server-ca.pem';
$pdo = new PDO('mysql:Host=xxx.xxx.xxx.xxx;dbname=db_name_x', 'user_name_x', 'pass_x', array(
PDO::MYSQL_ATTR_SSL_KEY => '/path/full/client-key.pem',
PDO::MYSQL_ATTR_SSL_CERT => '/path/full/client-cert.pem',
PDO::MYSQL_ATTR_SSL_CA => '/path/full/server-ca.pem',
PDO::MYSQL_ATTR_SSL_VERIFY_SERVER_CERT => false
)
);
$statement = $pdo->query("SHOW TABLES;");
var_dump($statement);
$row = $statement->fetch(PDO::FETCH_ASSOC);
echo json_encode($row);
exit();