Güvenli MySQL Kurulumu: mysql_secure_installation Sonrası Yapılacaklar

Yeni bir sunucuya MySQL kurduğunuzda ve mysql_secure_installation komutunu çalıştırdığınızda, pek çok yönetici “tamam, güvenliği sağladım” diye düşünür ve geçer. Oysa bu araç sadece temel güvenlik adımlarını atar: root şifresini belirler, anonim kullanıcıları siler, test veritabanını kaldırır. Gerçek anlamda güvenli bir MySQL kurulumu için yapılacak çok daha fazla şey var. Bu yazıda, mysql_secure_installation sonrasında uygulamanız gereken adımları tek tek ele alacağız.

mysql_secure_installation Ne Yapar, Ne Yapmaz?

Önce şunu netleştirelim. mysql_secure_installation şunları yapar:

  • Root hesabına şifre atar (eğer yoksa)
  • Anonim kullanıcı hesaplarını siler
  • Root kullanıcısının uzaktan bağlanmasını engeller
  • Test veritabanını siler
  • Privilege tablolarını yeniler

Bunlar iyi bir başlangıç, ama yeterli değil. Özellikle production ortamında çalışacak bir veritabanı sunucusu için asgari gereksinimler bunlar. Şimdi gerçekten güvenli bir kurulum için neleri yapmanız gerektiğine bakalım.

Kullanıcı Yönetimi ve Yetki Kontrolü

Mevcut Kullanıcıları Denetleyin

İlk iş olarak sistemde hangi kullanıcıların olduğunu ve hangi yetkilere sahip olduklarını gözden geçirin:

mysql -u root -p -e "SELECT User, Host, plugin, authentication_string FROM mysql.user;"

Bu çıktıda dikkat etmeniz gerekenler:

  • Host sütununda % olan kullanıcılar, her yerden bağlanabilir demektir
  • plugin sütununda mysql_native_password yerine caching_sha2_password veya auth_socket görmek istersiniz
  • Boş kullanıcı adları hala varsa, anonim erişim mümkün demektir

Eğer hala anonim kullanıcı kalmışsa temizleyin:

mysql -u root -p -e "DELETE FROM mysql.user WHERE User='';"
mysql -u root -p -e "FLUSH PRIVILEGES;"

Uygulama Kullanıcılarını Minimum Yetki ile Oluşturun

Her uygulama için ayrı bir kullanıcı oluşturun ve o uygulamanın ihtiyaç duyduğu yetkilerden fazlasını vermeyin. Bu, “principle of least privilege” yani en az yetki ilkesinin veritabanına uygulanmasıdır.

Bir WordPress sitesi için kullanıcı oluşturmak istediğinizi düşünelim:

mysql -u root -p <<EOF
CREATE USER 'wp_user'@'localhost' IDENTIFIED BY 'GucluBirSifre2024!';
GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, INDEX, ALTER ON wordpress_db.* TO 'wp_user'@'localhost';
FLUSH PRIVILEGES;
EOF

Dikkat edin, GRANT ALL PRIVILEGES kullanmadık. WordPress’in ihtiyaç duymadığı SUPER, FILE, PROCESS gibi yetkiler vermedik. Eğer uygulamanız sadece okuma yapıyorsa, sadece SELECT yeterlidir.

Bir raporlama aracı için salt okunur kullanıcı:

mysql -u root -p -e "CREATE USER 'readonly_user'@'10.0.1.50' IDENTIFIED BY 'RaporSifresi2024!'; GRANT SELECT ON production_db.* TO 'readonly_user'@'10.0.1.50'; FLUSH PRIVILEGES;"

Burada 10.0.1.50 yerine gerçek IP adresinizi yazın. Host kısıtlaması çok önemli, % kullanmaktan kaçının.

Root Hesabını Kilitlemek

Root hesabının localhost dışından bağlanmasını mysql_secure_installation engelliyor, ama bazı dağıtımlarda root hesabı auth_socket plugin ile çalışıyor olabilir. Bu durumu kontrol edin:

mysql -u root -p -e "SELECT User, Host, plugin FROM mysql.user WHERE User='root';"

Eğer root ile işlem yapmanız gerekiyorsa, bunun yerine tam yetkili ayrı bir yönetici hesabı oluşturun:

mysql -u root -p <<EOF
CREATE USER 'db_admin'@'localhost' IDENTIFIED BY 'AdminSifresi2024!';
GRANT ALL PRIVILEGES ON *.* TO 'db_admin'@'localhost' WITH GRANT OPTION;
FLUSH PRIVILEGES;
EOF

Bu şekilde root yerine db_admin kullanırsınız ve güvenlik loglarında hangi işlemlerin kim tarafından yapıldığını daha kolay takip edersiniz.

MySQL Konfigürasyon Dosyasını Güvenli Hale Getirme

my.cnf veya my.ini dosyasında yapmanız gereken kritik ayarlar var. Genellikle bu dosya /etc/mysql/mysql.conf.d/mysqld.cnf veya /etc/my.cnf konumunda bulunur:

sudo nano /etc/mysql/mysql.conf.d/mysqld.cnf

Aşağıdaki ayarları [mysqld] bölümüne ekleyin:

[mysqld]
# Ağ Güvenliği
bind-address = 127.0.0.1
# Eğer uzak bağlantı gerekmiyorsa, sadece localhost dinle
skip-networking = 0

# Güvenlik Ayarları
local-infile = 0
# LOCAL INFILE ile dosya okuma saldırılarını engelle

secure-file-priv = /var/lib/mysql-files
# Dosya okuma/yazma işlemlerini bu dizinle sınırla

symbolic-links = 0
# Sembolik link saldırılarını engelle

skip-show-database
# Yetkisiz kullanıcıların veritabanı listesini görmesini engelle

# Log Ayarları
general_log = 0
general_log_file = /var/log/mysql/mysql.log
log_error = /var/log/mysql/error.log

# Slow Query Log
slow_query_log = 1
slow_query_log_file = /var/log/mysql/mysql-slow.log
long_query_time = 2

Değişiklikleri uygulamak için MySQL’i yeniden başlatın:

sudo systemctl restart mysql
# veya MariaDB için
sudo systemctl restart mariadb

bind-address Ayarının Önemi

Eğer veritabanınıza sadece aynı sunucudan bağlanılacaksa bind-address = 127.0.0.1 ayarı kritik öneme sahiptir. Bu ayar, MySQL’in dış dünyaya port açmasını engeller. Uzak bağlantıya ihtiyaç varsa, % yerine belirli bir IP adresi belirtin.

Güvenlik Duvarı Kuralları

MySQL varsayılan olarak 3306 portunda çalışır. Bu portu gereksiz yere internete açmayın.

Ubuntu/Debian üzerinde UFW ile:

# Sadece belirli bir IP'den MySQL erişimine izin ver
sudo ufw allow from 10.0.1.0/24 to any port 3306

# Veya sadece localhost (bind-address ayarıyla zaten sağlandı ama ek güvenlik için)
sudo ufw deny 3306

# Kuralları kontrol et
sudo ufw status verbose

CentOS/RHEL üzerinde firewalld ile:

# MySQL servisini belirli bir zone'a ekle
sudo firewall-cmd --zone=internal --add-service=mysql --permanent

# Belirli bir kaynak IP için kural ekle
sudo firewall-cmd --permanent --zone=internal --add-source=10.0.1.0/24

sudo firewall-cmd --reload

# Kuralları doğrula
sudo firewall-cmd --list-all --zone=internal

Eğer uygulamanız ve veritabanınız aynı sunucudaysa, 3306 portunu dış dünyaya hiç açmayın. Uzak erişim gerekiyorsa MySQL’e doğrudan bağlanmak yerine SSH tünel kullanmayı düşünün.

SSL/TLS ile Şifreli Bağlantı

Uygulama sunucunuz ile veritabanı sunucunuz farklı makinelerdeyse, aralarındaki trafiği şifrelemek şarttır. MySQL 8.0 ve MariaDB’nin yeni sürümlerinde SSL desteği genellikle varsayılan olarak gelir, ama doğru yapılandırmak gerekir.

Önce mevcut SSL durumunu kontrol edin:

mysql -u root -p -e "SHOW VARIABLES LIKE '%ssl%';"
mysql -u root -p -e "SHOW STATUS LIKE 'Ssl_cipher';"

Self-signed sertifika oluşturun (production için gerçek CA sertifikası kullanın):

# Sertifika dizini oluştur
sudo mkdir -p /etc/mysql/ssl
cd /etc/mysql/ssl

# CA anahtarı ve sertifikası
sudo openssl genrsa 2048 | sudo tee ca-key.pem
sudo openssl req -new -x509 -nodes -days 3650 -key ca-key.pem -out ca-cert.pem -subj "/CN=MySQL-CA"

# Sunucu anahtarı ve sertifikası
sudo openssl req -newkey rsa:2048 -nodes -keyout server-key.pem -out server-req.pem -subj "/CN=mysql-server"
sudo openssl x509 -req -in server-req.pem -days 3650 -CA ca-cert.pem -CAkey ca-key.pem -set_serial 01 -out server-cert.pem

# İzinleri ayarla
sudo chown mysql:mysql /etc/mysql/ssl/*.pem
sudo chmod 600 /etc/mysql/ssl/server-key.pem
sudo chmod 644 /etc/mysql/ssl/ca-cert.pem /etc/mysql/ssl/server-cert.pem

my.cnf dosyasına SSL ayarlarını ekleyin:

[mysqld]
ssl-ca=/etc/mysql/ssl/ca-cert.pem
ssl-cert=/etc/mysql/ssl/server-cert.pem
ssl-key=/etc/mysql/ssl/server-key.pem
require_secure_transport=ON

require_secure_transport=ON ayarı, SSL olmadan bağlanmaya çalışan herkesi engeller. Bu çok önemli bir adım.

Log Yönetimi ve Denetim

Bir güvenlik olayı yaşandığında geriye dönük inceleme yapabilmeniz için loglar kritik öneme sahiptir.

Error Log

MySQL hata logları varsayılan olarak aktif gelir. Nerede olduğunu kontrol edin:

mysql -u root -p -e "SHOW VARIABLES LIKE 'log_error';"

General Query Log

Geliştirme ortamında veya sorun giderme sırasında tüm sorguları loglamak isteyebilirsiniz. Ama production’da dikkatli kullanın, disk I/O’yu ciddi şekilde artırır:

# Geçici olarak aktif et (restart gerektirmez)
mysql -u root -p -e "SET GLOBAL general_log = 'ON';"
mysql -u root -p -e "SET GLOBAL general_log_file = '/var/log/mysql/general.log';"

# İşin bitince kapat
mysql -u root -p -e "SET GLOBAL general_log = 'OFF';"

Audit Plugin ile Gelişmiş Denetim

MariaDB’de audit plugin yerleşik gelir. MySQL için audit_log plugin Enterprise sürümde var, ama Percona ve MariaDB alternatiflerini kullanabilirsiniz. MariaDB için:

mysql -u root -p <<EOF
INSTALL PLUGIN server_audit SONAME 'server_audit.so';
SET GLOBAL server_audit_logging=ON;
SET GLOBAL server_audit_events='CONNECT,QUERY,TABLE';
SET GLOBAL server_audit_file_path='/var/log/mysql/audit.log';
EOF

Bu ayarları kalıcı hale getirmek için my.cnf dosyasına ekleyin:

[mysqld]
plugin-load-add=server_audit=server_audit.so
server_audit_logging=ON
server_audit_events=CONNECT,QUERY,TABLE
server_audit_file_path=/var/log/mysql/audit.log

Şifre Politikası

MySQL’de validate_password plugin’i aktif ederek güçlü şifre politikası uygulayabilirsiniz:

# Plugin'i kontrol et
mysql -u root -p -e "SHOW PLUGINS;" | grep validate

# MySQL 8.0'da component olarak gelir
mysql -u root -p -e "INSTALL COMPONENT 'file://component_validate_password';"

# Politikayı yapılandır
mysql -u root -p <<EOF
SET GLOBAL validate_password.policy=MEDIUM;
SET GLOBAL validate_password.length=12;
SET GLOBAL validate_password.mixed_case_count=1;
SET GLOBAL validate_password.number_count=1;
SET GLOBAL validate_password.special_char_count=1;
EOF

Şifre politikası seviyeleri:

  • LOW: Sadece uzunluk kontrolü yapar
  • MEDIUM: Uzunluk, büyük/küçük harf, rakam ve özel karakter kontrolü yapar
  • STRONG: MEDIUM’a ek olarak şifreyi sözlük dosyasıyla karşılaştırır

my.cnf dosyasına kalıcı ayarlar:

[mysqld]
validate_password.policy=MEDIUM
validate_password.length=12
validate_password.mixed_case_count=1
validate_password.number_count=1
validate_password.special_char_count=1

Yedekleme Kullanıcısı Oluşturma

Yedekleme scriptleri için root kullanıcısı kullanmak yerine, sadece yedekleme için gereken yetkilere sahip özel bir kullanıcı oluşturun:

mysql -u root -p <<EOF
CREATE USER 'backup_user'@'localhost' IDENTIFIED BY 'YedeklemeSifresi2024!';
GRANT SELECT, SHOW DATABASES, LOCK TABLES, RELOAD, REPLICATION CLIENT, EVENT, TRIGGER ON *.* TO 'backup_user'@'localhost';
FLUSH PRIVILEGES;
EOF

Bu kullanıcının şifresini düz metin olarak script içine yazmak yerine, MySQL’in credential dosyası kullanın:

# Dosyayı oluştur
cat > /root/.my_backup.cnf << 'EOF'
[client]
user=backup_user
password=YedeklemeSifresi2024!
EOF

# Dosya izinlerini kısıtla
chmod 600 /root/.my_backup.cnf

Yedekleme scriptinde kullanımı:

#!/bin/bash
BACKUP_DIR="/var/backups/mysql"
DATE=$(date +%Y%m%d_%H%M%S)

mkdir -p $BACKUP_DIR

mysqldump --defaults-file=/root/.my_backup.cnf 
  --all-databases 
  --single-transaction 
  --routines 
  --triggers 
  --events 
  | gzip > $BACKUP_DIR/full_backup_$DATE.sql.gz

echo "Yedekleme tamamlandi: $BACKUP_DIR/full_backup_$DATE.sql.gz"

Performans Şeması ve Bilgi Şemasının Güvenliği

performance_schema ve information_schema veritabanları sistem bilgisi içerir. Normal uygulama kullanıcılarının bu şemalara geniş erişimi olmamalı.

mysql -u root -p <<EOF
-- Bir kullanıcının performance_schema erişimini kontrol et
SHOW GRANTS FOR 'wp_user'@'localhost';

-- performance_schema'ya erişimi kısıtla (zaten varsayılan olarak kısıtlı gelir)
-- Ama emin olmak için kontrol edin
REVOKE ALL ON performance_schema.* FROM 'wp_user'@'localhost';
FLUSH PRIVILEGES;
EOF

Periyodik Güvenlik Kontrol Scripti

Aşağıdaki scripti cron job olarak çalıştırarak düzenli güvenlik denetimi yapabilirsiniz:

#!/bin/bash
# MySQL Guvenlik Denetim Scripti
# /usr/local/bin/mysql_security_check.sh

MYSQL_USER="db_admin"
MYSQL_PASS="AdminSifresi2024!"
LOG_FILE="/var/log/mysql_security_audit.log"
DATE=$(date '+%Y-%m-%d %H:%M:%S')

echo "=== MySQL Guvenlik Denetimi - $DATE ===" | tee -a $LOG_FILE

# Anonim kullanicilari kontrol et
echo "--- Anonim Kullanicilar ---" | tee -a $LOG_FILE
mysql -u$MYSQL_USER -p$MYSQL_PASS -e "SELECT User, Host FROM mysql.user WHERE User='';" 2>/dev/null | tee -a $LOG_FILE

# Root uzak erisimi kontrol et
echo "--- Root Uzak Erisim ---" | tee -a $LOG_FILE
mysql -u$MYSQL_USER -p$MYSQL_PASS -e "SELECT User, Host FROM mysql.user WHERE User='root' AND Host NOT IN ('localhost', '127.0.0.1', '::1');" 2>/dev/null | tee -a $LOG_FILE

# Wildcard host kullanan kullanicilar
echo "--- Wildcard Host Kullananlar ---" | tee -a $LOG_FILE
mysql -u$MYSQL_USER -p$MYSQL_PASS -e "SELECT User, Host FROM mysql.user WHERE Host='%';" 2>/dev/null | tee -a $LOG_FILE

# Bos sifreli kullanicilar
echo "--- Bos Sifreli Kullanicilar ---" | tee -a $LOG_FILE
mysql -u$MYSQL_USER -p$MYSQL_PASS -e "SELECT User, Host FROM mysql.user WHERE authentication_string='' OR authentication_string IS NULL;" 2>/dev/null | tee -a $LOG_FILE

# SSL durumu
echo "--- SSL Durumu ---" | tee -a $LOG_FILE
mysql -u$MYSQL_USER -p$MYSQL_PASS -e "SHOW VARIABLES LIKE 'have_ssl';" 2>/dev/null | tee -a $LOG_FILE

echo "=== Denetim Tamamlandi ===" | tee -a $LOG_FILE

Bu scripti haftada bir çalıştırmak için cron ayarı:

chmod +x /usr/local/bin/mysql_security_check.sh
echo "0 9 * * 1 root /usr/local/bin/mysql_security_check.sh" | sudo tee -a /etc/cron.d/mysql_audit

Dosya Sistemi İzinleri

MySQL data dizininin doğru izinlere sahip olduğundan emin olun:

# Data dizinini kontrol et
ls -la /var/lib/mysql/

# Doğru izinleri ayarla
sudo chown -R mysql:mysql /var/lib/mysql/
sudo chmod 750 /var/lib/mysql/

# Log dizinini kontrol et
sudo chown -R mysql:adm /var/log/mysql/
sudo chmod 750 /var/log/mysql/

MySQL Versiyonunu Güncel Tutma

Bu sıradan bir tavsiye gibi görünebilir ama güvenlik açısından çok kritik. MySQL ve MariaDB için güvenlik güncellemelerini takip edin:

# Ubuntu/Debian
sudo apt-get update && sudo apt-get upgrade mysql-server

# CentOS/RHEL
sudo yum update mysql-server

# Mevcut versiyonu kontrol et
mysql -u root -p -e "SELECT VERSION();"

# Değişikliklerden önce mutlaka yedek al
mysqldump --all-databases -u root -p | gzip > /tmp/pre_update_backup.sql.gz

Sonuç

mysql_secure_installation iyi bir başlangıç noktası, ama bir bitiş noktası değil. Gerçek anlamda güvenli bir MySQL kurulumu için şu adımları tamamlamanız gerekiyor:

  • Kullanıcı yönetimini en az yetki prensibine göre kurmak
  • Konfigürasyon dosyasını güvenlik odaklı düzenlemek
  • Güvenlik duvarı kurallarını doğru yapılandırmak
  • SSL/TLS şifrelemesini etkinleştirmek
  • Güçlü şifre politikası uygulamak
  • Log ve denetim mekanizmalarını kurmak
  • Yedekleme için özel kullanıcı oluşturmak
  • Dosya sistemi izinlerini kontrol etmek
  • Sistemi güncel tutmak

Bunların hepsini tek seferde yapmanıza gerek yok. Önce kendi ortamınız için en kritik olanları belirleyin ve oradan başlayın. Production veritabanı söz konusu olduğunda, özellikle bind-address, güvenlik duvarı kuralları ve SSL ayarları en yüksek öncelikli maddeler olmalı. Geri kalanları zaman içinde ekleyerek güvenlik seviyenizi kademeli olarak artırabilirsiniz.

Yorum yapın