diff --git a/.github/workflows/clang-cl-qt6.yml b/.github/workflows/clang-cl-qt6.yml index c58a1ca5c..11f4505e3 100644 --- a/.github/workflows/clang-cl-qt6.yml +++ b/.github/workflows/clang-cl-qt6.yml @@ -271,28 +271,137 @@ jobs: run: | mysqld.exe --initialize-insecure --console - - name: MySQL generate SSL certificates + # We can't generate certificates first and then initialize MySQL data folder, MySQL throws + # error, it also generates all keys and certificates so we have remove them to generate are own + - name: MySQL SSL certificates remove working-directory: ${{ env.TinyMySQLDataPath }} + run: >- + Remove-Item ./ca.pem, ./ca-key.pem, ./server-cert.pem, ./server-key.pem, + ./client-cert.pem, ./client-key.pem + + - name: MySQL SSL certificates initialize + id: openssl-initialize-mysql-certificates + run: | + $folderPath = Join-Path -Path '${{ env.TinyRunnerWorkPath }}' ` + -ChildPath 'tiny-mysql-certificates' + + # Create an empty folder for generating certificates + New-Item -Type Directory $folderPath + + "FolderPath=$folderPath" >> $env:GITHUB_OUTPUT + + # This hash invalidates the MySQL certificates cache every month + $hash = Get-Date -Format 'yyyyMM' + "Hash=$hash" >> $env:GITHUB_OUTPUT + + - name: MySQL SSL certificates restore cache + uses: actions/cache/restore@v3 + id: openssl-cache-mysql-certificates + with: + path: | + ${{ env.folder_path }}/*.pem + key: ${{ runner.os }}-openssl-${{ env.cache_name }}-${{ env.cache_hash }} + env: + # This hash invalidates this certificates cache every month + cache_hash: ${{ steps.openssl-initialize-mysql-certificates.outputs.Hash }} + cache_name: mysql-certificates + folder_path: ${{ steps.openssl-initialize-mysql-certificates.outputs.FolderPath }} + + - name: MySQL SSL certificates generate + if: steps.openssl-cache-mysql-certificates.outputs.cache-hit != 'true' + working-directory: ${{ steps.openssl-initialize-mysql-certificates.outputs.FolderPath }} + run: | + Write-Output '::group::Print openssl version' + openssl.exe version -a + Write-Output '::endgroup::' + + Write-Output '::group::Create .rnd file' + openssl.exe rand -out ./.rnd -writerand ./.rnd + Write-Output '::endgroup::' + + Write-Output '::group::CA certificate' + # -days 32 is important, -days 30 is not enough + openssl.exe req -new -x509 -nodes -subj $env:DB_MYSQL_SSL_SUBJECT_CA -days 32 ` + -keyout ./ca-key.pem -out ./ca.pem + Write-Output '::endgroup::' + + Write-Output '::group::Server certificate' + openssl.exe req -new -nodes -subj $env:DB_MYSQL_SSL_SUBJECT_SERVER -keyout ./server-key.pem ` + -out ./server-req.pem + $env:OPENSSL_SAN = "DNS:${env:DB_MYSQL_HOST}" + openssl.exe x509 -req -CA ./ca.pem -CAkey ./ca-key.pem -days 32 -set_serial 01 ` + -extfile $env:extfile -in ./server-req.pem -out ./server-cert.pem + Write-Output '::endgroup::' + + Write-Output '::group::Client certificate' + openssl.exe req -new -nodes -subj $env:DB_MYSQL_SSL_SUBJECT_CLIENT ` + -keyout ./client-key.pem -out client-req.pem + $env:OPENSSL_SAN = "DNS:${env:DB_MYSQL_HOST_CLIENT}" + openssl.exe x509 -req -CA ./ca.pem -CAkey ./ca-key.pem -days 32 -set_serial 02 ` + -extfile $env:extfile -in ./client-req.pem -out ./client-cert.pem + Write-Output '::endgroup::' + env: + extfile: ${{ github.workspace }}/.github/resources/openssl/usr_cert.cnf + DB_MYSQL_HOST: ${{ secrets.DB_MYSQL_HOST_SSL }} + DB_MYSQL_HOST_CLIENT: ${{ secrets.DB_MYSQL_HOST_CLIENT_SSL }} + DB_MYSQL_SSL_SUBJECT_CA: ${{ secrets.DB_MYSQL_SSL_SUBJECT_CA }} + DB_MYSQL_SSL_SUBJECT_CLIENT: ${{ secrets.DB_MYSQL_SSL_SUBJECT_CLIENT }} + DB_MYSQL_SSL_SUBJECT_SERVER: ${{ secrets.DB_MYSQL_SSL_SUBJECT_SERVER }} + + # Always verify, regardless if certificates were newly generated or restored from the cache + - name: MySQL SSL certificates verify + working-directory: ${{ steps.openssl-initialize-mysql-certificates.outputs.FolderPath }} + run: | + openssl.exe verify -CAfile ./ca.pem ./server-cert.pem ./client-cert.pem + + # Save the cache only if certificates were newly generated + # The actions/cache/save allows to use the Move-Item during the install step + - name: MySQL SSL certificates save cache + if: steps.openssl-cache-mysql-certificates.outputs.cache-hit != 'true' + uses: actions/cache/save@v3 + with: + path: | + ${{ env.folder_path }}/*.pem + key: ${{ steps.openssl-cache-mysql-certificates.outputs.cache-primary-key }} + env: + folder_path: ${{ steps.openssl-initialize-mysql-certificates.outputs.FolderPath }} + + - name: MySQL SSL certificates install + working-directory: ${{ steps.openssl-initialize-mysql-certificates.outputs.FolderPath }} run: | - # It's enough to remove only these three certificate-related files - Remove-Item ./ca.pem, ./server-cert.pem, ./server-key.pem - mysql_ssl_rsa_setup.exe --suffix=TinyORM + Write-Output '::group::Install CA certificate' + Move-Item -Path ./ca.pem -Destination '${{ env.TinyMySQLDataPath }}' + Write-Output '::endgroup::' + + Write-Output '::group::Install server certificates' + Move-Item -Path ./server-cert.pem, ./server-key.pem ` + -Destination '${{ env.TinyMySQLDataPath }}' + Write-Output '::endgroup::' + + Write-Output '::group::Install client certificates' + Move-Item -Path ./client-cert.pem, ./client-key.pem ` + -Destination '${{ env.TinyMySQLDataPath }}' + Write-Output '::endgroup::' - name: MySQL service install/start run: | mysqld.exe --install MySQL Start-Service MySQL + # Securing the root account even on localhost is for testing to make sure that everything + # works as expected - name: MySQL change ${{ secrets.DB_MYSQL_ROOT_USERNAME }} password run: >- "alter user '$env:DB_MYSQL_ROOT_USERNAME'@'localhost' identified with caching_sha2_password by '$env:DB_MYSQL_ROOT_PASSWORD' - require issuer '/CN=MySQL_Server_TinyORM_Auto_Generated_CA_Certificate' and - subject '/CN=MySQL_Server_TinyORM_Auto_Generated_Client_Certificate';" | + require issuer '${{ env.DB_MYSQL_SSL_SUBJECT_CA }}' and + subject '${{ env.DB_MYSQL_SSL_SUBJECT_CLIENT }}';" | mysql.exe --user=$env:DB_MYSQL_ROOT_USERNAME --skip-password env: DB_MYSQL_ROOT_PASSWORD: ${{ secrets.DB_MYSQL_ROOT_PASSWORD }} DB_MYSQL_ROOT_USERNAME: ${{ secrets.DB_MYSQL_ROOT_USERNAME }} + DB_MYSQL_SSL_SUBJECT_CA: ${{ secrets.DB_MYSQL_SSL_SUBJECT_CA }} + DB_MYSQL_SSL_SUBJECT_CLIENT: ${{ secrets.DB_MYSQL_SSL_SUBJECT_CLIENT }} - name: MySQL time zone POSIX tables initialize download id: downloads-initialize-mysql-timezone-tables @@ -390,8 +499,8 @@ jobs: run: >- "create user '$env:DB_MYSQL_USERNAME'@'%' identified with caching_sha2_password by '$env:DB_MYSQL_PASSWORD' - require issuer '/CN=MySQL_Server_TinyORM_Auto_Generated_CA_Certificate' and - subject '/CN=MySQL_Server_TinyORM_Auto_Generated_Client_Certificate'; + require issuer '${{ env.DB_MYSQL_SSL_SUBJECT_CA }}' and + subject '${{ env.DB_MYSQL_SSL_SUBJECT_CLIENT }}'; grant all privileges on ``tinyorm\_%``.* to '$env:DB_MYSQL_USERNAME'@'%'; grant select on ``mysql``.``time_zone_name`` to '$env:DB_MYSQL_USERNAME'@'%'; flush privileges;" | @@ -400,6 +509,8 @@ jobs: DB_MYSQL_PASSWORD: ${{ secrets.DB_MYSQL_PASSWORD }} DB_MYSQL_ROOT_PASSWORD: ${{ secrets.DB_MYSQL_ROOT_PASSWORD }} DB_MYSQL_ROOT_USERNAME: ${{ secrets.DB_MYSQL_ROOT_USERNAME }} + DB_MYSQL_SSL_SUBJECT_CA: ${{ secrets.DB_MYSQL_SSL_SUBJECT_CA }} + DB_MYSQL_SSL_SUBJECT_CLIENT: ${{ secrets.DB_MYSQL_SSL_SUBJECT_CLIENT }} DB_MYSQL_USERNAME: ${{ secrets.DB_MYSQL_USERNAME }} - name: MySQL add libmysql.dll on the $env:Path, INCLUDE, and LIB diff --git a/.github/workflows/msvc2022-qt6.yml b/.github/workflows/msvc2022-qt6.yml index fb5ab783e..d20deb573 100644 --- a/.github/workflows/msvc2022-qt6.yml +++ b/.github/workflows/msvc2022-qt6.yml @@ -284,28 +284,137 @@ jobs: run: | mysqld.exe --initialize-insecure --console - - name: MySQL generate SSL certificates + # We can't generate certificates first and then initialize MySQL data folder, MySQL throws + # error, it also generates all keys and certificates so we have remove them to generate are own + - name: MySQL SSL certificates remove working-directory: ${{ env.TinyMySQLDataPath }} + run: >- + Remove-Item ./ca.pem, ./ca-key.pem, ./server-cert.pem, ./server-key.pem, + ./client-cert.pem, ./client-key.pem + + - name: MySQL SSL certificates initialize + id: openssl-initialize-mysql-certificates + run: | + $folderPath = Join-Path -Path '${{ env.TinyRunnerWorkPath }}' ` + -ChildPath 'tiny-mysql-certificates' + + # Create an empty folder for generating certificates + New-Item -Type Directory $folderPath + + "FolderPath=$folderPath" >> $env:GITHUB_OUTPUT + + # This hash invalidates the MySQL certificates cache every month + $hash = Get-Date -Format 'yyyyMM' + "Hash=$hash" >> $env:GITHUB_OUTPUT + + - name: MySQL SSL certificates restore cache + uses: actions/cache/restore@v3 + id: openssl-cache-mysql-certificates + with: + path: | + ${{ env.folder_path }}/*.pem + key: ${{ runner.os }}-openssl-${{ env.cache_name }}-${{ env.cache_hash }} + env: + # This hash invalidates this certificates cache every month + cache_hash: ${{ steps.openssl-initialize-mysql-certificates.outputs.Hash }} + cache_name: mysql-certificates + folder_path: ${{ steps.openssl-initialize-mysql-certificates.outputs.FolderPath }} + + - name: MySQL SSL certificates generate + if: steps.openssl-cache-mysql-certificates.outputs.cache-hit != 'true' + working-directory: ${{ steps.openssl-initialize-mysql-certificates.outputs.FolderPath }} + run: | + Write-Output '::group::Print openssl version' + openssl.exe version -a + Write-Output '::endgroup::' + + Write-Output '::group::Create .rnd file' + openssl.exe rand -out ./.rnd -writerand ./.rnd + Write-Output '::endgroup::' + + Write-Output '::group::CA certificate' + # -days 32 is important, -days 30 is not enough + openssl.exe req -new -x509 -nodes -subj $env:DB_MYSQL_SSL_SUBJECT_CA -days 32 ` + -keyout ./ca-key.pem -out ./ca.pem + Write-Output '::endgroup::' + + Write-Output '::group::Server certificate' + openssl.exe req -new -nodes -subj $env:DB_MYSQL_SSL_SUBJECT_SERVER -keyout ./server-key.pem ` + -out ./server-req.pem + $env:OPENSSL_SAN = "DNS:${env:DB_MYSQL_HOST}" + openssl.exe x509 -req -CA ./ca.pem -CAkey ./ca-key.pem -days 32 -set_serial 01 ` + -extfile $env:extfile -in ./server-req.pem -out ./server-cert.pem + Write-Output '::endgroup::' + + Write-Output '::group::Client certificate' + openssl.exe req -new -nodes -subj $env:DB_MYSQL_SSL_SUBJECT_CLIENT ` + -keyout ./client-key.pem -out client-req.pem + $env:OPENSSL_SAN = "DNS:${env:DB_MYSQL_HOST_CLIENT}" + openssl.exe x509 -req -CA ./ca.pem -CAkey ./ca-key.pem -days 32 -set_serial 02 ` + -extfile $env:extfile -in ./client-req.pem -out ./client-cert.pem + Write-Output '::endgroup::' + env: + extfile: ${{ github.workspace }}/.github/resources/openssl/usr_cert.cnf + DB_MYSQL_HOST: ${{ secrets.DB_MYSQL_HOST_SSL }} + DB_MYSQL_HOST_CLIENT: ${{ secrets.DB_MYSQL_HOST_CLIENT_SSL }} + DB_MYSQL_SSL_SUBJECT_CA: ${{ secrets.DB_MYSQL_SSL_SUBJECT_CA }} + DB_MYSQL_SSL_SUBJECT_CLIENT: ${{ secrets.DB_MYSQL_SSL_SUBJECT_CLIENT }} + DB_MYSQL_SSL_SUBJECT_SERVER: ${{ secrets.DB_MYSQL_SSL_SUBJECT_SERVER }} + + # Always verify, regardless if certificates were newly generated or restored from the cache + - name: MySQL SSL certificates verify + working-directory: ${{ steps.openssl-initialize-mysql-certificates.outputs.FolderPath }} + run: | + openssl.exe verify -CAfile ./ca.pem ./server-cert.pem ./client-cert.pem + + # Save the cache only if certificates were newly generated + # The actions/cache/save allows to use the Move-Item during the install step + - name: MySQL SSL certificates save cache + if: steps.openssl-cache-mysql-certificates.outputs.cache-hit != 'true' + uses: actions/cache/save@v3 + with: + path: | + ${{ env.folder_path }}/*.pem + key: ${{ steps.openssl-cache-mysql-certificates.outputs.cache-primary-key }} + env: + folder_path: ${{ steps.openssl-initialize-mysql-certificates.outputs.FolderPath }} + + - name: MySQL SSL certificates install + working-directory: ${{ steps.openssl-initialize-mysql-certificates.outputs.FolderPath }} run: | - # It's enough to remove only these three certificate-related files - Remove-Item ./ca.pem, ./server-cert.pem, ./server-key.pem - mysql_ssl_rsa_setup.exe --suffix=TinyORM + Write-Output '::group::Install CA certificate' + Move-Item -Path ./ca.pem -Destination '${{ env.TinyMySQLDataPath }}' + Write-Output '::endgroup::' + + Write-Output '::group::Install server certificates' + Move-Item -Path ./server-cert.pem, ./server-key.pem ` + -Destination '${{ env.TinyMySQLDataPath }}' + Write-Output '::endgroup::' + + Write-Output '::group::Install client certificates' + Move-Item -Path ./client-cert.pem, ./client-key.pem ` + -Destination '${{ env.TinyMySQLDataPath }}' + Write-Output '::endgroup::' - name: MySQL service install/start run: | mysqld.exe --install MySQL Start-Service MySQL + # Securing the root account even on localhost is for testing to make sure that everything + # works as expected - name: MySQL change ${{ secrets.DB_MYSQL_ROOT_USERNAME }} password run: >- "alter user '$env:DB_MYSQL_ROOT_USERNAME'@'localhost' identified with caching_sha2_password by '$env:DB_MYSQL_ROOT_PASSWORD' - require issuer '/CN=MySQL_Server_TinyORM_Auto_Generated_CA_Certificate' and - subject '/CN=MySQL_Server_TinyORM_Auto_Generated_Client_Certificate';" | + require issuer '${{ env.DB_MYSQL_SSL_SUBJECT_CA }}' and + subject '${{ env.DB_MYSQL_SSL_SUBJECT_CLIENT }}';" | mysql.exe --user=$env:DB_MYSQL_ROOT_USERNAME --skip-password env: DB_MYSQL_ROOT_PASSWORD: ${{ secrets.DB_MYSQL_ROOT_PASSWORD }} DB_MYSQL_ROOT_USERNAME: ${{ secrets.DB_MYSQL_ROOT_USERNAME }} + DB_MYSQL_SSL_SUBJECT_CA: ${{ secrets.DB_MYSQL_SSL_SUBJECT_CA }} + DB_MYSQL_SSL_SUBJECT_CLIENT: ${{ secrets.DB_MYSQL_SSL_SUBJECT_CLIENT }} - name: MySQL time zone POSIX tables initialize download id: downloads-initialize-mysql-timezone-tables @@ -403,8 +512,8 @@ jobs: run: >- "create user '$env:DB_MYSQL_USERNAME'@'%' identified with caching_sha2_password by '$env:DB_MYSQL_PASSWORD' - require issuer '/CN=MySQL_Server_TinyORM_Auto_Generated_CA_Certificate' and - subject '/CN=MySQL_Server_TinyORM_Auto_Generated_Client_Certificate'; + require issuer '${{ env.DB_MYSQL_SSL_SUBJECT_CA }}' and + subject '${{ env.DB_MYSQL_SSL_SUBJECT_CLIENT }}'; grant all privileges on ``tinyorm\_%``.* to '$env:DB_MYSQL_USERNAME'@'%'; grant select on ``mysql``.``time_zone_name`` to '$env:DB_MYSQL_USERNAME'@'%'; flush privileges;" | @@ -413,6 +522,8 @@ jobs: DB_MYSQL_PASSWORD: ${{ secrets.DB_MYSQL_PASSWORD }} DB_MYSQL_ROOT_PASSWORD: ${{ secrets.DB_MYSQL_ROOT_PASSWORD }} DB_MYSQL_ROOT_USERNAME: ${{ secrets.DB_MYSQL_ROOT_USERNAME }} + DB_MYSQL_SSL_SUBJECT_CA: ${{ secrets.DB_MYSQL_SSL_SUBJECT_CA }} + DB_MYSQL_SSL_SUBJECT_CLIENT: ${{ secrets.DB_MYSQL_SSL_SUBJECT_CLIENT }} DB_MYSQL_USERNAME: ${{ secrets.DB_MYSQL_USERNAME }} - name: MySQL add libmysql.dll on the $env:Path, INCLUDE, and LIB