diff --git a/.env.example b/.env.example index 5f7ab85501..dbdfcc3d72 100644 --- a/.env.example +++ b/.env.example @@ -40,12 +40,26 @@ DB_SANITIZE_BY_DEFAULT=false # -------------------------------------------- # OPTIONAL: SSL DATABASE SETTINGS # -------------------------------------------- +# Enable SSL connection to database (true/false) DB_SSL=false + +# Set to true for cloud databases like AWS RDS, Azure Database, Google Cloud SQL +# Set to false for self-hosted databases with client certificates DB_SSL_IS_PAAS=false + +# Required when DB_SSL_IS_PAAS=false (client certificate authentication) DB_SSL_KEY_PATH=null DB_SSL_CERT_PATH=null + +# Path to CA certificate bundle (required for SSL connections) +# For AWS RDS, download from: https://truststore.pki.rds.amazonaws.com/global/global-bundle.pem DB_SSL_CA_PATH=null + +# SSL cipher (optional, leave null for default) DB_SSL_CIPHER=null + +# Verify server certificate (true/false, defaults to false if not set) +# Set to false for development or when using self-signed certificates DB_SSL_VERIFY_SERVER=null # -------------------------------------------- diff --git a/config/database.php b/config/database.php index bffbb5d338..06dde25325 100755 --- a/config/database.php +++ b/config/database.php @@ -101,12 +101,13 @@ return [ 'dump_using_single_transaction' => true, // perform dump using a single transaction 'options' => (env('DB_SSL')) ? ((env('DB_SSL_IS_PAAS')) ? [ PDO::MYSQL_ATTR_SSL_CA => env('DB_SSL_CA_PATH'), // /path/to/ca.pem + PDO::MYSQL_ATTR_SSL_VERIFY_SERVER_CERT => env('DB_SSL_VERIFY_SERVER', false), //true/false ] : [ PDO::MYSQL_ATTR_SSL_KEY => env('DB_SSL_KEY_PATH'), // /path/to/key.pem PDO::MYSQL_ATTR_SSL_CERT => env('DB_SSL_CERT_PATH'), // /path/to/cert.pem PDO::MYSQL_ATTR_SSL_CA => env('DB_SSL_CA_PATH'), // /path/to/ca.pem PDO::MYSQL_ATTR_SSL_CIPHER => env('DB_SSL_CIPHER'), - PDO::MYSQL_ATTR_SSL_VERIFY_SERVER_CERT => env('DB_SSL_VERIFY_SERVER'), //true/false + PDO::MYSQL_ATTR_SSL_VERIFY_SERVER_CERT => env('DB_SSL_VERIFY_SERVER', false), //true/false ]) : [], ], diff --git a/tests/Unit/DatabaseSslConfigurationTest.php b/tests/Unit/DatabaseSslConfigurationTest.php new file mode 100644 index 0000000000..bdc8b7dc60 --- /dev/null +++ b/tests/Unit/DatabaseSslConfigurationTest.php @@ -0,0 +1,101 @@ + null + ]); + + // Test PAAS mode SSL configuration + config([ + 'database.connections.mysql.options' => $this->getSslOptions(true, false, true) // isPaas=true, verifyServer=false, sslEnabled=true + ]); + + $options = config('database.connections.mysql.options'); + + $this->assertArrayHasKey(PDO::MYSQL_ATTR_SSL_CA, $options); + $this->assertArrayHasKey(PDO::MYSQL_ATTR_SSL_VERIFY_SERVER_CERT, $options); + + // PAAS mode should not include client certificate attributes + $this->assertArrayNotHasKey(PDO::MYSQL_ATTR_SSL_KEY, $options); + $this->assertArrayNotHasKey(PDO::MYSQL_ATTR_SSL_CERT, $options); + $this->assertArrayNotHasKey(PDO::MYSQL_ATTR_SSL_CIPHER, $options); + } + + public function testMysqlSslConfigurationWithNonPaasMode(): void + { + config([ + 'database.connections.mysql.options' => null + ]); + + // Test non-PAAS mode SSL configuration + config([ + 'database.connections.mysql.options' => $this->getSslOptions(false, false, true) // isPaas=false, verifyServer=false, sslEnabled=true + ]); + + $options = config('database.connections.mysql.options'); + + // Non-PAAS mode should include all SSL attributes + $this->assertArrayHasKey(PDO::MYSQL_ATTR_SSL_CA, $options); + $this->assertArrayHasKey(PDO::MYSQL_ATTR_SSL_VERIFY_SERVER_CERT, $options); + $this->assertArrayHasKey(PDO::MYSQL_ATTR_SSL_KEY, $options); + $this->assertArrayHasKey(PDO::MYSQL_ATTR_SSL_CERT, $options); + $this->assertArrayHasKey(PDO::MYSQL_ATTR_SSL_CIPHER, $options); + } + + public function testMysqlSslConfigurationWithoutSsl(): void + { + config([ + 'database.connections.mysql.options' => null + ]); + + // Test SSL disabled configuration + config([ + 'database.connections.mysql.options' => $this->getSslOptions(true, false, false) // isPaas=true, verifyServer=false, sslEnabled=false + ]); + + $options = config('database.connections.mysql.options'); + + // When SSL is disabled, options should be empty + $this->assertEmpty($options); + } + + public function testSslVerifyServerDefaultsToFalse(): void + { + // Test that SSL_VERIFY_SERVER defaults to false when not explicitly set + $options = $this->getSslOptions(true, null, true); // isPaas=true, verifyServer=null, sslEnabled=true + + $this->assertArrayHasKey(PDO::MYSQL_ATTR_SSL_VERIFY_SERVER_CERT, $options); + $this->assertFalse($options[PDO::MYSQL_ATTR_SSL_VERIFY_SERVER_CERT]); + } + + private function getSslOptions(bool $isPaas, ?bool $verifyServer=false, bool $sslEnabled=true): array + { + // simulates the SSL options logic from database.php + if (!$sslEnabled) { + return []; + } + + if ($isPaas) { + return [ + PDO::MYSQL_ATTR_SSL_CA => '/path/to/ca.pem', + PDO::MYSQL_ATTR_SSL_VERIFY_SERVER_CERT => $verifyServer ?? false, + ]; + } + + return [ + PDO::MYSQL_ATTR_SSL_KEY => '/path/to/key.pem', + PDO::MYSQL_ATTR_SSL_CERT => '/path/to/cert.pem', + PDO::MYSQL_ATTR_SSL_CA => '/path/to/ca.pem', + PDO::MYSQL_ATTR_SSL_CIPHER => null, + PDO::MYSQL_ATTR_SSL_VERIFY_SERVER_CERT => $verifyServer ?? false, + ]; + } +}