From 4e7d09035a07e8b2768dbb936c5200803d4cbbe1 Mon Sep 17 00:00:00 2001 From: Alejandro Celaya Date: Wed, 18 Dec 2024 09:47:21 +0100 Subject: [PATCH] Support encrypted connections to MySQL/Maria and Postgres --- config/autoload/entity-manager.global.php | 30 +++++++++++++++-------- module/Core/src/Config/EnvVars.php | 2 ++ 2 files changed, 22 insertions(+), 10 deletions(-) diff --git a/config/autoload/entity-manager.global.php b/config/autoload/entity-manager.global.php index 4338a8b6..1bd3db44 100644 --- a/config/autoload/entity-manager.global.php +++ b/config/autoload/entity-manager.global.php @@ -12,9 +12,10 @@ use function Shlinkio\Shlink\Core\ArrayUtils\contains; return (static function (): array { $driver = EnvVars::DB_DRIVER->loadFromEnv(); + $useEncryption = (bool) EnvVars::DB_USE_ENCRYPTION->loadFromEnv(); $isMysqlCompatible = contains($driver, ['maria', 'mysql']); - $resolveDriver = static fn () => match ($driver) { + $doctrineDriver = match ($driver) { 'postgres' => 'pdo_pgsql', 'mssql' => 'pdo_sqlsrv', default => 'pdo_mysql', @@ -23,31 +24,40 @@ return (static function (): array { $value = $envVar->loadFromEnv(); return $value === null ? null : (string) $value; }; - $resolveCharset = static fn () => match ($driver) { + $charset = match ($driver) { // This does not determine charsets or collations in tables or columns, but the charset used in the data // flowing in the connection, so it has to match what has been set in the database. 'maria', 'mysql' => 'utf8mb4', 'postgres' => 'utf8', default => null, }; - - $resolveConnection = static fn () => match ($driver) { + $driverOptions = match ($driver) { + 'mssql' => ['TrustServerCertificate' => 'true'], + 'maria', 'mysql' => ! $useEncryption ? [] : [ + 1007 => true, // PDO::MYSQL_ATTR_SSL_KEY: Require using SSL + 1014 => false, // PDO::MYSQL_ATTR_SSL_VERIFY_SERVER_CERT: Trust any certificate + ], + 'postgres' => ! $useEncryption ? [] : [ + 'sslmode' => 'require', // Require connections to be encrypted + 'sslrootcert' => '', // Allow any certificate + ], + default => [], + }; + $connection = match ($driver) { null, 'sqlite' => [ 'driver' => 'pdo_sqlite', 'path' => 'data/database.sqlite', ], default => [ - 'driver' => $resolveDriver(), + 'driver' => $doctrineDriver, 'dbname' => EnvVars::DB_NAME->loadFromEnv(), 'user' => $readCredentialAsString(EnvVars::DB_USER), 'password' => $readCredentialAsString(EnvVars::DB_PASSWORD), 'host' => EnvVars::DB_HOST->loadFromEnv(), 'port' => EnvVars::DB_PORT->loadFromEnv(), 'unix_socket' => $isMysqlCompatible ? EnvVars::DB_UNIX_SOCKET->loadFromEnv() : null, - 'charset' => $resolveCharset(), - 'driverOptions' => $driver !== 'mssql' ? [] : [ - 'TrustServerCertificate' => 'true', - ], + 'charset' => $charset, + 'driverOptions' => $driverOptions, ], }; @@ -63,7 +73,7 @@ return (static function (): array { Events::postFlush => [ShortUrlVisitsCountTracker::class, OrphanVisitsCountTracker::class], ], ], - 'connection' => $resolveConnection(), + 'connection' => $connection, ], ]; diff --git a/module/Core/src/Config/EnvVars.php b/module/Core/src/Config/EnvVars.php index e2a6d38a..f8042feb 100644 --- a/module/Core/src/Config/EnvVars.php +++ b/module/Core/src/Config/EnvVars.php @@ -36,6 +36,7 @@ enum EnvVars: string case DB_HOST = 'DB_HOST'; case DB_UNIX_SOCKET = 'DB_UNIX_SOCKET'; case DB_PORT = 'DB_PORT'; + case DB_USE_ENCRYPTION = 'DB_USE_ENCRYPTION'; case GEOLITE_LICENSE_KEY = 'GEOLITE_LICENSE_KEY'; case CACHE_NAMESPACE = 'CACHE_NAMESPACE'; case REDIS_SERVERS = 'REDIS_SERVERS'; @@ -147,6 +148,7 @@ enum EnvVars: string 'mssql' => '1433', default => '3306', }, + self::DB_USE_ENCRYPTION => false, self::MERCURE_INTERNAL_HUB_URL => self::MERCURE_PUBLIC_HUB_URL->loadFromEnv(),