Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

nixos/mysql: don't run parts of mysqld.service as root #61589

Merged
merged 4 commits into from May 31, 2019

Conversation

flokli
Copy link
Contributor

@flokli flokli commented May 16, 2019

Also don't use RuntimeDirectory=mysqld, which translates to
/run/mysqld, which is cfg.pidDir, but only if cfg.pidDir isn't set
to something else.

Use systemd.tmpfiles.rules to create dataDir and pidDir, instead
of relying on the deprecated PermissionsStartOnly=yes [0][1] to setup
filesystem structure.

Also group some of the different steps together for better readability.

Motivation for this change

[0] systemd/systemd#10802
[1] #53852

Things done
  • Tested using sandboxing (nix.useSandbox on NixOS, or option sandbox in nix.conf on non-NixOS)
  • Built on platform(s)
    • NixOS
    • macOS
    • other Linux distributions
  • Tested via one or more NixOS test(s) if existing and applicable for the change (look inside nixos/tests)
  • Tested compilation of all pkgs that depend on this change using nix-shell -p nix-review --run "nix-review wip"
  • Tested execution of all binary files (usually in ./result/bin/)
  • Determined the impact on package closure size (by running nix path-info -S before and after)
  • Assured whether relevant documentation is up to date
  • Fits CONTRIBUTING.md.

@flokli flokli requested review from aanderse and infinisil May 16, 2019 12:13
cmdWatchForMysqlSocket = ''
# Wait until the MySQL server is available for use
count=0
while [ ! -e /run/mysqld/mysqld.sock ]
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As stated above, I'm not sure whether this is always /run/mysqld - it doesn't look like this depends on pidDir.

@flokli flokli requested a review from andir May 16, 2019 12:15
@flokli
Copy link
Contributor Author

flokli commented May 16, 2019

Ran the mysql tests successfully, mysqlReplication is broken since December 2018 and reported here: #61523

@flokli
Copy link
Contributor Author

flokli commented May 16, 2019

Splitted the changes into multiple commits as suggested by @aanderse over IRC.

Copy link
Member

@aanderse aanderse left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Aside from running as this as a different user the changes are minimal and for the most part compatible.
LGTM 👍

@flokli flokli force-pushed the mysql-permissions-start-only branch 2 times, most recently from 8a81cf5 to a51ee8b Compare May 17, 2019 12:58
@flokli flokli force-pushed the mysql-permissions-start-only branch from a51ee8b to 8181d2a Compare May 17, 2019 13:10
@flokli
Copy link
Contributor Author

flokli commented May 17, 2019

I did some deeper digging into the remaining pidDir TODO, and noticed this was only used in the wordpress module (to wait for mysql to boot up).

As we can simply wait for the mysql socket file to appear too, I dropped pidDir, further simplifying the mysql module.

Also added release notes for both changes.

@flokli flokli force-pushed the mysql-permissions-start-only branch from 8181d2a to 6039dab Compare May 18, 2019 09:30
@Izorkin
Copy link
Contributor

Izorkin commented May 18, 2019

Checked on mariadb-galera server- worked. Thanks.

We need to keep using `RuntimeDirectory=mysqld`, which translates to
`/run/mysqld`, as this is used for the location of the file socket, that
could differ with what is configured via `cfg.pidDir`.
@flokli flokli force-pushed the mysql-permissions-start-only branch from 6039dab to 44552dd Compare May 31, 2019 20:26
define commands like "waiting for the mysql socket to appear" or "setup
initial databases" in a let expression, so the main control flow becomes
more readable.
As we don't need to setup data directories from ExecStartPre= scripts
anymore, which required root, but use systemd.tmpfiles.rules instead,
everything can be run as just the mysql user.
mysql already has its socket path hardcoded to to
/run/mysqld/mysqld.sock.
There's not much value in making the pidDir configurable, which also
points to /run/mysqld by default.

We only seem to use `services.mysql.pidDir` in the wordpress startup
script, to wait for mysql to boot up, but we can also simply wait on the
(hardcoded) socket location too.

A much nicer way to accomplish that would be to properly describe a
dependency on mysqld.service. This however is not easily doable, due to
how the apache-httpd module was designed.
@flokli flokli force-pushed the mysql-permissions-start-only branch from 44552dd to 5ea7a3e Compare May 31, 2019 20:28
@flokli
Copy link
Contributor Author

flokli commented May 31, 2019

Rebased on latest master, tests still pass.

@flokli flokli merged commit d2905ff into NixOS:master May 31, 2019
@flokli flokli deleted the mysql-permissions-start-only branch May 31, 2019 20:29
@flokli
Copy link
Contributor Author

flokli commented Jun 23, 2019

@thorstenweber83 we have a nixos test using services.mysql.ensure(Users,Databases), which didn't break after this PR, so I guess this should work :-)

@aanderse
Copy link
Member

Or did i miss something?

@thorstenweber83 Yes. The part you missed is that mysql on NixOS is insanely insecure out of the box and allows anyone to authenticate as the root mysql user. If you were to secure your mysql setup, which I hope you and everyone else has, this change will then likely (depending on how you secured) cause breakage for ensureUsers and ensureDatabases as you suggested.

I have been meaning to address the overall issue of an insecure mysql setup out of the box on NixOS for a while. I'll discuss with @flokli and will report back.

@thorstenweber83
Copy link
Contributor

@aanderse you're right, I use a postStart script to secure access like mysql_secure_installation does and set up socket authentication for root:

systemd.services.mysql.postStart = ''
    ( echo "ALTER USER root@localhost IDENTIFIED WITH unix_socket;"
      echo "ALTER USER root@'127.0.0.1' IDENTIFIED WITH unix_socket;"
      echo "ALTER USER root@'::1' IDENTIFIED WITH unix_socket;"

      echo "DELETE FROM mysql.user WHERE User=''';"
      echo "DELETE FROM mysql.user WHERE User='root' AND Host NOT IN ('localhost', '127.0.0.1', '::1');"
      echo "DROP DATABASE IF EXISTS test;"
      echo "DELETE FROM mysql.db WHERE Db='test' OR Db='test\\_%';"
      echo "FLUSH PRIVILEGES;"
    ) | ${mysql}/bin/mysql -u root -N
  '';

@aanderse
Copy link
Member

aanderse commented Jun 25, 2019

  echo "ALTER USER root@'127.0.0.1' IDENTIFIED WITH unix_socket;"

@thorstenweber83 I wouldn't have thought that to make sense as mysql/mariadb can only do socket authentication on localhost.

@thorstenweber83
Copy link
Contributor

@aanderse yeah you're right, this is a bit nonsensical.

@aanderse
Copy link
Member

Partial revert. I don't have the time/energy to go any further on this at the moment. Important to get this fixed now, though.

See 4243732 for proposal. Note that this is based on #63786 which I'll wait to be merged before going ahead with this.

ping @flokli and @thorstenweber83

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants