Ivan Gabriele
Ivan Gabriele

Reputation: 6900

Symfony : how to set SSL parameters in Doctrine DBAL configuration (YAML)?

I'd like to add my SSL cert and key files to Doctrine DBAL configuration but I don't see how to achieve that.

In PHP, I just have to write something like :

$databaseHandler = new \PDO(
    'mysql:host=my_host;dbname=my_db',
    'username',
    'password',
    array(
        \PDO::MYSQL_ATTR_SSL_KEY   => '.../client-key.pem',
        \PDO::MYSQL_ATTR_SSL_CERT  => '.../client-cert.pem',
        \PDO::MYSQL_ATTR_SSL_CA    => '.../ca-cert.pem'
    )
);

I understand there is a Custom Driver Option driverOptions, and I saw this answer but I'm not sure about how to translate that into YAML.

I have the feeling I should write something close to :

doctrine:
    dbal:
        driver:   "%database_driver%"
        host:     "%database_host%"
        port:     "%database_port%"
        dbname:   "%database_name%"
        user:     "%database_user%"
        password: "%database_password%"
        charset:  UTF8
        driverOptions:
            PDO::MYSQL_ATTR_SSL_CA: '.../client-key.pem'
            PDO::MYSQL_ATTR_SSL_CERT: '.../client-cert.pem'
            PDO::MYSQL_ATTR_SSL_CA: '.../ca-cert.pem'

But double colons won't really please YAML...

Upvotes: 8

Views: 15454

Answers (7)

alakin_11
alakin_11

Reputation: 719

I am using PHP 5.6.40 on docker and have been debugging why my local would not connect via ssl. For some weird reason it wants const 1009 instead of 1012. Dropping this answer here in case anyone stumbles upon it on the future.

doctrine:
    dbal:
        connections:
            default:
                options:
                    1001: true
                    1009: %ssl_cert_path%

Upvotes: 0

Robert
Robert

Reputation: 126

Since Symfony 3.2 this became a lot easier:

doctrine:
    dbal:
        <other configs>
        options:
            !php/const:PDO::MYSQL_ATTR_SSL_CA: %ca_cert%
            !php/const:PDO::MYSQL_ATTR_SSL_KEY: %private_key%
            !php/const:PDO::MYSQL_ATTR_SSL_CERT: %public_cert%

Upvotes: 11

dicotout
dicotout

Reputation: 401

Now in 2020, with Symfony > 4.2, the solution is :

# Doctrine Configuration
doctrine:
    dbal:
        driver:   pdo_mysql
        host:     "%database_host%"
        port:     "%database_port%"
        dbname:   "%database_name%"
        user:     "%database_user%"
        password: "%database_password%"
        charset:  UTF8
        # Options for SSL connection
        options:
            !php/const PDO::MYSQL_ATTR_SSL_CA : %ca_cert%
            !php/const PDO::MYSQL_ATTR_SSL_KEY : %private_key%
            !php/const PDO::MYSQL_ATTR_SSL_CERT : %public_cert%

Source : symfony.com/doc/4.2/service_container/parameters.html

Tested with Symfony 5.1.8

Upvotes: 4

Colin O&#39;Dell
Colin O&#39;Dell

Reputation: 8647

An alternative approach would be installing composer/ca-bundle to help find the path to the CA root bundle and use a custom compiler pass to automagically register that path with Doctrine:

<?php

namespace App\DepenedencyInjection\Compiler;

use Composer\CaBundle\CaBundle;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;

/**
 * Registers a CA root bundle with the PDO MySQL driver used by Doctrine DBAL
 *
 * This allows Doctrine to connect to MySQL instances that force SSL encryption, such as Azure's.
 */
final class RegisterCABundleWithPDOMysqlDriverPass implements CompilerPassInterface
{
    /**
     * @inheritDoc
     */
    public function process(ContainerBuilder $container)
    {
        $caPathOrFile = CaBundle::getSystemCaRootBundlePath();

        foreach ($container->getParameter('doctrine.connections') ?? [] as $connectionName) {
            $definition = $container->getDefinition($connectionName);
            $options = $definition->getArgument(0) ?? [];
            $options['driverOptions'][\PDO::MYSQL_ATTR_SSL_CA] = $caPathOrFile;
            $definition->setArgument(0, $options);
        }
    }
}

Upvotes: 1

Alvin Bunk
Alvin Bunk

Reputation: 7764

I found a much easier way than the rest. Make the following settings in app/config/config.yml:

# Doctrine Configuration
doctrine:
    dbal:
        driver:   pdo_mysql
        host:     "%database_host%"
        port:     "%database_port%"
        dbname:   "%database_name%"
        user:     "%database_user%"
        password: "%database_password%"
        charset:  UTF8
        # Options for SSL connection
        options:
            MYSQL_ATTR_SSL_CA : %ca_cert%
            MYSQL_ATTR_SSL_KEY : %private_key%
            MYSQL_ATTR_SSL_CERT : %public_cert%

Then in your app/config/parameters.yml file:

parameters:
    ...
    # SSL Info
    private_key: /etc/my.cnf.d/certs/client-key.pem
    public_cert: /etc/my.cnf.d/certs/client-cert.pem
    ca_cert: /etc/my.cnf.d/certs/ca-cert.pem

I tested this on Symfony3 and this works great. The paths above may be different, in particular the certs may be different depending on your distro and how you set it up.

Upvotes: 8

user2608603
user2608603

Reputation:

Symfony configuration via yaml (and possibly xml), doesn't allow the keys to be dynamically set, which means you can't use the constants. To get around this, you can create an extra PHP config file that just handles making a key out of the constants.

The solution in a Gist is here: https://gist.github.com/samsch/d5243de3924a8ad10df2

The two major features that this utilizes are that a PHP config file can use any string value for the key, including variables, constants; and that you can use parameters as values for other parameters (something I didn't know until I tried it recently.)

So, you add the PHP config file in config.yml:

imports:
    - { resource: parameters.yml }
    - { resource: pdo-constants.php }

pdo-constants.php is this:

<?php
$container->setParameter("pdo_options", [
    PDO::MYSQL_ATTR_SSL_CA => "%pdo_ca_file%",
]);

Add any other constants you need as well.

Then in parameters.yml, you just need the values for your constants:

parameters:
#...
    pdo_ca_file: /pathtocerts/certs/mysql-ca.pem

Now, I'm guessing that working with another DB system which uses PDO constants would be similar, but I've only used this MySQL.

Upvotes: 3

Valentas
Valentas

Reputation: 2175

Instead of PDO constats, You shoul use their values in options:

doctrine:
    dbal:
        connections:
            default:
                driver:   %database_driver%
                host:     %database_host%
                port:     %database_port%
                dbname:   %database_name%
                password: %database_password%
                charset:  UTF8
                options:
                    1010 : %private_key% 
                    1011 : %public_cert% 
                    1012 : %ca_cert%

Upvotes: 1

Related Questions