Preskoči na sadržaj

Konfiguracija sustava za upravljanje bazom podataka MariaDB

MariaDB (Wikipedia) je sustav za upravljanje relacijskom bazom podataka, razvijan od strane zajednice i komercijalno podržan. Razvoj MariaDB-a započet je odvajanjem od MySQL-a izvedenim od strane nekolicine izvornih programera MySQL-a zbog zabrinutosti oko njegove budućnosti povodom akvizicije Suna od strane Oraclea. Prvenstveni cilj stvaranja projekta neovisnog o Oracleu je želja da softvera ostane slobodan i otvorenog koda pod licencom GNU General Public License.

MariaDB zadržava visok nivo kompatibilnosti s MySQL-om, ali proširuje njegovu funkcionalnost tako da nudi i značajke koje MySQL nema. Kao i MySQL, MariaDB je ponuđena i u obliku usluge u oblaku (drugim riječima, sustava koji netko drugi održava) pod imenom SkySQL.

Ime MariaDB dao je autor MySQL-a Michael "Monty" Widenius prema svojoj mlađoj kćeri koja se zove Maria. Slično tome, ime MySQL dao je prema imenu starije kćeri koja se zove My.

Note

Kako MariaDB zadržava što je moguće veću razinu kompatibilnosti s MySQL-om, uočit ćemo kako se u naredbama ljuske, konfiguracijskim naredbama i nazivima datoteka na mnogo mjesta može koristiti naziv MySQL umjesto MariaDB. Primjerice, klijent sučelja naredbenog retka dostupan je naredbama mariadb i mysql, a poslužitelj naredbama mariadbd (MariaDB daemon) i mysqld (MySQL daemon).

Slika mariadb na Docker Hubu

Sustav za upravljanje bazom podataka MariaDB koristit ćemo u obliku Docker kontejnera. Na Docker Hubu moguće je pronaći sliku mariadb, koja je jedna od službenih slika. Koristit ćemo verziju 10.11, koja je posljednja izdana stabilna verzija. Pokretanje kontejnera maridab izvodimo naredbom docker run:

$ docker run mariadb:10.11
Unable to find image 'mariadb:10.11' locally
10.11: Pulling from library/mariadb
1bc677758ad7: Pull complete
196e1740aea4: Pull complete
3d4df0997938: Pull complete
9fa4e4184824: Pull complete
22001c5fbbed: Pull complete
49ed08e2853d: Pull complete
ca39212f2f3c: Pull complete
439f9b904603: Pull complete
Digest: sha256:1c33370a599c870eab28891191b1fc5f46ddf8dfd90bd5f56b03e8a16e83f2fb
Status: Downloaded newer image for mariadb:10.11
2023-05-10 16:12:11+00:00 [Note] [Entrypoint]: Entrypoint script for MariaDB Server 1:10.11.2+maria~ubu2204 started.
2023-05-10 16:12:11+00:00 [Note] [Entrypoint]: Switching to dedicated user 'mysql'
2023-05-10 16:12:11+00:00 [Note] [Entrypoint]: Entrypoint script for MariaDB Server 1:10.11.2+maria~ubu2204 started.
2023-05-10 16:12:11+00:00 [ERROR] [Entrypoint]: Database is uninitialized and password option is not specified
        You need to specify one of MARIADB_ROOT_PASSWORD, MARIADB_ALLOW_EMPTY_ROOT_PASSWORD and MARIADB_RANDOM_ROOT_PASSWORD

Docker slika ne dozvoljava pokretanje bez navođenja zaporke korijenskog korisnika koja će se korstiti. Navedimo ju putem varijable okoline MARIADB_ROOT_PASSWORD parametrom --env i dodajmo parametar --detach kako bismo zadržali mogućnost daljnjeg rada u terminalu:

$ docker run --detach --env MARIADB_ROOT_PASSWORD=m0j4z4p0rk4 mariadb:10.11
b618846ff70c0012813dc62c02a3e262f29d0ac6e54d4504ff042914e7f6d9e9

Naredbom docker ps možemo se uvjeriti da je kontejner pokrenut:

$ docker ps
CONTAINER ID   IMAGE           COMMAND                  CREATED         STATUS         PORTS      NAMES
b618846ff70c   mariadb:10.11   "docker-entrypoint.s…"   4 seconds ago   Up 3 seconds   3306/tcp   sleepy_poincare

Naredbom docker logs koja kao argument prima identifikator kontejnera možemo se uvjeriti da je pokretanje poslužitelja bilo uspješno:

$ docker logs b618846ff70c0012813dc62c02a3e262f29d0ac6e54d4504ff042914e7f6d9e9
2023-05-10 16:12:56+00:00 [Note] [Entrypoint]: Entrypoint script for MariaDB Server 1:10.11.2+maria~ubu2204 started.
2023-05-10 16:12:56+00:00 [Note] [Entrypoint]: Switching to dedicated user 'mysql'
2023-05-10 16:12:56+00:00 [Note] [Entrypoint]: Entrypoint script for MariaDB Server 1:10.11.2+maria~ubu2204 started.
2023-05-10 16:12:56+00:00 [Note] [Entrypoint]: Initializing database files


PLEASE REMEMBER TO SET A PASSWORD FOR THE MariaDB root USER !
To do so, start the server, then issue the following command:

'/usr/bin/mariadb-secure-installation'

which will also give you the option of removing the test
databases and anonymous user created by default.  This is
strongly recommended for production servers.

See the MariaDB Knowledgebase at https://mariadb.com/kb

Please report any problems at https://mariadb.org/jira

The latest information about MariaDB is available at https://mariadb.org/.

Consider joining MariaDB's strong and vibrant community:
https://mariadb.org/get-involved/

2023-05-10 16:12:58+00:00 [Note] [Entrypoint]: Database files initialized
2023-05-10 16:12:58+00:00 [Note] [Entrypoint]: Starting temporary server
2023-05-10 16:12:58+00:00 [Note] [Entrypoint]: Waiting for server startup
2023-05-10 16:12:58 0 [Note] Starting MariaDB 10.11.2-MariaDB-1:10.11.2+maria~ubu2204 source revision cafba8761af55ae16cc69c9b53a341340a845b36 as process 111
2023-05-10 16:12:58 0 [Note] InnoDB: Compressed tables use zlib 1.2.11
2023-05-10 16:12:58 0 [Note] InnoDB: Number of transaction pools: 1
2023-05-10 16:12:58 0 [Note] InnoDB: Using crc32 + pclmulqdq instructions
2023-05-10 16:12:58 0 [Note] InnoDB: Using liburing
2023-05-10 16:12:58 0 [Note] InnoDB: Initializing buffer pool, total size = 128.000MiB, chunk size = 2.000MiB
2023-05-10 16:12:58 0 [Note] InnoDB: Completed initialization of buffer pool
2023-05-10 16:12:58 0 [Note] InnoDB: Buffered log writes (block size=512 bytes)
2023-05-10 16:12:58 0 [Note] InnoDB: 128 rollback segments are active.
2023-05-10 16:12:58 0 [Note] InnoDB: Setting file './ibtmp1' size to 12.000MiB. Physically writing the file full; Please wait ...
2023-05-10 16:12:58 0 [Note] InnoDB: File './ibtmp1' size is now 12.000MiB.
2023-05-10 16:12:58 0 [Note] InnoDB: log sequence number 46590; transaction id 14
2023-05-10 16:12:58 0 [Note] Plugin 'FEEDBACK' is disabled.
2023-05-10 16:12:58 0 [Warning] 'user' entry 'root@14890c14c5dc' ignored in --skip-name-resolve mode.
2023-05-10 16:12:58 0 [Warning] 'proxies_priv' entry '@% root@14890c14c5dc' ignored in --skip-name-resolve mode.
2023-05-10 16:12:58 0 [Note] mariadbd: ready for connections.
Version: '10.11.2-MariaDB-1:10.11.2+maria~ubu2204'  socket: '/run/mysqld/mysqld.sock'  port: 0  mariadb.org binary distribution
2023-05-10 16:12:59+00:00 [Note] [Entrypoint]: Temporary server started.
2023-05-10 16:13:00+00:00 [Note] [Entrypoint]: Securing system users (equivalent to running mysql_secure_installation)

2023-05-10 16:13:00+00:00 [Note] [Entrypoint]: Stopping temporary server
2023-05-10 16:13:00 0 [Note] mariadbd (initiated by: unknown): Normal shutdown
2023-05-10 16:13:00 0 [Note] InnoDB: FTS optimize thread exiting.
2023-05-10 16:13:00 0 [Note] InnoDB: Starting shutdown...
2023-05-10 16:13:00 0 [Note] InnoDB: Dumping buffer pool(s) to /var/lib/mysql/ib_buffer_pool
2023-05-10 16:13:00 0 [Note] InnoDB: Buffer pool(s) dump completed at 230510 16:13:00
2023-05-10 16:13:00 0 [Note] InnoDB: Removed temporary tablespace data file: "./ibtmp1"
2023-05-10 16:13:00 0 [Note] InnoDB: Shutdown completed; log sequence number 46590; transaction id 15
2023-05-10 16:13:00 0 [Note] mariadbd: Shutdown complete

2023-05-10 16:13:00+00:00 [Note] [Entrypoint]: Temporary server stopped

2023-05-10 16:13:00+00:00 [Note] [Entrypoint]: MariaDB init process done. Ready for start up.

2023-05-10 16:13:00 0 [Note] Starting MariaDB 10.11.2-MariaDB-1:10.11.2+maria~ubu2204 source revision cafba8761af55ae16cc69c9b53a341340a845b36 as process 1
2023-05-10 16:13:00 0 [Note] InnoDB: Compressed tables use zlib 1.2.11
2023-05-10 16:13:00 0 [Note] InnoDB: Number of transaction pools: 1
2023-05-10 16:13:00 0 [Note] InnoDB: Using crc32 + pclmulqdq instructions
2023-05-10 16:13:00 0 [Note] InnoDB: Using liburing
2023-05-10 16:13:00 0 [Note] InnoDB: Initializing buffer pool, total size = 128.000MiB, chunk size = 2.000MiB
2023-05-10 16:13:00 0 [Note] InnoDB: Completed initialization of buffer pool
2023-05-10 16:13:00 0 [Note] InnoDB: Buffered log writes (block size=512 bytes)
2023-05-10 16:13:00 0 [Note] InnoDB: 128 rollback segments are active.
2023-05-10 16:13:00 0 [Note] InnoDB: Setting file './ibtmp1' size to 12.000MiB. Physically writing the file full; Please wait ...
2023-05-10 16:13:00 0 [Note] InnoDB: File './ibtmp1' size is now 12.000MiB.
2023-05-10 16:13:00 0 [Note] InnoDB: log sequence number 46590; transaction id 14
2023-05-10 16:13:00 0 [Note] InnoDB: Loading buffer pool(s) from /var/lib/mysql/ib_buffer_pool
2023-05-10 16:13:00 0 [Note] Plugin 'FEEDBACK' is disabled.
2023-05-10 16:13:00 0 [Warning] You need to use --log-bin to make --expire-logs-days or --binlog-expire-logs-seconds work.
2023-05-10 16:13:00 0 [Note] InnoDB: Buffer pool(s) load completed at 230510 16:13:00
2023-05-10 16:13:00 0 [Note] Server socket created on IP: '0.0.0.0'.
2023-05-10 16:13:00 0 [Note] Server socket created on IP: '::'.
2023-05-10 16:13:00 0 [Note] mariadbd: ready for connections.
Version: '10.11.2-MariaDB-1:10.11.2+maria~ubu2204'  socket: '/run/mysqld/mysqld.sock'  port: 3306  mariadb.org binary distribution

Poslužitelj zaustavljamo naredbom docker kill:

$ docker kill b618846ff70c0012813dc62c02a3e262f29d0ac6e54d4504ff042914e7f6d9e9
b618846ff70c0012813dc62c02a3e262f29d0ac6e54d4504ff042914e7f6d9e9

Naredba docker ps ukazuje da poslužitelj više nije pokrenut:

$ docker ps
CONTAINER ID   IMAGE     COMMAND   CREATED   STATUS    PORTS     NAMES

Uvjerili smo se da možemo pokrenuti i zaustaviti poslužitelj, ali klijent se neće moći povezati na ovako pokrenut poslužitelj. Naime, kako bi se mogla ostvariti veza klijenta i poslužitelja, oni moraju biti u istoj mreži i poslužitelj mora biti imenovan. Stvorimo mrežu naredbom docker network:

$ docker network create db-network
ef5139aa1ec739e9c5da903581328a537380095b9117b555d72a1b33678836b7

Pokrenimo poslužitelj na toj mreži i nazovimo ga fidit-mariadb korištenjem parametra --name:

$ docker run --detach --network db-network --name fidit-mariadb --env MARIADB_ROOT_PASSWORD=m0j4z4p0rk4 mariadb:10.11
39b77a3679fd4e5c8638d63d3d577464b46c3ee0b9cc34a965b100355b9bb6aa

Pokrenimo klijent na istoj mreži i iskoristimo parametar -h naredbe mariadb za navođenje imena poslužitelja, parametar -u za navođenje imena korisnika i parametar -p za uključivanje upita za zaporkom. Uočimo pritom kako naredba mariadb ne očekuje razmak između parametra i njegove vrijednosti.

$ docker run -it --network db-network mariadb:10.11 mariadb -hfidit-mariadb -uroot -p
Enter password:
Welcome to the MariaDB monitor.  Commands end with ; or \g.
Your MariaDB connection id is 3
Server version: 10.11.2-MariaDB-1:10.11.2+maria~ubu2204 mariadb.org binary distribution

Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

MariaDB [(none)]>

Nakon unošenja zaporke vidimo da smo se uspješno povezali na poslužitelj.

U ljusci klijenta MariaDB dostupne su nam naredbe jezika SQL i brojne druge specifične za MariaDB. Naredbe jezika SQL su slične među različitim sustavima za upravljanje bazama podataka i njih ćemo koristiti nešto kasnije. Jedna od naredbi specifičnih za MariaDB je SHOW (dokumentacija) koja može prikazati popis autora MariaDB korištenjem parametra AUTHORS (dokumentacija):

SHOW AUTHORS;
+--------------------------------+---------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------+
| Name                           | Location                              | Comment                                                                                                                                 |
+--------------------------------+---------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------+
| Michael (Monty) Widenius       | Tusby, Finland                        | Lead developer and main author                                                                                                          |
| Sergei Golubchik               | Kerpen, Germany                       | Architect, Full-text search, precision math, plugin framework, merges etc                                                               |
| Igor Babaev                    | Bellevue, USA                         | Optimizer, keycache, core work                                                                                                          |
| Sergey Petrunia                | St. Petersburg, Russia                | Optimizer                                                                                                                               |
| Oleksandr Byelkin              | Lugansk, Ukraine                      | Query Cache (4.0), Subqueries (4.1), Views (5.0)                                                                                        |
(...)
+--------------------------------+---------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------+
102 rows in set (0.000 sec)

Primjenom parametra DATABASES (dokumentacija) prikazat će popis baza podataka koje postoje na poslužitelju:

SHOW DATABASES;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| sys                |
+--------------------+
4 rows in set (0.001 sec)

Naposlijetku, moguće je prikazati globalne varijable ili varijable trenutne sesije parametrom VARIABLES (dokumentacija). U slučaju da želimo prikazati globalnu varijablu, dodajemo i parametar GLOBAL, a kod navođenja imena varijable u obliku znakovnog niza koristimo standardni SQL operator LIKE (dokumentacija). MariaDB podržava jednostruke i dvostruke navodnike kod navođenja znakovnih nizova. Varijabla koja nas zanima je have_ssl pa je naredba oblika:

SHOW GLOBAL VARIABLES LIKE 'have_ssl';
+---------------+----------+
| Variable_name | Value    |
+---------------+----------+
| have_ssl      | DISABLED |
+---------------+----------+
1 row in set (0.001 sec)

Uočimo kako MariaDB trenutno ne koristi SSL/TLS za šifriranje komunikacije klijenta i poslužitelja, što ćemo promijeniti u nastavku.

Šifriranje podataka

MariaDB podržava šifriranje:

  • podataka u prijenosu (engl. data in transit), odnosno upita poslanih od klijenta do poslužitelja i njihovih rezultata poslanih od poslužitelja do klijenta te
  • podataka na odmoru (engl. data at rest), odnosno spremljenih sadržaja baza podataka i binarnih logova poslužitelja.

Šifriranje podataka u prijenosu

Stvaranje asimetričnih ključeva

Note

U nastavku stvaramo ključeve korištenjem Easy-RSA, koji je skup skripti za olakšavanje stvaranja RSA ključeva korištenjem OpenSSL-a. Alternativno, moguće je certifikate napraviti i ručnim korištenjem OpenSSL-a, kako je to opisano u koracima 3, 4, 5 i 6 u članku How to set up MariaDB SSL and secure connections from clients na nixCraftu.

Ključeve i X.509 certifikate koje će MariaDB koristiti stvaramo korištenjem OpenSSL-a i Easy-RSA. Inicijalizirajmo infrastrukturu privatnog ključa i kopirajmo direktorij s informacijama o vrstama X.509 certifikata i datoteke s postavkama OpenSSL-a:

$ easyrsa init-pki
$ cp -r /etc/easy-rsa/x509-types pki
$ cp /etc/easy-rsa/openssl-easyrsa.cnf pki
$ cp /etc/easy-rsa/vars pki

Izgradimo prvo ključ i certifikat autoriteta certifikata:

$ easyrsa build-ca

Naravno, ako smo već ranije koristili Easy-RSA pa imamo uspostavljenu infrastrukturu privatnog ključa, neke od naredbi će nam javiti da već postoje napravljeni certifikati i ključevi. U tom slučaju, obzirom da samo učimo kako radi infrastruktura privatnog ključa u MariaDB, možemo iskorstiti certifikate i ključeve koje smo već koristili u drugim sustavima; u praksi to ne smijemo napraviti jer time smanjujemo sigurnost i naše instance MariaDB i tih drugih sustava.

Izgradimo ključ i certifikat za poslužitelj:

$ easyrsa build-server-full moj-mariadb-posluzitelj nopass

Izgradimo ključ i certifikat koji će klijent koristiti:

$ easyrsa build-client-full moj-mariadb-klijent nopass

Pripremit ćemo direktorije s konfiguracijom i certifikatima za poslužiteljski i klijentski kontejner. Kopirajmo stvoreni certifikat autoriteta certifikata, poslužiteljski certifikat i ključ na mjesto s kojeh ćemo ih koristiti te dozvolimo ostalim korisnicima (među kojima je i korisnik mysql koji pokreće MariaDB poslužitelj) čitanje datoteka:

$ mkdir -p mariadb-server-conf/certs
$ cp pki/ca.crt mariadb-server-conf/certs/ca-cert.pem
$ cp pki/issued/moj-mariadb-posluzitelj.crt mariadb-server-conf/certs/server-cert.pem
$ cp pki/private/moj-mariadb-posluzitelj.key mariadb-server-conf/certs/server-key.pem
$ chmod a+r mariadb-server-conf/certs/*.pem

Analogno pripremimo certifikate i ključeve za klijentski kontejner:

$ mkdir -p mariadb-client-conf/certs
$ cp pki/ca.crt mariadb-client-conf/certs/ca-cert.pem
$ cp pki/issued/moj-mariadb-klijent.crt mariadb-client-conf/certs/client-cert.pem
$ cp pki/private/moj-mariadb-klijent.key mariadb-client-conf/certs/client-key.pem
$ chmod a+r mariadb-client-conf/certs/*.pem

Uključivanje ključeva u konfiguracijsku datoteku

Nakon stvaranja privatnog ključa i X.509 certifikata te njihovog kopiranja u direktorije iz kojih će se koristiti uključit ćemo njihovo korištenje konfiguracijskim naredbama:

  • ssl_cert (dokumentacija), kojom ćemo navesti X.509 certifikat u formatu PEM
  • ssl_key (dokumentacija), kojom ćemo navesti privatni ključ u formatu PEM
  • ssl_ca (dokumentacija), kojom ćemo, u slučaju korištenja samopotpisanih certifikata, navesti i certifikat autoriteta certifikata koji ga je potpisao

Više informacija o ovim konfiguracijskim naredbama može se naći u službenoj dokumentaciji.

MariaDB ne preporuča modificiranje postojećih konfiguracijskih datoteka, već dodavanje novih. U direktoriju za konfiguraciju poslužitelja korištenjem uređivača teksta GNU nano ili bilo kojeg drugog stvorimo datoteku ssl.cnf:

$ nano mariadb-server-conf/ssl.cnf

Jako je važno da nastavak bude .cnf, a ne .conf ili neka treća jer konfiguracijska naredba !includedir koju MariaDB koristi učitava u danom direktoriju samo datoteke s nastavkom .cnf. U njoj postavimo putanje poslužiteljskih ključeva i certifikata:

[mariadb]

ssl_cert = /etc/mysql/conf.d/certs/server-cert.pem
ssl_key = /etc/mysql/conf.d/certs/server-key.pem
ssl_ca = /etc/mysql/conf.d/certs/ca-cert.pem

Analogno stvorimo konfiguracijsku datoteku klijenta i u njoj postavimo putanje za klijentske ključeve i certifikate:

$ nano mariadb-client-conf/ssl.cnf
[client-mariadb]

ssl_cert = /etc/mysql/conf.d/certs/client-cert.pem
ssl_key = /etc/mysql/conf.d/certs/client-key.pem
ssl_ca = /etc/mysql/conf.d/certs/ca-cert.pem

Note

Umjesto u odjeljak [mariadb], konfiguracijske smo naredbe mogli staviti u [server] ili [mysqld] koje poslužitelj čita kod pokretanja (detaljnije objašnjenje pojedinih odjeljaka moguće je naći u dijelu službene dokumentacije Configuring MariaDB with Option Files), dok smo umjesto u odjeljak [client-mariadb] konfiguracijske naredbe mogli staviti u odjeljak [client] (detalji).

Pokrenimo ponovno poslužitelj tako da dodatno parametrom -v montiramo direktorij /home/korisnik/mariadb-server-conf na /etc/mysql/conf.d, iz kojeg će MariaDB poslužitelj čitati konfiguraciju:

$ docker run --detach --network db-network --name fidit-mariadb -v /home/korisnik/mariadb-server-conf:/etc/mysql/conf.d --env MARIADB_ROOT_PASSWORD=m0j4z4p0rk4 mariadb:10.11
fd5bc31673cb7f87d632ef9d59bf515bafa944ba4c1058f5776f3d0dc74a402d

Kako bismo se uvjerili da je TLS uključen, povežimo se klijentom tako da i na njegovoj strani montiramo direktorij s konfiguracijskim datotekama:

$ docker run -it --network db-network -v /home/korisnik/mariadb-client-conf:/etc/mysql/conf.d mariadb:10.11 mariadb -hfidit-mariadb -uroot -p
Enter password:

Zatim iskoristimo naredbu SHOW za prikaz vrijednosti globalne varijable have_ssl:

SHOW GLOBAL VARIABLES LIKE 'have_ssl';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| have_ssl      | YES   |
+---------------+-------+
1 row in set (0.001 sec)

Dodatne postavke TLS-a

Slično kao kod drugih softvera koji koriste TLS, možemo navesti dodatne postavke šifriranja. Neke od korisnih naredbi su:

  • require_secure_transport (dokumentacija), postavljanjem koje na ON možemo tražiti da se svako povezivanje klijenta sa poslužiteljem događa uz korištenje TLS-a (zadana vrijednost je OFF) (zahtijeva MariaDB 10.5 ili noviju)
  • ssl_capath (dokumentacija), kojom navodimo putanju do direktorija s certifikatima autoriteta certifikata kojima se vjeruje, primjerice /usr/share/ca-certificates/mozilla
  • ssl_cipher (dokumentacija), kojom navodimo popis šifrarnika koji će se koristiti
  • tls_version (dokumentacija), kojom navodimo verziju TLS-a koji će se koristiti (zahtijeva MariaDB 10.4 ili noviju)

Note

Za generiranje adekvatnih sigurnosnih postavki možemo ponovno iskoristiti Mozillin generator SSL konfiguracije i kao poslužiteljski softver odabrati MySQL.

Šifriranje podataka na odmoru

MariaDB podržava šifriranje podataka na odmoru korištenjem HashiCorp Vaulta, Amazon Web Services (AWS) Key Management Servicea ili datoteke s ključevima. Kako nemamo trenutno postavljen vlastiti oblak koji koristi HashiCorp Vault i nemamo želju postavljati sve potrebne usluge na AWS-u, koristit ćemo dodatak file_key_management (dokumentacija) koji upravlja šifriranjem podataka na odmoru pomoću datoteke s ključevima za šifriranje baza podataka i binarnih logova.

Učitavanje dodatka

U konfiguracijskom direktoriju poslužitelja stvorimo datoteku file-key-management.cnf u kojoj ćemo konfiguracijskom naredbom plugin_load_add (dokumentacija) učitati dodatak file_key_management:

[mariadb]

plugin_load_add = file_key_management

Stvaranje simetričnih ključeva

Korišteni algoritam za šifriranje je Advanced Encryption Standard (AES) i podržane veličine ključeva su 128, 192 i 256 bita. Ključeve je moguće navesti po želji ili generirati OpenSSL-om kao slučajne podatke određene duljine. Kako se duljina navodi u bajtovima, za stvaranje 256-bitnog ključa generirat ćemo 32-bajtni slučajni podatak naredbom openssl rand:

$ openssl rand -hex 32
1cece9bfd9e0263da50bcf02d088b12889cf1eddeb7f8ffdd719b9ab23359be2

U slučaju da trebamo više ključeva, naredbu ćemo iskoristiti više puta. Dodatne informacije o ovoj naredbi i parametrima koje podržava moguće je pronaći u man stranici rand(1ssl) (naredba man 1ssl rand). Stvorimo direktorij za ključeve za šifriranje:

$ mkdir mariadb-server-conf/encryption

Stvorimo u tom direktoriju datoteku keyfile u kojoj su u svakom retku identifikator ključa (cijeli broj), znak točke sa zarezom i ključ:

1;1cece9bfd9e0263da50bcf02d088b12889cf1eddeb7f8ffdd719b9ab23359be2
2;df8762cdcd39d0e095a538ecad06ca94f55f805cc76841ed304ec26e4f46d2a0
11;6bf495bc15a970f8e51b7be49e0ebad5b74fc8febccd1ff45e259ca82e35a973
34;34e791122e8cb9fe983534d33bc45522d3e9ca2ec373e720eb08fc34e7f59b7b

Identifikatori ključa moraju biti međusobno različiti, ali ne moraju ići po redu.

Uključivanje datoteke s ključevima

Dopunimo datoteku file-key-management.cnf dodavanjem konfiguracijske naredbe file_key_management_filename (dokumentacija) tako da bude oblika:

[mariadb]

plugin_load_add = file_key_management
file_key_management_filename = /etc/mysql/conf.d/encryption/keyfile

Tip

Datoteku s ključevima je moguće šifrirati pa navesti ključ za dešifriranje konfiguracijskom naredbom file_key_management_filekey (dokumentacija).

Odabir algoritma za šifriranje

Podržane su dvije varijante algoritma AES:

Kombinacija CTR-a i GCM-a se smatra boljim odabirom i naša je verzija OpenSSL-a podržava pa ćemo njeno korištenje uključiti dodavanjem konfiguracijske naredbe file_key_management_encryption_algorithm (dokumentacija) u datoteku file-key-management.cnf tako da bude oblika:

[mariadb]

plugin_load_add = file_key_management
file_key_management_filename = /etc/mysql/conf.d/encryption/keyfile
file_key_management_encryption_algorithm = AES_CTR

Ako korišteni OpenSSL ne podržava taj algoritam, zamijenit ćemo posljednju liniju za:

file_key_management_encryption_algorithm = AES_CBC

Zaustavimo i pokrenimo ponovno poslužitelj kako bi učitao nove postavke pa se povežimo na njega klijentom.

Šifriranje tablica u bazi podataka

Šifriranje tablica u bazi podataka zahtijeva od nas da prvo stvorimo bazu podataka. Povežimo se na poslužitelj klijentom mariadb kao ranije pa stvorimo bazu SQL upitom CREATE DATABASE (dokumentacija):

CREATE DATABASE mojabaza;
Query OK, 1 row affected (0.000 sec)

Odaberimo je za korištenje naredbom USE (dokumentacija):

USE mojabaza;
Database changed

Uočimo kako nam piše ime baze unutar uglatih zagrada gdje je ranije pisalo (none). Stvorimo šifriranu tablicu SQL upitom CREATE TABLE (dokumentacija) uz navođenje opcije ENCRYPTED (dokumentacija) postavljene na YES:

CREATE TABLE names ( id int PRIMARY KEY, str varchar(50) ) ENCRYPTED=YES;
Query OK, 0 rows affected (0.004 sec)

Ubacimo i nešto podataka u tablicu SQL upitom INSERT (dokumentacija) jer će nam dobro doći kasnije da nam tablica nije prazna:

INSERT INTO names VALUES (1, 'Tomislav');
Query OK, 1 row affected (0.001 sec)
INSERT INTO names VALUES (2, 'Arijana');
Query OK, 1 row affected (0.001 sec)

Uvjerimo se da su podaci u tablici SQL upitom SELECT (dokumentacija):

SELECT * FROM names;
+----+----------+
| id | str      |
+----+----------+
|  1 | Tomislav |
|  2 | Arijana  |
+----+----------+
2 rows in set (0.000 sec)

Ova tablica i svi uneseni podaci su šifrirani korištenjem ključa s identifikatorom 1, koji je zadani ključ. U to da je ključ s identifikatorom 1 zadani možemo se uvjeriti dohvaćanjem vrijednosti varijable sesije innodb_default_encryption_key_id (dokumentacija). (InnoDB je zadani pogon za pohranu tablica u MariaDB, a dostupan je za korištenje i u MySQL-u.) Za dohvaćanje te varijable iskoristit ćemo naredbu SHOW na način:

SHOW SESSION VARIABLES LIKE 'innodb_default_encryption_key_id';
+----------------------------------+-------+
| Variable_name                    | Value |
+----------------------------------+-------+
| innodb_default_encryption_key_id | 1     |
+----------------------------------+-------+
1 row in set (0.001 sec)

Korištenje ključa različitog od zadanog možemo postaviti kod stvaranja tablice navođenjem dodatne opcije ENCRYPTION_KEY_ID (dokumentacija) postavljene na identifikator ključa:

CREATE TABLE surnames ( id int PRIMARY KEY, str varchar(50) ) ENCRYPTED=YES ENCRYPTION_KEY_ID=2;
Query OK, 0 rows affected (0.004 sec)

Ponovno, ubacimo nešto podataka da imamo s čime raditi kasnije:

INSERT INTO surnames VALUES (1, 'Lasić');
Query OK, 1 row affected (0.001 sec)
INSERT INTO surnames VALUES (2, 'Rebić');
Query OK, 1 row affected (0.001 sec)
INSERT INTO surnames VALUES (3, 'Kutleša');
Query OK, 1 row affected (0.001 sec)

Uvjerimo se ponovno da su podaci u tablici:

SELECT * FROM surnames;
+----+----------+
| id | str      |
+----+----------+
|  1 | Lasić    |
|  2 | Rebić    |
|  3 | Kutleša  |
+----+----------+
3 rows in set (0.000 sec)

Šifriranje binarnih logova

Šifriranje binarnih logova moguće je uključiti dodavanjem konfiguracijske naredbe encrypt_binlog (dokumentacija) postavljene na vrijednost ON:

[mariadb]

encrypt_binlog = ON

Privilegije korisnika

Dosad smo pokretali klijent MariaDB kao korijenski korisnik i zbog toga imali sva prava na svim bazama i svim tablicama u tim bazama. U praksi tu mogućnost želimo koristiti samo kad nam treba, a u redovnom radu ograničiti privilegije korisnika u radu s bazom i tablicama u njoj na one koje su zaista potrebne. Naime, u slučaju neograničenih prava zlonamjeran SQL upit može vrlo lako promijeniti ili izbrisati podatke kojima inače uopće ne pristupa i nema razloga pristupati. U aplikaciji želimo spriječiti da takav upit uopće dođe do sustava za upravljanje bazom podataka; ako ipak pronađe put do njega, u sustavu za upravljanje bazom podataka želimo spriječiti da bude uspješan.

Korisnici

MariaDB omogućuje upravljanje korisnicima korištenjem naredbi sličnih SQL upitima:

Stvorimo korisnika sa svojim imenom koji će se prijavljivati s lokalnog računala korištenjem lozinke:

CREATE USER 'ivanzhegalkin'@'localhost' IDENTIFIED BY 'ne3pr0v4lj1v4t4jn4l0z1nka';
Query OK, 0 rows affected (0.000 sec)

Sada se možemo prijaviti kao taj korisnik, što ćemo i napraviti u drugom terminalu bez prekidanja postojeće sesije korijenskog korisnika. Parametrom -u navodimo korisničko ime korisnika koji se prijavljuje, a parametrom -p navodimo da ćemo izvršiti prijavu korištenjem zaporke:

$ docker run -it --network db-network mariadb:10.11 mariadb -hfidit-mariadb -u ivanzhegalkin
ERROR 1045 (28000): Access denied for user 'ivanzhegalkin'@'localhost' (using password: NO)

$ docker run -it --network db-network mariadb:10.11 mariadb -hfidit-mariadb -u ivanzhegalkin -p
Enter password:
Welcome to the MariaDB monitor.  Commands end with ; or \g.
Your MariaDB connection id is 58
Server version: 10.11.2-MariaDB-1:10.11.2+maria~ubu2204 mariadb.org binary distribution

Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

MariaDB [(none)]>

Pokušamo li sada pristupiti bazi mojabaza od ranije, uočit ćemo kako to ne možemo izvesti:

USE mojabaza;
ERROR 1044 (42000): Access denied for user 'ivanzhegalkin'@'localhost' to database 'mojabaza'

Ostavimo otvorena oba terminala jer ćemo u nastavku dodjeljivati i provjeravati dodijeljene privilegije.

Privilegije

Korijenski korisnik može naredbom GRANT (dokumentacija) dodjeljivati privilegije drugim korisnicima, uključujući i privilegiju da mogu dalje dodjeljivati privilegije koje posjeduju. U nastavku ćemo raditi kao korijenski korisnik, a kao drugi korisnik možemo se eventualno uvjeriti da zaista posjedujemo dodijeljene privilegije.

Postoji više nivoa privilegija, a nama su zanimljive:

  1. globalne privilegije (popis u službenoj dokumentaciji), u koje spadaju pregledavanje popisa svih baza koje postoje na sustavu naredbom SHOW DATABASES, stvaranje korisnika naredbom CREATE USER i dodjeljivanje privilegija drugom korisniku naredbom GRANT OPTION:
  2. privilegije baze podataka (popis u službenoj dokumentaciji), u koje spadaju stvaranje baze naredbom CREATE DATABASE, brisanje baze naredbom DROP DATABASE i dodjeljivanje tih privilegija drugom korisniku naredbom GRANT OPTION;
  3. privilegije tablice (popis u službenoj dokumentaciji), u koje spadaju stvaranje tablice naredbom CREATE TABLE, stvaranje pogleda naredbom CREATE VIEW, promjena strukture tablice naredbom ALTER TABLE, čitanje podataka iz tablice naredbom SELECT, umetanje podataka u tablicu naredbom INSERT, promjenu podataka u tablici naredbom UPDATE, brisanje tablice ili pogleda naredbama DROP TABLE i DROP VIEW, stvaranje indeksa tablice naredbom CREATE INDEX i druge.

Dodijeljene privilegije mogu prikazati naredbom SHOW GRANTS (dokumentacija).

SHOW GRANTS FOR 'ivanzhegalkin'@'localhost';
+----------------------------------------------------------------------------------------------------------------------+
| Grants for ivanzhegalkin@localhost                                                                                   |
+----------------------------------------------------------------------------------------------------------------------+
| GRANT USAGE ON *.* TO `ivanzhegalkin`@`localhost` IDENTIFIED BY PASSWORD '*FB0DD9B1D2A1CF4B2203A2FBF5E1EAE4A2008788' |
+----------------------------------------------------------------------------------------------------------------------+
1 row in set (0.000 sec)

Dodjeljivanje privilegija

Privilegija USAGE ne omogućuje ništa specijalno, već samo označava da korisnik postoji. Dodijelimo korisniku pravo pregledavanja baza koje postoje na sustavu:

GRANT SHOW DATABASES ON *.* TO 'ivanzhegalkin'@'localhost';
Query OK, 0 rows affected (0.000 sec)

Kako bismo bili sigurni da su naše promjene privilegija aktivne, moramo sprati dodijeljene privilegije naredbom FLUSH (dokumentacija):

FLUSH PRIVILEGES;
Query OK, 0 rows affected (0.000 sec)

Uočimo promjenu kod izlaza naredbe SHOW GRANTS:

SHOW GRANTS FOR 'ivanzhegalkin'@'localhost';
+-------------------------------------------------------------------------------------------------------------------------------+
| Grants for ivanzhegalkin@localhost                                                                                            |
+-------------------------------------------------------------------------------------------------------------------------------+
| GRANT SHOW DATABASES ON *.* TO `ivanzhegalkin`@`localhost` IDENTIFIED BY PASSWORD '*FB0DD9B1D2A1CF4B2203A2FBF5E1EAE4A2008788' |
+-------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.000 sec)

Uvjerimo se kao obični korisnik da smo zaista dobili privilegiju pregledavanja popisa baza podataka:

SHOW DATABASES;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mojabaza           |
| mysql              |
| performance_schema |
+--------------------+
4 rows in set (0.000 sec)

Kako se čitanje podataka iz baze vrši naredbom SELECT, pravo čitanja podataka iz svih tablica korisniku ćemo dati na način:

GRANT SELECT ON mojabaza.* to 'ivanzhegalkin'@'localhost';
Query OK, 0 rows affected (0.000 sec)
FLUSH PRIVILEGES;
Query OK, 0 rows affected (0.000 sec)
SHOW GRANTS FOR 'ivanzhegalkin'@'localhost';
+-------------------------------------------------------------------------------------------------------------------------------+
| Grants for ivanzhegalkin@localhost                                                                                            |
+-------------------------------------------------------------------------------------------------------------------------------+
| GRANT SHOW DATABASES ON *.* TO `ivanzhegalkin`@`localhost` IDENTIFIED BY PASSWORD '*FB0DD9B1D2A1CF4B2203A2FBF5E1EAE4A2008788' |
| GRANT SELECT ON `mojabaza`.* TO `ivanzhegalkin`@`localhost`                                                                   |
+-------------------------------------------------------------------------------------------------------------------------------+
2 rows in set (0.000 sec)

Uvjerimo se kao obični korisnik da zaista imamo privilegije pregledavanja tablica i čitanja podataka iz njih:

USE mojabaza;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Database changed
SHOW TABLES;
+--------------------+
| Tables_in_mojabaza |
+--------------------+
| names              |
| surnames           |
+--------------------+
2 rows in set (0.000 sec)
DESCRIBE names;
+-------+-------------+------+-----+---------+-------+
| Field | Type        | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| id    | int(11)     | NO   | PRI | NULL    |       |
| str   | varchar(50) | YES  |     | NULL    |       |
+-------+-------------+------+-----+---------+-------+
2 rows in set (0.001 sec)
DESCRIBE surnames;
+-------+-------------+------+-----+---------+-------+
| Field | Type        | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| id    | int(11)     | NO   | PRI | NULL    |       |
| str   | varchar(50) | YES  |     | NULL    |       |
+-------+-------------+------+-----+---------+-------+
2 rows in set (0.001 sec)
SELECT * FROM names;
+----+----------+
| id | str      |
+----+----------+
|  1 | Tomislav |
|  2 | Arijana  |
+----+----------+
2 rows in set (0.000 sec)
SELECT * FROM surnames;
+----+----------+
| id | str      |
+----+----------+
|  1 | Lasić    |
|  2 | Rebić    |
|  3 | Kutleša  |
+----+----------+
3 rows in set (0.000 sec)

Uvjerimo se i da nismo dobili druge privilegije:

INSERT INTO names VALUES (5, 'Marko');
ERROR 1142 (42000): INSERT command denied to user 'ivanzhegalkin'@'localhost' for table 'names'
DROP TABLE surnames;
ERROR 1142 (42000): DROP command denied to user 'ivanzhegalkin'@'localhost' for table 'surnames'

Ako to želimo, na analogan način bismo uz pomoć popisa privilegija tablice mogli dodijeliti te privilegije kao i mogućnost promjene podataka, promjene strukture tablice i druge.

Opozivanje privilegija

Dodijeljene privilegije se opozivaju naredbom REVOKE (dokumentacija) čiji je način korištenja potpuno analogan načinu korištenja naredbe GRANT.

Uloge

Uloge se koriste za grupiranje većeg broja privilegija zajedno, što olakšava dodjeljivanje privilegijama korisnicima. Privilegije se dodjeljuju ulozi, a onda se uloga dodjeljuje proizvoljnom broju korisnika. Naredba CREATE ROLE (dokumentacija) stvara ulogu, a naredba DROP ROLE (dokumentacija) briše ulogu.

Za ilustraciju, možemo zamisliti sustav u kojem studenti tek uče raditi s bazama podataka pa imaju pravo čitanja podataka iz svih tablica iz svih baza, ali ne i zapisivanja podataka u njih. Ulogu student ćemo stvoriti, dodijeliti joj privilegije i dodijeliti je korisnicima na način:

CREATE ROLE student;

GRANT SHOW DATABASES ON *.* TO student;
GRANT SELECT ON *.* TO student;

GRANT student to filip;
GRANT student to laura;

S druge strane, profesori imaju potrebu i unositi novi sadržaj u baze podataka i uređivati postojeći sadržaj u njima pa za ulogu professor imamo:

CREATE ROLE professor;

GRANT SHOW DATABASES ON *.* TO professor;
GRANT SELECT ON *.* TO professor;
GRANT INSERT ON *.* TO professor;
GRANT UPDATE ON *.* TO professor;

GRANT professor to lucia;
GRANT professor to danijela;
GRANT professor to kristian;

Naredba DROP ROLE koristi se analogno naredbi CREATE ROLE.

Dodatak: pregled strukture konfiguracije poslužitelja MariaDB

Nakon instalacije sva konfiguracija poslužitelja MariaDB nalazi se u /etc/mysql. Nama će u nastavku biti zanimljive samo datoteka /etc/mysql/mariadb.cnf i datoteke u direktorijima /etc/mysql/mariadb.conf.d i /etc/mysql/mariadb.conf.d. Razmotrimo za početak sadržaj datoteke /etc/mysql/mariadb.cnf:

# The MariaDB configuration file
#
# The MariaDB/MySQL tools read configuration files in the following order:
# 1. "/etc/mysql/mariadb.cnf" (this file) to set global defaults,
# 2. "/etc/mysql/conf.d/*.cnf" to set global options.
# 3. "/etc/mysql/mariadb.conf.d/*.cnf" to set MariaDB-only options.
# 4. "~/.my.cnf" to set user-specific options.
#
# If the same option is defined multiple times, the last one will apply.
#
# One can use all long options that the program supports.
# Run program with --help to get a list of available options and with
# --print-defaults to see which it would actually understand and use.

#
# This group is read both both by the client and the server
# use it for options that affect everything
#
[client-server]

# Import all .cnf files from configuration directory
!includedir /etc/mysql/conf.d/
!includedir /etc/mysql/mariadb.conf.d/

Uočimo kako gotovo čitav sadržaj datoteke čine komentari i prazni retci, osim odjeljka [client-server] i dvije naredbe !includedir kojima se uključuju konfiguracijske datoteke iz dva već ranije spomenuta direktorija.

U direktoriju /etc/mysql/conf.d/ datoteka mysql.cnf sadrži samo oznaku odjeljka, a datoteka mysqldump.cnf tiče se konfiguracije naredbe mysqldump koja omogućuje pohranjivanje baza u tekstualnom zapisu kao niz SQL upita i koja nam u nastavku neće trebati.

U direktoriju /etc/mysql/mariadb.conf.d/ nalazimo konfiguraciju klijenta (50-client.cnf), svih aplikacija za pristup poslužitelju (50-mysql-clients.cnf), konfiguraciju za sigurno pokretanje u slučaju problema (50-mysqld_safe.cnf) i konfiguraciju poslužitelja (50-server.cnf). Razmtorimo sadržaj posljednje datoteke:

#
# These groups are read by MariaDB server.
# Use it for options that only the server (but not clients) should see
#
# See the examples of server my.cnf files in /usr/share/mysql

# this is read by the standalone daemon and embedded servers
[server]

# this is only for the mysqld standalone daemon
[mysqld]

#
# * Basic Settings
#
user                    = mysql
pid-file                = /run/mysqld/mysqld.pid
socket                  = /run/mysqld/mysqld.sock
#port                   = 3306
basedir                 = /usr
datadir                 = /var/lib/mysql
tmpdir                  = /tmp
lc-messages-dir         = /usr/share/mysql
#skip-external-locking

# Instead of skip-networking the default is now to listen only on
# localhost which is more compatible and is not less secure.
bind-address            = 127.0.0.1

# ...

Uočimo kako su u odjeljku [mysqld] koji se odnosi na poslužitelj MariaDB navedene brojne konfiguracijske naredbe, primjerice:

  • user, kojom se postavlja ime korisnika koji pokreće poslužitelj,
  • pid, kojom se postavlja putanja do datoteke u kojoj je naveden PID procesa poslužitelja,
  • datadir, kojom se navodi putanja do podatkovnog direktorija u kojem se spremaju baze podataka i binarni logovi
  • tmpdir, kojom se navodi putanja do direktorija s privremenim datotekama i
  • lc-messages-dir, kojom se navodi putanja do direktorija s lokalizacijskim datotekama (prijevodima na različite jezike).

Author: Vedran Miletić