Docker, AspNetCore, рекомендации по использованию строки подключения к БД

Я провел последнюю неделю или около того, пытаясь изучить докер и все, что он может сделать, однако одна вещь, которую я пытаюсь обдумать, это лучшая практика о том, как управлять секретами, особенно в отношении строк подключения к базе данных и как они должны храниться.

У меня в голове есть план, где я хочу иметь образ докера, который будет содержать веб-сайт ASP.NET Core, базу данных MySQL и интерфейс PHPMyAdmin, и развернуть его на капле, которую я имею в DigitalOcean.

Я немного поигрался, и у меня есть файл docker-compose.yml, в котором MySQL DB и PhpMyAdmin правильно связаны друг с другом.

version: "3"

services:
  db:
    image: mysql:latest
    container_name: mysqlDatabase
    environment:
    - MYSQL_ROOT_PASSWORD=0001
    - MYSQL_DATABASE=atestdb
    restart: always
    volumes:
    - /var/lib/mysql
  phpmyadmin:
    image: phpmyadmin/phpmyadmin
    container_name: db-mgr
    ports:
    - "3001:80"
    environment:
    - PMA_HOST=db
    restart: always
    depends_on:
    - db

Это правильно создает базу данных MySQL для меня, и я могу подключиться к ней с работающим внешним интерфейсом PHPMyAdmin, используя root / 0001 в качестве комбинированного имени пользователя / пароля.

Я знаю, что теперь мне нужно добавить к этому свое веб-приложение AspNetCore, но я все еще нахожусь в тупике из-за лучшего способа получить пароль БД.

Я изучил рой / секреты Docker, но до сих пор не до конца понимаю, как это работает, особенно если я хочу проверить свой файл docker-compose в GIT/SCM. Другие вещи, которые я прочитал, предложили использовать переменные среды, но я все еще не понимаю, как это отличается от простой проверки строки подключения в моем файле appsettings.json или, в этом отношении, как это будет работать в полный конвейер сборки CI/CD.

Этот вопрос помог мне немного разобраться в этом вопросе, но у них все еще есть пароль БД в файле docker-compose.

Может быть, я пытаюсь переосмыслить это

Любая помощь, руководство или предложения будут с благодарностью приняты.

1 ответ

Если вы используете Docker Swarm, вы можете воспользоваться функцией секретов и сохранить всю конфиденциальную информацию, такую ​​как пароли или даже всю строку подключения, как секрет докера.

Для каждого созданного секрета Docker будет монтировать файл внутри контейнера. По умолчанию он монтирует все секреты в папку /run/secrets.

Вы можете создать настраиваемого поставщика конфигурации, чтобы прочитать секрет и сопоставить его как значение конфигурации.

public class SwarmSecretsConfigurationProvider : ConfigurationProvider
{
    private readonly IEnumerable<SwarmSecretsPath> _secretsPaths;

    public SwarmSecretsConfigurationProvider(
        IEnumerable<SwarmSecretsPath> secretsPaths)
    {
        _secretsPaths = secretsPaths;
    }

    public override void Load()
    {
        var data = new Dictionary<string, string>
            (StringComparer.OrdinalIgnoreCase);

        foreach (var secretsPath in  _secretsPaths)
        {
            if (!Directory.Exists(secretsPath.Path) && !secretsPath.Optional)
            {
                throw new FileNotFoundException(secretsPath.Path);
            }
            foreach (var filePath in Directory.GetFiles(secretsPath.Path))
            {
                var configurationKey = Path.GetFileName(filePath);
                if (secretsPath.KeyDelimiter != ":")
                {
                    configurationKey = configurationKey
                        .Replace(secretsPath.KeyDelimiter, ":");
                }
                var configurationValue = File.ReadAllText(filePath);
                data.Add(configurationKey, configurationValue);
            }
        }
        Data = data;
    }
}

затем вы должны добавить настраиваемого поставщика в конфигурацию приложения

public static IHostBuilder CreateHostBuilder(string[] args)
{
    return Host.CreateDefaultBuilder(args)
        .ConfigureAppConfiguration((hostingContext, config) =>
        {
            config.AddSwarmSecrets();
        })
        .ConfigureWebHostDefaults(webBuilder =>
        {
            webBuilder.UseStartup<Startup>();
        });
}

тогда, если вы создадите секрет с именем "my_connection_secret"

$ echo "Server=myServerAddress;Database=myDataBase;Uid=myUsername;Pwd=myPassword;" \
| docker secret create my_connection_secret -

и сопоставьте его со своей службой как строки подключения:DatabaseConnection

services:
  app:
    secrets:
      - target: ConnectionStrings:DatabaseConnection
        source: my_connection_secret

это будет то же самое, что записать его в appsettings.config

{
  "ConnectionStrings": {
    "DatabaseConnection": "Server=myServerAddress;Database=myDataBase;Uid=myUsername;Pwd=myPassword;"
  }
}

Если вы не хотите хранить всю строку подключения в секрете, вы можете использовать заполнитель для пароля.

Server=myServerAddress;Database=myDataBase;Uid=myUsername;Pwd={{pwd}};

и используйте другой поставщик настраиваемой конфигурации, чтобы заменить его паролем, сохраненным в секрете.

В своем сообщении в блоге " Как управлять паролями в файлах конфигурации ASP.NET Core" я подробно объясняю, как создать настраиваемый поставщик конфигурации, который позволяет хранить в секрете только пароль и обновлять строку конфигурации во время выполнения. Также полный исходный код этой статьи размещен на https://www.github.com/gabihodoroaga/blog-app-secrets.

Секреты сложны. Я скажу, что включение их в переменные среды немного поднимает проблему, особенно когда вы используете только docker-compose (а не что-то более изощренное, например, kubernetes или swarm). Ваш файл docker-compose.yaml будет выглядеть примерно так:

environment:
- MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD}

Compose будет извлекать MYSQL_ROOT_PASSWORD из файла.env или переменной командной строки / среды, когда вы раскручиваете свои сервисы. Большинство служб CI/CD предоставляют способы (либо через графический интерфейс, либо через некоторый интерфейс командной строки) шифрования секретов, которые сопоставляются с переменными среды на сервере CI.

Нельзя сказать, что переменные среды обязательно являются лучшим способом обработки секретов. Но если вы перейдете на платформу оркестровки, такую ​​как kubernetes, будет прямой путь к сопоставлению секретов kubernetes с теми же переменными среды.

Другие вопросы по тегам