💡 본 내용은 Real MySQL 8.0 1권을 읽으면서 정리한 내용입니다.
응용 프로그램의 암호화는 주요 정보를 가진 칼럼 단위로 암호화를 수행하며, 데이터베이스 수준에서는 테이블 단위로 암호화를 적용한다.
데이터베이스 서버와 디스크 사이의 데이터 읽고 쓰기 지점에서 암호화 또는 복호화를 수행한다.
그래서 디스크 입출력 이외의 부분에서는 암호화 처리가 필요 없다.
즉, InnoDB 스토리지 엔진의 I/O 레이어에서만 데이터 암호화 및 복호화 과정이 실행된다.

이러한 암호화 방식을 TDE(Transparent Data Encryption, 투명한 데이터 암호화)이라고 함
MySQL 서버의 TDE에서 암호화 키는 키링(KeyRing) 플러그인에 의해 관리된다.
위와 같은 다양한 플러그인이 제공되지만, 마스터 키를 사용하는 방법만 다를 뿐 MySQL 서버 내부적으로 작동하는 방식은 모두 동일하다.
키링 플러그인은 2단계(2-Tier) 키 관리 방식을 사용함

2단계 암호화 아키텍처 사진이다.
데이터 암호화는 마스터 키와 테이블스페이스 키를 가지고 있다.
테이블스페이스 키는 테이블이 삭제되지 않는 이상 절대 변경되지 않는다.
마스터 키는 외부로 노출될 수 있기 때문에 주기적으로 변경해야 한다.
ALTER INSTANCE ROTATE INNODB MASTER KEY;MySQL 서버의 암호화는 TDE 방식 ⇒ 디스크로부터 한 번 읽은 데이터 페이지는 복호화되어 InnoDB 버퍼 풀에 적재된다.
InnoDB 버퍼 풀에 존재하지 않는 데이터를 읽을 경우
암호화된 테이블이 변경되는 경우
SELECT, UPDATE, DELETE 명령을 실행하는 경우
암호화한다고 해서 InnoDB 버퍼 풀의 효율이 달라지거나 메모리 사용 효율이 떨어지는 현상은 발생하지 않는다.
같은 테이블에 대해 암호화와 압축이 동시에 적용되면 압축을 먼저 실행하고 암호화를 적용함
암호화된 테이블의 경우 읽기는 3~5배, 쓰기는 5~6배정도 느림
MySQL 서버의 복제에서 레플리카 서버는 소스 서버의 모든 사용자 데이터를 동기화하기 때문에 실제 데이터 파일도 동리할 것이라 생각할 수 있다.
하지만, TDE를 이용한 암호화 사용 시 -> 마스터 키와 데이블스페이스 키는 그렇지 않다.
MySQL 서버에서 기본적으로 모든 노드는 각자의 마스터 키를 할당해야 한다.
DB 서버의 로컬 디렉터리에 마스터 키를 관리할 때는 두 서버가 다른 키를 가질 수밖에 없겠지만, 원격으로 키 관리 솔루션을 사용하는 경우에도 두 서버는 서로 다른 마스터 키를 갖도록 해야 한다.
=> 애초에 마스터 키 자체가 레플리카로 복제되지 않아 테이블 스페이스 키도 복제되지 않는다.
즉, 소스 서버와 레플리카 서버는 서로 각자의 마스터 키와 테이블스페이스 키를 관리한다.
그래서 실제 암호화된 데이터가 저장된 데이터 파일의 내용은 완전히 달라진다.
복제 소스 서버의 마스터 키를 변경할 때는
ALTER INSTANCE ROTATE INNODB MASTER KEY
위의 명령을 실행하는데, 이 때 이 명령 자체는 레플리카 서버로 복제되지만, 실제로 전달되는 것은 아니다.
마스터 키 로테이션을 실행하면 소스 서버와 레플리카 서버가 각각 서로 다른 마스터 키를 새로 발급받는다.
MySQL 서버의 백업에서 TDE의 키링 파일을 백업하지 않는 경우가 있다. => 이 경우 키링 파일을 찾지 못하면 데이터 복구가 불가능해진다.
만약, 키링 파일과 데이터 백업을 별도로 백업한다면, 마스터 키 로테이션 명령으로 TDE의 마스터 키가 언제 변경됐는지 기억해둬야 한다.
물론 보안을 위해 별도로 보관하는 것을 권장하긴 한다. 그럼에도 복구를 감안하고 백업 방식을 선택해야 한다.
TDE의 암호화 키 관리는 플러그인 방식으로 제공된다.
keyring_file 플러그인은 테이블스페이스 키를 암호화하기 위해 마스터 키를 디스크 파일로 관리함
TDE 플러그인은 가장 빨리 초기화돼야 하므로 MySQL 서버의 설정 파일(my.cnf)에 다음을 추가하면 된다.
early-plugin-load = keyring_file.sokeyring_file_data = /very/secure/directory/tde_master.keySHOW PLUGINS 명령으로 keyring_file 플러그인의 초기화 여부 확인 가능
키링 플러그인은 마스터 키를 생성하고 관리하는 부분까지만 담당한다.
따라서 어떤 키링 플러그인을 사용하든지 암호화된 테이블을 생성하고 활용하는 방법은 모두 동일하다.
ENCRYPTION='Y' 옵션만 넣으면 됨
mysql> CREATE TABLE tab_encrypted (
id INT,
data VARCHAR(100),
PRIMARY KEY(id)
) ENCRYPTION='Y';
모든 테이블에 암호화를 적용하려면 default_table_encryptioni 시스템 변수를 ON으로 설정하면 됨
응용 프로그램에서 직접 암호화해서 MySQL 서버에 저장하는 경우도 있다.
이 경우에는 아래와 같이 될 수 있다.
1. 칼럼 값의 암호화 여부를 서버가 인지하지 못한다.
2. 암호화된 칼럼은 인덱스의 기능을 100% 활용하지 못한다.
3. 암호회된 칼럼을 기준으로 정렬하는 쿼리를 사용하지 못한다.
3 - 1.MySQL 서버는 이미 암호화된 값을 기준으로 정렬한다. 그래서 암호화 되기 전의 값을 기준으로 정렬할 수 없다.
즉, 고민할 필요 없이 MySQL 서버의 암호화 기능을 선택할것을 권장한다.
FLUSTH TABLES 명령으로 테이블스페이스 Export 가능
mysql> FLUSH TABLES source_table FOR EXPORT;
FLUSTH TABLES 명령 실행source_table.cfg 파일로 기록source_table.cfg 파일을 목적지 서버로 복사FLUSTH TABLES 명령 실행source_table.cfp 파일로 기록한다.source_table.cfp 파일을 목적지 서버로 복사한다.MySQL 8.0.16 버전부터 innodb_undo_log_encrypt, innodb_redo_log_encrypt 시스템 변수를 이용해 InnoDB 스토리지 엔진의 리두 로그와 언두 로그를 암호화된 상태로 저장할 수 있다.
테이블의 암호화는 일단 테이블 하나에 암호화가 적용되면 해당 테이블의 모든 데이터가 암호화돼야 한다.
하지만 리두 로그나 언두 로그는 그렇게 적용할 수 없다.
즉, 실행 중인 MySQL 서버에서 언두 로그나 리두 로그를 활성화한다고 해도, 모든 리두 로그나 언두 로그의 데이터를 해당 시점에 한 번에 암호화해서 다시 저장할 수 없다.
그래서 아래와 같은 경우들이 있다.
즉, 리두 로그와 언두 로그를 위한 각각의 프라이빗 키가 발급되고, 해당 프라이빗 키는 마스터 키로 암호화되어 리두 로그 파일과 언두 로그 파일의 헤더에 저장됨
InnoDB 리두 로그의 암호화 여부 확인 방법
mysql> SHOW GLOBAL VARIABLES LIKE 'innodb_redo_log_encrypt';
+-------------------------+-------+
| Variable_name | Value |
+-------------------------+-------+
| innodb_redo_log_encrypt | OFF |
바이너리 로그 파일의 암호화는 상황에 따라 중요도가 높아질 수 있다.
바이너리 로그와 릴레이 로그 파일 데이터의 암호화를 위해 2단계 암호화 키 관리 방식을 사용한다.

파일 키로 로그 파일의 데이터를 암호화해서 디스크에 ㅓ장한다.
ALTER INSTANCE ROTATE BINLOG MASTER KEY 명령으로 바이너리 암호화 키를 변경할 수 있다.
MySQL 서버의 바이너리 로그 파일이 암호화돼 있는지 여부 확인 방법
mysql> SHOW BINARY LOGS;
바이너리 로그 파일이 한 번 암호화되면 바이너리 로그 암호화 키가 없으면 복호화할 수 없다.
근데, 암호화 키는 MySQL 서버만 갖고 있어서 복호화가 불가능하다..
mysqlbinlog를 활용해서 MySQL 서버에 접속해서 바이너리 로그를 가져오는 방법밖에 없다.
linux> mysqlbinlog --read-from-remote-server -uroot -p -vvv mysql-bin.000011
mysql-bin.000011 로그 파일을 가지고 있다는 가정하에 mysql-bin.000011 로그 파일의 내용을 확인하고자 한다면, 위와 같이 하는 수밖에 없다.
mysqlbinlog 도구가 mysql-bin.000011 파일을 읽는 것은 아니기 때문에 --read-from 파라미터가 필요하다.