Skip to main content

Secure MySQL Access with SSO, TLS, and Auditing

Secure MySQL access with SSO while keeping databases off the public internet, authenticating with short-lived client certificates, and recording every query in the audit log.

Setup takes four steps: create a join token, configure the MySQL server, grant access through AlmaForge RBAC, and connect with native mysql or GUI clients.

info

Running MariaDB? See the MariaDB database access guide. Running TiDB? See the TiDB database access guide.

Prerequisites​

MySQL CLI​

On your computer, check that a MySQL client is installed:

Terminal
mysql --versionmysql  Ver 8.4 ...

On macOS, install a missing client with Homebrew:

Terminal
brew install mysql-client...export PATH="$(brew --prefix mysql-client)/bin:$PATH"# No output on success.mysql --versionmysql  Ver ...

Add the export to your shell's startup file to keep that PATH setting. For Linux, use the MySQL packages. A mariadb client also works. alma prefers mariadb when both clients are on PATH. The examples below show the mysql prompt.

MySQL server​

On the database server, check the installed server:

Terminal
mysqld --versionmysqld  Ver 8.4 ...systemctl is-active mysqldactive

The commands use MySQL 8.4 on an RPM-based Linux system with the mysqld service and /etc/my.cnf. Use your package's paths and service name if they differ. You need sudo and a MySQL administrator account to configure TLS and create the example database user.

AlmaForge CLI​

On your computer, check whether alma is installed:

Terminal
alma version --clientClient Version: v2026.1.0+<build>

If the command is not found, install it and repeat the check:

Terminal
curl -fL https://get.almaforge.com/install.sh | sh...==> AlmaForge installed successfullyalma version --clientClient Version: v2026.1.0+<build>

The installer supports Linux and macOS on both amd64 and arm64. See CLI installation for package-specific options.

AlmaForge Cluster​

On your computer, sign in to your cluster and check your permissions.

Get your cluster's hostname from its administrator. If you do not have an AlmaForge cluster yet, complete the standalone deployment before continuing. Replace almaforge.example.com below with that hostname. Run the login command and complete the sign-in in your browser:

Terminal
alma login --proxy=almaforge.example.com:443
text
...
> Profile URL: https://almaforge.example.com:443
Logged in as: [email protected]
Cluster: almaforge.example.com
Roles: admin
...

After signing in, check your account and roles:

Terminal
alma status
text
> Profile URL:        https://almaforge.example.com:443
Logged in as: [email protected]
Cluster: almaforge.example.com
Roles: admin
...

In the status output, check that:

  • Cluster names the cluster you intend to configure.
  • Logged in as shows your account.
  • Roles includes admin.

If admin is missing, ask a cluster administrator to grant that role, then run alma logout and repeat the login and status commands. Continue once Roles includes admin.

Step 1. Create AlmaForge join token​

On your computer, create an AlmaForge join token. The database agent uses it to join your AlmaForge cluster:

Terminal
alma create token --services=databaseToken created.  client_id:     <client-id>  client_secret: <client-secret>

You will copy client_id and client_secret into the agent configuration in Step 2. They are valid for 30 minutes. If they expire before the agent joins, create a new token and use its values.

Step 2. Configure the MySQL server​

Install and configure the agent​

The agent is almad with its Database Service enabled. It connects outward to your cluster on port 443 and carries connections between users and MySQL.

On the MySQL server, check whether almad is installed:

Terminal
almad versionAlmaForge v2026.1.0+<build>

If the command is not found, install the AlmaForge package:

Terminal
curl -fL https://get.almaforge.com/install.sh | sh...==> AlmaForge installed successfullyalmad versionAlmaForge v2026.1.0+<build>

On an RPM-based system, the installer uses the RPM package and installs the almad systemd service. It supports both amd64 and arm64. The version command must succeed before you configure the agent. For other Linux distributions, see Linux package installation.

Already running an agent on this host?

Keep its existing settings and enable ALMA_DATABASE_SERVICE=true. Preserve the other services and label selectors. The join credentials must permit the database service. The local target created below does not need a label selector.

On the MySQL server, open the agent configuration:

Terminal
sudoedit /etc/almaforge/almad.env# Your text editor opens.

For a new agent, enter the settings below. Replace ALMA_PROXY with your cluster's hostname and port 443. Set ALMA_CLIENT_ID and ALMA_CLIENT_SECRET to the values from Step 1:

almad.env:

/etc/almaforge/almad.env
# Database Service agent on the MySQL host.
# Install at /etc/almaforge/almad.env as root:root with mode 0600.
ALMA_PROXY=almaforge.example.com:443

# Printed by `alma create token --services=database`.
ALMA_CLIENT_ID=paste-client-id-here
ALMA_CLIENT_SECRET=paste-client-secret-here

ALMA_DATABASE_SERVICE=true
ALMA_SSH_SERVICE=false

# Agent labels, separate from the database's labels.
ALMA_LABELS=env=demo

Save the file and close the editor. Restrict it to root because it contains the join credentials:

Terminal
sudo chown root:root /etc/almaforge/almad.env# No output on success.sudo chmod 0600 /etc/almaforge/almad.env# No output on success.

Create the TLS certificates​

On the MySQL server, download the public database CA from your cluster and create a server certificate for the local agent connection:

Terminal
curl -fsS -o almaforge-db-ca.pem 'https://almaforge.example.com:443/api/v1/auth/export?type=db'# No output on success.openssl x509 -in almaforge-db-ca.pem -noout# No output means the file contains a valid certificate.sudo install -d -o mysql -g mysql -m 0700 /etc/mysql# No output on success.sudo install -o mysql -g mysql -m 0644 almaforge-db-ca.pem /etc/mysql/server.cas# No output on success.sudo openssl req -x509 -newkey rsa:2048 -nodes -days 3650 \    -subj '/CN=localhost' \    -addext 'subjectAltName=DNS:localhost,IP:127.0.0.1' \    -keyout /etc/mysql/server.key -out /etc/mysql/server.crt...-----sudo chown mysql:mysql /etc/mysql/server.key /etc/mysql/server.crt# No output on success.sudo chmod 0600 /etc/mysql/server.key# No output on success.

If MySQL already has a server certificate, keep it and use its issuing CA in the target configuration below. MySQL's ssl-ca must trust the AlmaForge database CA that signs the agent's client certificates.

Enable TLS in MySQL​

Open the server option file:

Terminal
sudoedit /etc/my.cnf# Your text editor opens.

Under [mysqld], set the values below. Preserve other server settings. bind-address limits TCP access to the local host.

mysql.cnf:

/etc/my.cnf
# MySQL TLS listener for an AlmaForge agent on this host.
# Merge into the server's [mysqld] options and preserve other settings.
[mysqld]
bind-address=127.0.0.1
require_secure_transport=ON
ssl-cert=/etc/mysql/server.crt
ssl-key=/etc/mysql/server.key
ssl-ca=/etc/mysql/server.cas

Restart the server and confirm that it is running:

Terminal
sudo systemctl restart mysqld# No output on success.systemctl is-active mysqldactive

Create the database account​

On the MySQL server, open an administrator session over the local socket:

Terminal
sudo mysqlWelcome to the MySQL monitor.  Commands end with ; or \g....mysql>

Use your administrator's login method if it differs. Run the following SQL. It creates a sample database and a read-only account named alma-demo. The account requires a trusted certificate with the exact subject /CN=alma-demo, which the agent presents when connecting as that user.

create-user.sql:

create-user.sql
-- Create sample data and a read-only certificate-authenticated account.
-- Run through a local MySQL administrator session.
CREATE DATABASE alma_demo;
CREATE TABLE alma_demo.messages (id INT PRIMARY KEY, message VARCHAR(100));
INSERT INTO alma_demo.messages VALUES (1, 'Connected through TLS');
CREATE USER 'alma-demo'@'127.0.0.1' REQUIRE SUBJECT '/CN=alma-demo';
GRANT SELECT ON alma_demo.* TO 'alma-demo'@'127.0.0.1';

Each statement must succeed. Type exit to leave the administrator session. This account has no database password. Its certificate requirement is mandatory: a passwordless account without REQUIRE SUBJECT would not have the same authentication protection.

Register MySQL with the agent​

Display the public server certificate:

Terminal
sudo cat /etc/mysql/server.crt-----BEGIN CERTIFICATE-----...-----END CERTIFICATE-----

Create the target file and open it:

Terminal
sudo install -d -o root -g root -m 0700 /etc/almaforge/almad.d# No output on success.sudoedit /etc/almaforge/almad.d/mysql.yaml# Your text editor opens.

Copy the example below. Replace the certificate placeholder with the complete server certificate, indenting every line by six spaces beneath caCert: |:

target.yaml.in:

/etc/almaforge/almad.d/mysql.yaml
# MySQL target for an agent running on the database server.
# Replace caCert with the complete server certificate or its issuing CA.
apiVersion: almaforge.com/v1
kind: DatabaseTarget
metadata:
name: mysql
labels:
db: mysql
env: demo
spec:
protocol: mysql
uri: 127.0.0.1:3306
tls:
caCert: |
<paste the complete server certificate here>

Save the file, restrict it to root, and start the agent:

Terminal
sudo chown root:root /etc/almaforge/almad.d/mysql.yaml# No output on success.sudo chmod 0600 /etc/almaforge/almad.d/mysql.yaml# No output on success.sudo systemctl enable --now almad...sudo systemctl restart almad# No output on success.systemctl is-active almadactive

Step 3. Grant access​

On your computer, confirm that the database is registered:

Terminal
alma get dbHost             Name            Protocol       URI                 Labels             Version---------------- --------------- -------------- ------------------- ------------------ --------<database-host>  mysql           mysql          <database-uri>      db=mysql ... 2026.1.0

The mysql row must have the database server in its Host column. Download the role below. It permits the alma-demo account on targets labeled db: mysql:

mysql-access.yaml:

mysql-access.yaml
# Read the sample database through the existing alma-demo MySQL account.
apiVersion: almaforge.com/v1
kind: Role
metadata:
name: mysql-access
spec:
allow:
databaseLabels:
db: mysql
databaseUsers:
- alma-demo

Apply it:

Terminal
alma apply -f mysql-access.yamlrole 'mysql-access' has been created

Creating the role does not assign it to anyone. To grant it to an SSO group, list your connectors:

Terminal
alma get oidcKind          Name------------- -----------OIDCConnector company-sso

Find the connector your team uses to sign in. Replace <connector-name> with its name from the output, then open it in your text editor:

Terminal
alma edit oidc/<connector-name># Your text editor opens. After saving your changes:oidc connector "<connector-name>" has been updated

Under spec.claimsToRoles, find the entry for the group that should have MySQL access. Add mysql-access to that entry's roles list. Preserve the existing roles and mappings, including those that grant admin, then save and close the editor. The command applies your changes. If the group has no mapping yet, follow OIDC role mapping to add one.

Step 4. Connect​

On your computer, sign out of saved sessions, then sign back in with an account in the group granted access in Step 3 to get a session with the new role. logout clears saved sessions for all clusters. Use your cluster's hostname in the login command:

Terminal
alma logoutLogged out all users from all proxies.alma login --proxy=almaforge.example.com:443...> Profile URL:        https://almaforge.example.com:443  Logged in as:       [email protected]  Cluster:            almaforge.example.com  Roles:              mysql-access  ...alma status> Profile URL:        https://almaforge.example.com:443  Logged in as:       [email protected]  Cluster:            almaforge.example.com  Roles:              mysql-access  ...

Check that Roles includes mysql-access. If it is missing, check your SSO group membership and the mapping from Step 3 before continuing.

Connect as the account created in Step 2 and run the queries at the prompt:

Terminal
alma db connect --db-user=alma-demo --db-name=alma_demo mysql...mysql> SELECT CURRENT_USER(), DATABASE();+-------------------------+------------+| CURRENT_USER()          | DATABASE() |+-------------------------+------------+| [email protected]      | alma_demo  |+-------------------------+------------+mysql> SELECT message FROM messages WHERE id = 1;+-----------------------+| message               |+-----------------------+| Connected through TLS |+-----------------------+

The first result identifies the MySQL account and database. The second confirms its read access to the sample table. Type exit to disconnect.

Advanced configuration​

GUI clients and scripts​

Leave this command running on the computer where your client runs:

Terminal
alma proxy db --tunnel --db-user=alma-demo --db-name=alma_demo mysqlStarted authenticated tunnel for the MySQL database "mysql" in cluster "almaforge.example.com" on 127.0.0.1:54321....

Use the printed address and port, alma-demo as the user, and alma_demo as the database. Use plain TCP to this local listener. The tunnel authenticates to AlmaForge, and the agent authenticates to MySQL with the user's certificate.

Architecture​

The database agent runs beside MySQL and opens an outbound tunnel to the AlmaForge Proxy. MySQL listens on localhost and trusts the agent's client certificates.

MySQL database access topology

Troubleshooting​

Database is missing or has no host​

Check /etc/almaforge/almad.d/mysql.yaml and ALMA_DATABASE_SERVICE=true in /etc/almaforge/almad.env on the database server. Inspect the agent log:

Terminal
sudo journalctl -u almad -n 50 --no-pager...<date> <time> <database-host> almad[<pid>]: <log-message>...

Restart almad after correcting the files, then repeat alma get db.

MySQL denies the account​

Check the account's host match, certificate subject requirement, and password settings through a MySQL administrator session. The example expects alma-demo from 127.0.0.1 and subject /CN=alma-demo, with no database password. An existing password-protected account will not work with this certificate-only setup.

For an AlmaForge access denial, check that alma status shows mysql-access. The role's labels and databaseUsers must match the target and requested account.

Queries are denied​

MySQL grants control database, table, and command permissions. Check SHOW GRANTS FOR 'alma-demo'@'127.0.0.1' as an administrator. The example grants only SELECT on alma_demo.*.

Certificate validation fails​

MySQL's ssl-ca must trust the AlmaForge database CA. The target's spec.tls.caCert must trust the MySQL server certificate. Its SAN must match the target address, 127.0.0.1 in this example. After replacing a self-signed server certificate, update the target's caCert and restart MySQL and almad.

Limitations​

  • For self-hosted MySQL, the agent connects with a client certificate and an empty database password. Configure the database account for certificate authentication.
  • AlmaForge does not enforce databaseNames restrictions for MySQL. Use MySQL grants to restrict schemas and tables.
  • This guide creates the database account explicitly. Automatic user provisioning requires an administrator account on the target and the corresponding role settings.

References​