$ systemctl status mariadb ● mariadb.service - MariaDB 11.3.2 database server Loaded: loaded (/lib/systemd/system/mariadb.service; enabled; vendor preset: enabled) Drop-In: /etc/systemd/system/mariadb.service.d └─migrated-from-my.cnf-settings.conf Active: active (running) since Tue 2024-03-05 06:32:22 KST; 7min ago Docs: man:mariadbd(8) https://mariadb.com/kb/en/library/systemd/
MariaDB 보안 설정하기
설치후에 MariaDB 시스템 초기화와 보안 설정을 진행해야 한다.
7개 질문이 나오는데 unix_socket 은 n 이고 나머지는 기본 값으로 진행한다.
단, root 패스워드는 잊어버리지 않아야 한다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
$ sudo mysql_secure_installation
Enter current password for root (enter for none):
Switch to unix_socket authentication [Y/n] n
Change the root password? [Y/n] Y
Remove anonymous users? [Y/n] Y
Disallow root login remotely? [Y/n] Y
Remove test database and access to it? [Y/n] Y
Reload privilege tables now? [Y/n] Y
이제 root 계정으로 명령행으로 접속해 보자
1 2 3 4 5 6 7 8 9 10 11
~$ mariadb -u root -p Enter password: Welcome to the MariaDB monitor. Commands end with ; or \g. Your MariaDB connection id is 40 Server version: 11.3.2-MariaDB-1:11.3.2+maria~ubu2204 mariadb.org binary distribution
Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.
Type 'help;' or '\h'forhelp. Type '\c' to clear the current input statement.
MariaDB [(none)]>
현재 11버전까지 mysql 클라이언트를 사용하지만 향후 deprecated 될 예정으로
mariadb 클라이언트 사용을 권장한다.
Option file 설정
설정 파일은 유닉스 계열은 my.cnf (or mariadb.cnf) 이고 윈도우 계열은 my.ini 이다.
import pymysql from sshtunnel import SSHTunnelForwarder
with SSHTunnelForwarder(('DBSERVER', 2020), ssh_username=SERVER24_USER, ssh_password=SERVER24_PW, remote_bind_address=('127.0.0.1', 3306), ) as tunnel:
# connect MySQL like local with pymysql.connect( host='127.0.0.1', #(local_host) user=DB_USER, passwd=DB_PW, db='lecture', charset='utf8', port=tunnel.local_bind_port, # ssh로 접속한 클라이언트 포트 cursorclass=pymysql.cursors.DictCursor) as conn: with conn.cursor() as cur: sql = "show tables;" cur.execute(sql) print(sql) results = cur.fetchall() print(results) for result in results: print(result)
터널링을 통해서 SQL Query가 잘 진행된다.
사례2) ssh_pkey 사용 (실패)
기록을 위해 남긴다. 잘 안되는 코드이다.
사례2 같이 직접 서버에 접근이 안되는 경우 ssh key pair 를 사용할 수 있다.
사용자 아이디, 패스워드 형식에서 패스워드를 직접 코드 등에 입력하기 보다 private key 쌍을 사용하면 좀 더 보안에 안전하다.
ssh-keygen 으로 생성한 공개키를 DB 서버의 ssh/authorized_keys`` 파일에 id_rsa.pub 내용을 ssh-copy-id또는scp` 명령으로 서버에 복사한다.
with SSHTunnelForwarder(('DBSERVER', 2020), ssh_username='qkboo', ssh_pkey='~/.ssh/id_rsa', remote_bind_address=('127.0.0.1', 3306)) as tunnel:
print( tunnel.ssh_host_key ) print( tunnel.local_bind_address ) print( tunnel._remote_binds ) # connect MySQL like local with pymysql.connect( host='127.0.0.1', #(local_host) user='user1', passwd='012345', db='lecture', charset='utf8', port=3306, # port=tunnel.local_bind_port, cursorclass=pymysql.cursors.DictCursor) as conn: with conn.cursor() as cur: sql = "show tables;" cur.execute(sql) print(sql) results = cur.fetchall() print(results) for result in results: print(result)
SQLAlchemy engine 생성하기
SQLAlchemy 의 engine 을 생성할 수 있다. with 구문과 함께 사용할 수 있지만 engine 을 여러 프로시저에서 지속해서 사용한다면 아래 같이 start(), stop() 사이에 pymysql, sqlalchemy 코드를 배치해도 좋다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
# SSH Tunnel 사용1 from sshtunnel import SSHTunnelForwarder
server = SSHTunnelForwarder(('DBSERVER', 2020), ssh_username=SERVER24_USER, ssh_password=SERVER24_PW, remote_bind_address=('127.0.0.1', 3306), ) server.start() # Tunnel 시작
MySQL / MaraiDB 서버에 TLS 를 활성화 해서 암호화 통신을 할 수 있다. MySQL (MariaDB도 동일함)에서는 서버-클라이언트 사이에 전송되는 데이터를 TLS (이전 SSL) 프로토콜을 이용하여 암호화하여 DB 정보가 노출되지 않게 방지할 수 있다. SSL을 통해서 Replication Master - Slave 도 가능하다.
인증서는 사설 CA(Certificate Authority)용 인증서, 서버용, 클라이언트용 총 3가지를 만든다.
인증서 저장 위치 생성
1 2
(SERVER) $ sudo mkdir /etc/ssl/mysql (SERVER) $ cd /etc/ssl/mysql
생성한 TLS 인증서는 MySQL/MariaDB 의 my.cnf 설정파일의 변수를 3가지 설정한다.
ssl_cert 시스템 변수: 서버 인증서(X509) 경로 지정
ssl_key 시스템 변수: 서버 개인키 경로 지정
ssl_ca 혹은 ssl_capath 시스템 변수: Self-signed CA certificate CA 키 경로
openssl 사설 CA 인증서 생성
저장 위치 /etc/ssl/mysql 에서 관리용 CA 인증서 생성한다.
먼저 openssl에서 rsa 알고리즘으로 4096 크기 비밀키를 생성한다.
1 2 3
(SERVER) $ sudo openssl genrsa -out ca-key.pem 4096 Generating RSA private key, 4096 bit long modulus (2 primes) ...
비밀키 파일 ca-key.pem 파일을 사용해서 CA인증서 ca.pem 파일로 생성한다. 비밀키로 CA를 위한 CSR(certificate signing request) 과정을 거쳐 ca.pem 을 생성해9서 필요한 인증서 정보를 묻는다.
1 2 3 4 5 6 7 8 9
(SERVER) $ sudo openssl req -new -x509 -nodes -days 365000 -key ca-key.pem -out ca.pem ... Country Name (2 letter code) [AU]: KR State or Province Name (full name) [Some-State]:Seoul Locality Name (eg, city) []: Organization Name (eg, company) [Internet Widgits Pty Ltd]:YOUR company Organizational Unit Name (eg, section) []: Administration Common Name (e.g. server FQDN or YOUR name) []::mysql-admin.DOMAIN.name Email Address []:
Country Name (2 letter code) [AU]:KR State or Province Name (full name) [Some-State]:Seoul Locality Name (eg, city) []: Organization Name (eg, company) [Internet Widgits Pty Ltd]:YOUR company Organizational Unit Name (eg, section) []:Administration Common Name (e.g. server FQDN or YOUR name) []:server.DOMAIN.name Email Address []:
Please enter the following 'extra' attributes to be sent with your certificate request A challenge password []: An optional company name []: ...
클라이언트 인증서는 다음과 같은 용도로 사용한다. 단, openssl 명령 과정에서 Common Name 을 3가지 모두 다르게 해야 검증오류를 피할 수 있다.
DB 서버와 별도로 존재하는 웹 서버에서 DB 서버로 SSL 통신을 할 때 웹 서버에 적용
접속하고자 하는 DB 서버와 별도의 리눅스 환경에서 mysql 클라이언트 프로그램으로 DB 서버에 접속할 때 클라이언트에 적용
Replication 에서 Master와 Slave 간의 SSL 통신을 하고자 할 때 Slave 서버에 적용
1 2 3 4 5 6 7 8 9
(SERVER) $ sudo openssl req -newkey rsa:2048 -days 365000 -nodes -keyout client-key.pem -out client-req.pem Country Name (2 letter code) [AU]:KR State or Province Name (full name) [Some-State]:Seoul Locality Name (eg, city) []: Organization Name (eg, company) [Internet Widgits Pty Ltd]: Organizational Unit Name (eg, section) []: Common Name (e.g. server FQDN or YOUR name) []::mysql-client.thinkbee.kr
(SERVER) $ sudo openssl x509 -req -in client-req.pem -days 365000 -CA ca.pem -CAkey ca-key.pem -set_serial 01 -out client-cert.pem Signature ok subject=C = KR, ST = Seoul, O = Internet Widgits Pty Ltd, CN = client-thinkbee.kr Getting CA Private Key
1 2
(SERVER) $ sudo openssl verify -CAfile ca.pem client-cert.pem client-cert.pem: OK
현재 디렉토리를 접근 권한을 조정한다.
1 2 3 4 5 6 7 8 9 10
(SERVER) $ sudo chown mysql.mysql *.* (SERVER) $ ls -l -rw-r--r-- 1 mysql mysql 3243 7월 16 15:43 ca-key.pem -rw-r--r-- 1 mysql mysql 1984 7월 16 15:46 ca.pem -rw-r--r-- 1 mysql mysql 1497 7월 16 15:51 client-cert.pem -rw-r--r-- 1 mysql mysql 1679 7월 16 15:51 client-key.pem -rw-r--r-- 1 mysql mysql 989 7월 16 15:50 client-req.pem -rw-r--r-- 1 mysql mysql 1838 7월 16 15:48 server-cert.pem -rw------- 1 mysql mysql 3243 7월 16 15:48 server-key.pem -rw-r--r-- 1 mysql mysql 1671 7월 16 15:47 server-req.pem
MariaDB [(none)]> status -------------- mysql Ver 15.1 Distrib 10.11.2-MariaDB, for debian-linux-gnu (aarch64) using EditLine wrapper
Connection id: 315 Current database: Current user: root@localhost SSL: Cipher in use is TLS_AES_256_GCM_SHA384 Current pager: stdout Using outfile: '' Using delimiter: ; Server: MariaDB Server version: 10.11.2-MariaDB-1:10.11.2+maria~deb11 mariadb.org binary distribution Protocol version: 10 Connection: Localhost via UNIX socket Server characterset: utf8mb4 Db characterset: utf8mb4 Client characterset: utf8mb3 Conn. characterset: utf8mb3 UNIX socket: /run/mysqld/mysqld.sock Uptime: 6 min 54 sec
Threads: 69 Questions: 2386 Slow queries: 0 Opens: 37 Open tables: 30 Queries per second avg: 5.763 --------------