<div id="docs-body">
 <div class="section">
  <div class="titlepage">
   <div>
    <div>
     <h4 class="title">
      <a name="mysql-cluster-security-mysql-privileges">
      </a>
      25.6.21.2 NDB Cluster and MySQL Privileges
     </h4>
    </div>
   </div>
  </div>
  <a class="indexterm" name="idm46045087001616">
  </a>
  <p>
   In this section, we discuss how the MySQL privilege system works
        in relation to NDB Cluster and the implications of this for
        keeping an NDB Cluster secure.
  </p>
  <p>
   <a class="indexterm" name="idm46045086999280">
   </a>
   Standard MySQL privileges apply to NDB Cluster tables. This
        includes all MySQL privilege types
        (
   <a class="link" href="privileges-provided.html#priv_select">
    <code class="literal">
     SELECT
    </code>
   </a>
   privilege,
   <a class="link" href="privileges-provided.html#priv_update">
    <code class="literal">
     UPDATE
    </code>
   </a>
   privilege,
   <a class="link" href="privileges-provided.html#priv_delete">
    <code class="literal">
     DELETE
    </code>
   </a>
   privilege, and so on)
        granted on the database, table, and column level. As with any
        other MySQL Server, user and privilege information is stored in
        the
   <code class="literal">
    mysql
   </code>
   system database. The SQL statements
        used to grant and revoke privileges on
   <a class="link" href="mysql-cluster.html" title="Chapter 25 MySQL NDB Cluster 8.4">
    <code class="literal">
     NDB
    </code>
   </a>
   tables, databases containing
        such tables, and columns within such tables are identical in all
        respects with the
   <a class="link" href="grant.html" title="15.7.1.6 GRANT Statement">
    <code class="literal">
     GRANT
    </code>
   </a>
   and
   <a class="link" href="revoke.html" title="15.7.1.8 REVOKE Statement">
    <code class="literal">
     REVOKE
    </code>
   </a>
   statements used in
        connection with database objects involving any (other) MySQL
        storage engine. The same thing is true with respect to the
   <a class="link" href="create-user.html" title="15.7.1.3 CREATE USER Statement">
    <code class="literal">
     CREATE USER
    </code>
   </a>
   and
   <a class="link" href="drop-user.html" title="15.7.1.5 DROP USER Statement">
    <code class="literal">
     DROP USER
    </code>
   </a>
   statements.
  </p>
  <p>
   <a class="indexterm" name="idm46045086986224">
   </a>
   It is important to keep in mind that, by default, the MySQL
        grant tables use the
   <a class="link" href="innodb-storage-engine.html" title="Chapter 17 The InnoDB Storage Engine">
    <code class="literal">
     InnoDB
    </code>
   </a>
   storage
        engine. Because of this, those tables are not normally
        duplicated or shared among MySQL servers acting as SQL nodes in
        an NDB Cluster. In other words, changes in users and their
        privileges do not automatically propagate between SQL nodes by
        default. If you wish, you can enable synchronization of MySQL
        users and privileges across NDB Cluster SQL nodes; see
   <a class="xref" href="mysql-cluster-privilege-synchronization.html" title="25.6.13 Privilege Synchronization and NDB_STORED_USER">
    Section 25.6.13, “Privilege Synchronization and NDB_STORED_USER”
   </a>
   , for
        details.
  </p>
  <p>
   <a class="indexterm" name="idm46045086981888">
   </a>
   <a class="indexterm" name="idm46045086980400">
   </a>
   Conversely, because there is no way in MySQL to deny privileges
        (privileges can either be revoked or not granted in the first
        place, but not denied as such), there is no special protection
        for
   <code class="literal">
    NDB
   </code>
   tables on one SQL node from users
        that have privileges on another SQL node; this is true even if
        you are not using automatic distribution of user privileges. The
        definitive example of this is the MySQL
   <code class="literal">
    root
   </code>
   account, which can perform any action on any database object. In
        combination with empty
   <code class="literal">
    [mysqld]
   </code>
   or
   <code class="literal">
    [api]
   </code>
   sections of the
   <code class="filename">
    config.ini
   </code>
   file, this account can be
        especially dangerous. To understand why, consider the following
        scenario:
  </p>
  <div class="itemizedlist">
   <ul class="itemizedlist" style="list-style-type: disc; ">
    <li class="listitem">
     <p>
      The
      <code class="filename">
       config.ini
      </code>
      file contains at least
            one empty
      <code class="literal">
       [mysqld]
      </code>
      or
      <code class="literal">
       [api]
      </code>
      section. This means that the NDB
            Cluster management server performs no checking of the host
            from which a MySQL Server (or other API node) accesses the
            NDB Cluster.
     </p>
    </li>
    <li class="listitem">
     <p>
      There is no firewall, or the firewall fails to protect
            against access to the NDB Cluster from hosts external to the
            network.
     </p>
    </li>
    <li class="listitem">
     <p>
      The host name or IP address of the NDB Cluster management
            server is known or can be determined from outside the
            network.
     </p>
    </li>
   </ul>
  </div>
  <p>
   If these conditions are true, then anyone, anywhere can start a
        MySQL Server with
   <a class="link" href="mysql-cluster-options-variables.html#option_mysqld_ndbcluster">
    <code class="option">
     --ndbcluster
    </code>
   </a>
   <a class="link" href="mysql-cluster-options-variables.html#option_mysqld_ndb-connectstring">
    <code class="option">
     --ndb-connectstring=
     <em class="replaceable">
      <code>
       management_host
      </code>
     </em>
    </code>
   </a>
   and access this NDB Cluster. Using the MySQL
   <code class="literal">
    root
   </code>
   account, this person can then perform
        the following actions:
  </p>
  <div class="itemizedlist">
   <ul class="itemizedlist" style="list-style-type: disc; ">
    <li class="listitem">
     <p>
      Execute metadata statements such as
      <a class="link" href="show-databases.html" title="15.7.7.15 SHOW DATABASES Statement">
       <code class="literal">
        SHOW DATABASES
       </code>
      </a>
      statement (to
            obtain a list of all
      <a class="link" href="mysql-cluster.html" title="Chapter 25 MySQL NDB Cluster 8.4">
       <code class="literal">
        NDB
       </code>
      </a>
      databases on the server) or
      <a class="link" href="show-tables.html" title="15.7.7.39 SHOW TABLES Statement">
       <code class="literal">
        SHOW TABLES
            FROM
        <em class="replaceable">
         <code>
          some_ndb_database
         </code>
        </em>
       </code>
      </a>
      statement to obtain a list of all
      <a class="link" href="mysql-cluster.html" title="Chapter 25 MySQL NDB Cluster 8.4">
       <code class="literal">
        NDB
       </code>
      </a>
      tables in a given database
     </p>
    </li>
    <li class="listitem">
     <p>
      <a class="indexterm" name="idm46045086958576">
      </a>
      <a class="indexterm" name="idm46045086957072">
      </a>
      Run any legal MySQL statements on any of the discovered
            tables, such as:
     </p>
     <div class="itemizedlist">
      <ul class="itemizedlist" style="list-style-type: circle; ">
       <li class="listitem">
        <p>
         <code class="literal">
          SELECT * FROM
          <em class="replaceable">
           <code>
            some_table
           </code>
          </em>
         </code>
         or
         <code class="literal">
          TABLE
          <em class="replaceable">
           <code>
            some_table
           </code>
          </em>
         </code>
         to read
                all the data from any table
        </p>
       </li>
       <li class="listitem">
        <p>
         <code class="literal">
          DELETE FROM
          <em class="replaceable">
           <code>
            some_table
           </code>
          </em>
         </code>
         or
                TRUNCATE TABLE to delete all the data from a table
        </p>
       </li>
       <li class="listitem">
        <p>
         <code class="literal">
          DESCRIBE
          <em class="replaceable">
           <code>
            some_table
           </code>
          </em>
         </code>
         or
         <code class="literal">
          SHOW CREATE TABLE
          <em class="replaceable">
           <code>
            some_table
           </code>
          </em>
         </code>
         to
                determine the table schema
        </p>
       </li>
       <li class="listitem">
        <p>
         <code class="literal">
          UPDATE
          <em class="replaceable">
           <code>
            some_table
           </code>
          </em>
          SET
          <em class="replaceable">
           <code>
            column1
           </code>
          </em>
          =
          <em class="replaceable">
           <code>
            some_value
           </code>
          </em>
         </code>
         to fill
                a table column with
         <span class="quote">
          “
          <span class="quote">
           garbage
          </span>
          ”
         </span>
         data; this
                could actually cause much greater damage than simply
                deleting all the data
        </p>
        <p>
         More insidious variations might include statements like
                these:
        </p>
        <div class="copytoclipboard-wrapper">
         <pre class="programlisting one-line language-sql"><div class="docs-select-all right" id="sa86597072"><div class="copy-help left">Press ⌘+C to copy</div> <div class="right"><button class="clipboard-btn" title="Copy to Clipboard"><span class="icon-clipboard"></span></button></div></div><code class="language-sql"><span class="token keyword">UPDATE</span> <em class="replaceable">some_table</em> <span class="token keyword">SET</span> <em class="replaceable">an_int_column</em> <span class="token operator">=</span> <em class="replaceable">an_int_column</em> <span class="token operator">+</span> <span class="token number">1</span></code></pre>
        </div>
        <p>
         or
        </p>
        <div class="copytoclipboard-wrapper">
         <pre class="programlisting one-line language-sql"><div class="docs-select-all right" id="sa49035529"><div class="copy-help left">Press ⌘+C to copy</div> <div class="right"><button class="clipboard-btn" title="Copy to Clipboard"><span class="icon-clipboard"></span></button></div></div><code class="language-sql"><span class="token keyword">UPDATE</span> <em class="replaceable">some_table</em> <span class="token keyword">SET</span> <em class="replaceable">a_varchar_column</em> <span class="token operator">=</span> <span class="token function">REVERSE</span><span class="token punctuation">(</span><em class="replaceable">a_varchar_column</em><span class="token punctuation">)</span></code></pre>
        </div>
        <p>
         Such malicious statements are limited only by the
                imagination of the attacker.
        </p>
       </li>
      </ul>
     </div>
     <p>
      The only tables that would be safe from this sort of mayhem
            would be those tables that were created using storage
            engines other than
      <code class="literal">
       NDB
      </code>
      , and so not
            visible to a
      <span class="quote">
       “
       <span class="quote">
        rogue
       </span>
       ”
      </span>
      SQL node.
     </p>
     <p>
      <a class="indexterm" name="idm46045086936160">
      </a>
      <a class="indexterm" name="idm46045086934672">
      </a>
      A user who can log in as
      <code class="literal">
       root
      </code>
      can also
            access the
      <a class="link" href="information-schema.html" title="Chapter 28 INFORMATION_SCHEMA Tables">
       <code class="literal">
        INFORMATION_SCHEMA
       </code>
      </a>
      database and its tables, and so obtain information about
            databases, tables, stored routines, scheduled events, and
            any other database objects for which metadata is stored in
      <code class="literal">
       INFORMATION_SCHEMA
      </code>
      .
     </p>
     <p>
      It is also a very good idea to use different passwords for
            the
      <code class="literal">
       root
      </code>
      accounts on different NDB
            Cluster SQL nodes unless you are using shared privileges.
     </p>
    </li>
   </ul>
  </div>
  <p>
   In sum, you cannot have a safe NDB Cluster if it is directly
        accessible from outside your local network.
  </p>
  <div class="important" style="margin-left: 0.5in; margin-right: 0.5in;">
   <div class="admon-title">
    Important
   </div>
   <p>
    <span class="emphasis">
     <em>
      Never leave the MySQL root account password
          empty
     </em>
    </span>
    . This is just as true when running MySQL as
          an NDB Cluster SQL node as it is when running it as a
          standalone (non-Cluster) MySQL Server, and should be done as
          part of the MySQL installation process before configuring the
          MySQL Server as an SQL node in an NDB Cluster.
   </p>
  </div>
  <p>
   If you need to synchronize
   <code class="literal">
    mysql
   </code>
   system
        tables between SQL nodes, you can use standard MySQL replication
        to do so, or employ a script to copy table entries between the
        MySQL servers. Users and their privileges can be shared and kept
        in synch using the
   <a class="link" href="privileges-provided.html#priv_ndb-stored-user">
    <code class="literal">
     NDB_STORED_USER
    </code>
   </a>
   privilege.
  </p>
  <p>
   <b>
    Summary.
   </b>
   The most important points to remember regarding the MySQL
          privilege system with regard to NDB Cluster are listed here:
  </p>
  <div class="orderedlist">
   <ol class="orderedlist" type="1">
    <li class="listitem">
     <p>
      Users and privileges established on one SQL node do not
            automatically exist or take effect on other SQL nodes in the
            cluster. Conversely, removing a user or privilege on one SQL
            node in the cluster does not remove the user or privilege
            from any other SQL nodes.
     </p>
    </li>
    <li class="listitem">
     <p>
      You can share MySQL users and privileges among SQL nodes
            using
      <a class="link" href="privileges-provided.html#priv_ndb-stored-user">
       <code class="literal">
        NDB_STORED_USER
       </code>
      </a>
      .
     </p>
    </li>
    <li class="listitem">
     <p>
      Once a MySQL user is granted privileges on an
      <a class="link" href="mysql-cluster.html" title="Chapter 25 MySQL NDB Cluster 8.4">
       <code class="literal">
        NDB
       </code>
      </a>
      table from one SQL node in
            an NDB Cluster, that user can
      <span class="quote">
       “
       <span class="quote">
        see
       </span>
       ”
      </span>
      any data in
            that table regardless of the SQL node from which the data
            originated, even if that user is not shared.
     </p>
    </li>
   </ol>
  </div>
 </div>
 <br/>
</div>
