$ 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 --------------
mysql >createuser foo@localhost identified by'password'; mysql >createuser'foo'@'%' identified by'password';
혹은
1
insert into user (host, user, password) values ('localhost', 'hiru', 'password('hirururu'));
사용자 제거 mysql > drop user ‘hiru’; mysql > delete from user where user =’hiru’
사용자 생성시 다음같이 1396 에러는 CREATE USER/GRANT 명령으로 사용자와 권한을 추가/관리해야 하는데 mysql.db, mysql.user 테이블을 직접 조작하다가 일관성이 깨졌기 때문
1 2
mysql> create user 'shopuser'@'localhost' identified by ')12345'; ERROR 1396 (HY000): Operation CREATE USER failed for 'shopuser'@'localhost'
제대로 사용자를 삭제하고
drop user shopuser@localhost
flush privileges; 로 갱신해 준다.
권한 주기
권한을 추가하고 삭제하기 위해서, GRANT와 REVOKE의 명령을 사용한다. GRANT 명령 등으로 데이터베이스 사용자가 데이터베이스 자원에 접근하는 권한을 만들 수 있다.
GRANT ALL privileges ON DB_NAME.TABLE TO USER_ID@[HOST] IDENTIFIED BY ‘PASSWORD’ GRANT [SELECT,DELETE,INSERT,UPDATE,] ON DB_NAME.TABLE TO USER_ID@[HOST] IDENTIFIED BY ‘PASSWORD’
현재 머신에서만 접속할 수 있는 사용자 계정, 외부, 원격에서 접속할 수 있는 사용자 계정을 추가해 준다.
1 2 3
mysql> use mysql; # mysql system db mysql>GRANTALL privileges ON mydb.*TO foo@localhost IDENTIFIED BY'*****'; mysql>GRANTALL privileges ON mydb.*TO foo@'%' IDENTIFIED BY'*****';
혹은
1 2
grant select, insert, update, delete on mydb.* to foo@host identified by 'password'; mysql > grant select, insert, update, delete on dbname.table to userid@'192.168.%' identified by 'password';
권한을 확인하는 방법
1 2
mysql >show grants for foo@localhost mysql >show grants for'foo'@'%';
변경된 권한을 적용하기
1
mysql > flush privileges;
권한을 삭제하는 방법
1
mysql > revoke all on dbname.table from username@host
추가한 사용자는 SELECT로 확인할 수 있다.
1
mysql> select host,authentication_string from user where user='foo';
studnets.txt 파일을 읽어들이는 것은 스크립트 파일을 작성하거나 mysql에서 직접 실행할 수 있다. 먼저 스크립트 파일 students.sql은 다음과 같다.
1 2 3
use mydb; load data local infile "student.txt" intotable student fields terminated by',' ;
이제 mysql 클라이언트에서 데이터를 읽어 들인다.
1 2
mysql>source students.sql;
데이터 조회
SELECT [DISTINCT] select _expr essi on FROM table_list WHERE where_definition ORDER BY col_name [ASC|DESC] GROUP BY col _name_list LIMIT [offset ], rows
예제-1) 전체 교수 리스트를 출력하는 SQL 검색 문을 작성하라. mysql > sel ect * fromprof;
예제-2) 전체 교수 리스트를 이름순서로 출력하는 검색 문을 작성하라. mysql > sel ect * fromprof order by pname;
예제-5) 전체 교수 리스트를 이름 역순으로 출력하는 검색 문을 작성하라. mysql > sel ect * fromprof order by pname desc;
전체 교수 리스트를 학과별로 출력하는 검색 문을 작성하라. mysql > sel ect * fromprof order by pdept, pname;
예제-4) 국문학과 교수 리스트를 이름순서로 출력하는 검색 문을 작성하라. mysql> select * from professor where pdept =’국문학과’;
JOIN
“FROM 테이블명 AS 별명” 구문은 SQL 문장에서 별명으로 테이블을 참조하 는 역할은 한다.
예제-6) MySQL 과목을 강의하는 교수님의 이름, 전화번호와 강의실을 검색 하는 문장을 작성하라. mysql> select p.pname, p.pphone, c.croom from professor p, course c, lecture l where c.cname=’MySQL’ and c.ccode=l.lccode and l.lpcode=p.pcode;
예제-7) ‘김구’ 교수님이 강의하는 과목명, 강의 시수와 강의실을 검색하는 문장을 작성하라.
1 2 3 4
select c.cname, c.ctime, c.croom from professor as p, course as c, lecture as l where p.pname ='김 구'and p.pcode = l.lpcode and l.lccode = c.ccode;
예제-8) 각 학생이 수강 신청한 과목에 대해서 학생이름, 전화번호, 과목명, 강의실, 강의 시수를 검색하는 문장을 작성하라.
1 2 3 4
select s.sname, s.sphone, c.cname, c.ctime, c.croom from student as s , course as c, register as r where s.scode = r.rscode and r.rccode = c.ccode orderby s.sname, c.cname;
sub-query
예제-9) 각 학생이 신청한 총 학점을 구하는 검색식을 작성하라.
1 2 3 4
select s.sname, s.sdept, s.sphone, sum(c.ctime) from student as s , course as c, register as r where s.scode = r.rscode and r.rccode = c.ccode groupby s.sname;
WHERE 조건절에 해당하는 결과를 GROUP BY 구절에 명시된 s.sname 필드에 따라 그룹으로 결과를 분류하고 난 후, SELECT 필드에 SUM(c.cti me) 함수를 사용해서 c.cti me 필드에 대한 합을 구함으로써 각 학 생이 신청한 총 학점를 구할 수 있다.
예제-10) 각 학과별 교수님은 몇 분인지 구하는 검색식을 작성하라.
1 2 3
select pdept, count(*) from professor groupby pdept;
LIMIT 구절
예제-11) 페이지 크기가 2 일 때, (예제-8)의 결과에서 두 번째 페이지를 검색하는 SQL문장은 작성하라. select s.sname, s.sphone, c.cname, c.ctime, c.croom fromstudent as s , course as c, regi ster as r where s.scode = r.rscode and r.rccode = c.ccode order by s.sname, c.cname limit 2, 2;
마지막 행의 limit 2, 2구절에서, 첫 번째 인자는 오프셋(offset)으로 검 색 결과 레코드들의 순번을 의미한다. 오프셋 값은 0 부터 지정하기 때문에 오프셋값2는전체레코드중에서세번째레코드를가리킨다. 두번째는 인자는 출력하는 레코드 수(rows)를 의미한다. 따라서, 레코드 수 2 는 2 개 의 레코드를 출력하라는 의미가 된다.
예제-12) 교수테이블에서 ‘김 구’ 선생님의 이름을 ‘하은용’ 교수님으로 변 경하는 문장을 작성하라. update prof set pname =’하은용’ where pname =’김구’;
예제-13) 지도 테이블의 교수코드가 ‘P007’ 인 레코드들을 모두 ‘P005’ 로 변경하라. update advise set apcode =’P005’ where apcode =’P007’;
예제-14) 강의 시수가 2인 과목들의 강의 시수를 하나 증가 시키고, 강의실 을 Lab1로 변경하라. update course set ctime=ctime + 1, croom=’Lab1’ where ctime=2;
Delete
DELETE FROM tbl_name [WHERE where_definition] [LIMIT rows]
예제-15 ) 국문학과 학생 레코드를 삭제하는 문장을 작성하라. delete fromstudent where sdept =’국문학과’;
PyMySQL 튜토리얼
PyMySQL 설치
1
$ pip install PyMySQL
만약 pip 로 설치가 안되면 다음 같이 setup.py를 이용해 직접 설치 할 수 있다. $ # X.X is the desired PyMySQL version (e.g. 0.5 or 0.6). $ curl -L https://github.com/PyMySQL/PyMySQL/tarball/pymysql-X.X | tar xz $ cd PyMySQL* $ python setup.py install $ # The folder PyMySQL* can be safely removed now.
mysql 설치작업이 끝나면 데몬을 구동하기 위한 초기화 작업이 필요하다. 다음과 같이 작업이 완료되면 최초 설치 작업은 마무리 된다.
mysql 환경설정 기본 파일 복사
1
$ cp ./support-files/my-default.cnf /etc/my.cnf
mysql 초기화
1 2
$ cd /usr/local/mysql $ /usr/local/mysql/scripts/mysql_install_db –user=mysql
mysql 서비스 스크립트 및 서비스 설정
Mysql 설정이 완료되면 부가적으로 서비스의 스크립트와, 부팅 시 자동으로 서비스가 올라오도록 아래와 같은 기본 설정을 추가한다.
mysql 서비스 스크립트 및 서비스 runlevel 등재
1 2
$ cd /usr/local/mysql $ cp -a support-files/mysql.server /etc/init.d/mysqld # ln -s /etc/init.d/mysqld /etc/rc3.d/S90mysqld
Start
mysql-server 를 설치하며 만든 root 사용자 패스워드를 사용해서 데이터베이스에 접속한다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
$ mysql -u root -p Enter password: Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 1 Server version: 5.6.26 MySQL Community Server (GPL)
Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
mysql> show databases; +--------------------+ | Database | +--------------------+ | information_schema | | mysql | | performance_schema | +--------------------+ 3 rows in set (0.00 sec)
# 현재 머신에서만 접속할 수 있는 사용자 계정 mysql>GRANTALL privileges ON*.*TO ID@localhost IDENTIFIED BY'*****'; # 외부, 원격에서 접속할 수 있는 사용자 계정 mysql>GRANTALL privileges ON*.*TO ID@'%' IDENTIFIED BY'*****';
localhost 머신의 MySQL 데이터베이스에 myid라는 이름의 아이디를 만들고, 패스워드는 password로 설정
사용자 데이터베이스 사용
새로 생성한 사용자 ID로 로그인을 해서 데이터베이스를 만든다.
1 2 3
root@a5d2a69fa410:/# mysql -u qkboo -p Enter password: Welcome to the MySQL monitor. Commands end with ; or \\g.