한줄 정리
쓰지 않을 이유가 없는 것 같다. 그러나 시스템의 규모가 어느정도 커졌을 때, DBA가 있을때, 개인정보를 많이 다룰 때? 사용하는 것이 좋아보인다.
MySQL 서버의 데이터 암호화
MySQL 서버의 암호화 기능은 데이터베이스 서버와 디스크 사이의 데이터 읽고 쓰기 지점에서 암호화 또는 복호화를 한다. 그래서 MySQL 서버에서 디스크 입출력 이외의 부분에서는 암호화 처리가 전혀 필요하지 않다. 즉, MySQL 서버의 I/O 레이어에서만 데이터의 암호화 및 복호화 과정이 실행되는 것이다.
사용자 쿼리를 처리하는 과정에서 테이블의 데이터 암호화돼 있는지 여부를 식별할 필요가 없으며, 암호화된 테이블도 그렇지 않은 테이블과 동일한 처리 과정을 거친다. 데이터 암호화 기능이 활정화돼 있다고 하더라도 MySQL 내부 사용자와 사용자 입장에서는 아무런 차이가 없기 때문에 이러한 암호화 방식을 TDE (Transparent Data Encryption)이라고 한다.
키 관리
MySQL 서버의 TDE에서 암호화 키는 키링(KeyRing) 플러그인에 의해 관리된다. 다양한 플러그인이 제공되지만 마스터 키를 관리하는 방법만 다를 뿐 MySQL 서버 내부적으로 작동하는 방식은 모두 동일하다.
데이터 암호화는 마스터 키와 테이블스페이스 키라는 두 가지 종류의 키를 가지고 있는데, 테이블스페이스 키는 프라이빗 키라고도 한다.
MySQL은 외부 키관리솔루션(KMS) 또는 디스크의 파일에서 마스터 키를 가져오고, 암호화된 테이블이 생성될 때마다 해당 테이블을 위한 임의의 테이블 스페이스 키를 발급한다. MySQL 서버는 마스터 키를 이용해 테이블스페이스 키를 암호화해서 각 테이블의 데이터 파일 헤더에 저장한다. 이렇게 생성된 테이블스페이스 키는 테이블이 삭제되지 않는 이상 절대 변경되지 않는다.
하지만, 테이블스페이스 키는 절대 MySQL 서버 외부로 노출되지 않기 때문에 테이블스페이스 키를 주기적으로 변경하지 않아도 보안상 취약점은 되지 않는다.
하지만, 마스터 키는 외부에 있는 것을 이용하기 때문에 노출될 가능성이 있다. 그래서 마스터 키는 주기적으로 변경해야 한다.
1
ALTER INSTANCE ROTATE INNODB MASTER KEY;
마스터 키를 변경하면 MySQL 서버는 기존의 마스터 키를 이용해 각 테이블의 테이블스페이스 키를 복호화한 다음에 새로운 마스터 키로 다시 암호화 한다. 마스터 키가 변경되는 동안 MySQL 서버의 테이블스페이스 키 자체와 데이터 파일의 데이터는 전혀 변경되지 않는다.
이렇게 2단계 암호화 방식을 사용하는 이유는 키 변경으로 인해 과도한 부하를 피하기 위해서다. (테이블스페이스 키가 변경되면 모든 데이터가 복호화 → 암호화 해야하기 때문에)
MySQL에서 지원되는 암호화 알고리즘은 AES-256이다. 테이블스페이스 키는 AES-256 ECB 알고리즘을 이용해 암호화 되고, 실제 데이터 파일은 AES-256 CBC 알고리즘을 이용해 암호화된다.
암호화 성능
결론적으로 말하면 체감하기 힘들다.
디스크로부터 한 번 읽은 데이터 페이지는 복호화되어 InnoDB 버퍼 풀에 적재된다. 그래서 데이터 페이지가 한 번 메모리에 적재되면 암호화되지 않은 테이블과 동일한 성능을 보인다. 하지만 쿼리가 InnoDB 버퍼 풀에 없는 데이터 페이지를 읽어야 하는 경우에는 복호화 과정을 거치기 때문에 복호화 시간 동안 쿼리 처리가 지연될 것이다. 그리고 암호화된 테이블이 변경되면 다시 디스크로 동기화될 때 암호화돼야 하기 때문에 디스크에 저장할 때도 추가로 시간이 더 걸린다.
하지만 데이터 페이지 저장은 사용자 쿼리를 처리하는 스레드가 아닌 MySQL 서버의 백그라운드 스레드가 수행하기 때문에 실제 사용자의 쿼리가 지연되는 것은 아니다. SELECT, UPDATE, DELETE 명령 또한 변경하고자 하는 레코드를 InnoDB 버퍼 풀로 읽어와야 하기 때문에 새롭게 디스크에서 읽어야 하는 데이터 페이지의 개수에 따라 그만큼 복호화 지연이 발생한다.
AES 암호화 알고리즘은 암호화하고자 하는 평문의 길이가 짧은 경우 암호화 키의 크기에 따라 암호화된 결과의 용량이 커질 수도 있지만, 이미 데이터 페이지는 암호화 키보다 훨씬 크기 때문에 암호화 결과가 평문의 결과와 동일한 크기의 암호문을 반환한다. 그래서 TDE를 적용한다고 해도 데이터 파일의 크기는 암호화되지 않은 테이블과 동일한 크기를 가진다. 즉, 암호화 한다고 해서 InnoDB 버퍼 풀의 효율이 달라지거나 메모리 사용 효율이 떨어지는 현상은 발생하지 않는다.
같은 테이블에 대해 암호화와 압축이 동시에 적용되면 압축을 먼저 실행하고 암호화를 적용한다. 이유는 199 Page 참고
암호화된 테이블의 읽고 쓰기 성능을 직접 확인해보고자 한다면 다음 쿼리 사용
1
2
3
4
SELECT (SUM(SUM_TIMER_READ) / SUM(COUNT_READ))/1000000000 as avg_read_latency_ms,
(SUM(SUM_TIMER_WRITE) / SUM(COUNT_WRITE))/1000000000 as avg_write_latency_ms,
FROM performance_schema.file_summary_by_instance
WHERE file_name LIKE '%DB_NAME/TABLE_NAME%';
암호화와 복제
MySQL 서버의 복제에서 레플리카 서버는 소스 서버의 모든 사용자 데이터를 동기화하기 때문에 실제 데이터 파일도 동일할 것이라 생각할 수 있다. 하지만 TDE를 이용한 암호화 사용 시 마스터 키와 테이블스페이스 키는 그렇지 않다. MySQL 서버에서 기본적으로 모든 노드는 각자의 마스터 키를 할당해야 한다. 데이터베이스 서버의 로컬 디렉터리에 마스터 키를 관리하는 경우에는 소스 서버와 레플리카 서버가 다른 키를 가질 수 밖에 없겠지만 원격으로 키관리솔루션을 사용하는 경우에도 소스 서버와 레플리카 서버는 다른 키를 갖도록 설정해야 한다. 마스터 키 자체가 레플리카로 복제되지 않기 때문에 테이블스페이스 키 또한 레플리카로 복제되지 않는다.
결국 소스 서버와 레플리카 서버는 서로 각자의 마스터 키와 테이블스페이스 키를 관리하기 때문에 복제 멤버들의 데이터 파일은 암호화되기 전의 값이 동일하더라도 실제 암호화된 데이터가 저장된 데이터 파일의 내용은 완전히 달라진다.
복제 소스 서버의 마스터 키를 변경할 때는 ALTER INSTANCE ROTATE INNODB MASTER KEY 명령을 실행하는데, 이 때 ALTER INSTANCE ROTATE INNODB MASTER KEY 명령 자체는 레플리카 서버로 복제되지만 실제 소스 서버의 마스터 키 자체가 레플리카 서버로 전달되는 것은 아니다.
그래서 마스터키 로테이션을 실행하면 소스 서버와 레플리카 서버가 각각 서로 다른 마스터 키를 새로 발급 받는다. MySQL 서버의 백업에서 TDE의 키링(KeyRing) 파일을 백업하지 않은 경우가 있는데, 이 경우 키링 파일을 찾기 못하면 데이터 복구를 할 수 없게 된다. 키링 파일을 데이터 백업과 별도로 백업한다면 마스터 키 로테이션 명령으로 TDE의 마스터 키가 언제 변경됐는지까지 기억하고 있어야 한다.
물론, 보안을 위해 키링 파일을 데이터 파일과 별도로 보관하는 것을 권장하지만 복구를 감안하고 백업 방식을 선택해야 한다. 이미 언급한 바와 같이 마스터 키도 계속 변경될 수 있기 때문에 백업마다 키링 파일의 백업도 같이 고려하자.
TDE 플러그인
다른 플러그인과 달리 서버가 올라갈 때, 가장 빠르게 초기화되어야 하기 때문에 my.cnf 파일에 아래와 같이 명시해야한다.
1
2
early-plugin-load = keyring_file.so
keyring_file_date = /very/secure/directory/tde_master.key
초기화 여부 확인
1
SHOW PLUGINS;
테이블 암호화
1
2
3
4
5
6
7
8
9
10
11
12
-- TDE를 이용하는 테이블 생성
CREATE TABLE tab_encrypted (
id INT,
data VARCHAR(100),
PRIMARY KEY(id)
) ENCRYPTION = 'Y';
-- 암호화된 테이블 조회
SELECT table_schema, table_name, create_options
FROM information_schema.tables
WHERE table_name='tab_encrypted'
TDE 사용하였을 때 인덱스 관련 작업을 모두 처리한 후 최종 디스크에 데이터 페이지를 저장할 때만 암호화한다.
테이블스페이스 이동
TDE 적용되지 않은 테이블스페이스
1
FLUSH TABLES source_table FOR EXPORT;
source_table 저장되지 않은 것을 모두 기록하고 변경하지 못하도록 잠근다. 이와 동시에 source_table 구조를 source_table.cfg 파일로 기록해둔다. 그러면 source_table.ibd 파일과 source_table.cfg 파일을 목적지 서버로 복사한다. 복사가 모두 완료되면 UNLOCK TABLES 명령을 실행해 source_table을 사용할 수 있게 하면 된다.
TDE 적용 테이블스페이스
1
FLUSH TABLES source_table FOR EXPORT;
source_table 저장되지 않은 것을 모두 기록하고 변경하지 못하도록 잠근다. source_table.cfp 파일에 임시로 사용할 마스터 키를 기록한다. 그리고 기존 암호화된 테이블 스페이스의 테이블 스페이스 키를 기존 마스터 키로 복호화한 후, 임시로 발급한 마스터 키를 이용해 다시 암호화해서 데이터 파일의 헤더 부분에 저장한다. 이와 동시에 source_table 구조를 source_table.cfg 파일로 기록해둔다. 그러면 source_table.ibd 파일과 source_table.cfg 파일을 목적지 서버로 복사한다. 이때 꼭 .cfp 파일도 함께 복사해야 한다. 복사가 모두 완료되면 UNLOCK TABLES 명령을 실행해 source_table을 사용할 수 있게 하면 된다.
Undo Log & Redo Log Encryption
- 테이블의 암호화를 적용하더라도 디스크로 저장되는 데이터만 암호화되고 MySQL 서버의 메모리에 존재하는 데이터는 복호화된 평문으로 관리되며, 이 평문 데이터가 테이블의 데이터 파일 이외의 디스크 파일로 기록되는 경우에는 여전히 평문으로 저장된다. MySQL 8.0.16 버전부터는 innodb_undo_log_encrypt 와 innodb_redo_log_encrypt 시스템 변수를 이용해 InnoDB 스토리지 엔진의 리두 로그와 언두 로그를 암호화된 상태로 저장할 수 있게 개선됐다.
- 설정을 on/off 시점부터 암호화, 평문 처리되어 기록된다.
- 리두로그와 언두로그 모두 각각의 테이블스페이스 키로 암호화되고, 테이블스페이스 키는 다시 마스터 키로 암호화된다. 즉, ALTER INSTANCE ROTATE INNODB MASTER KEY 명령이 실행되면 새로운 마스터 키가 발급되고 테이블 암호화에 사용된 테이블스페이스 키가 사용된다고 했는데, 여기서 이야기한 테이블스페이스 키는 실제 테이블의 암호화에 사용된 테이블스페이스 키가 아니라 리두 로그와 언두 로그 파일을 위한 프라이빗 키를 의미한다. 즉, 리두 로그와 언두 로그를 위한 각각의 프라이빗 키가 발급되고 해당 프라이빗 키는 마스터 키로 암호화되어 리두 로그 파일과 언두 로그 파일의 헤더에 저장되는 것이다.
- SHOW GLOBAL VARIABLES LIKE ‘innodb_redo_log_encrypt’; 로 암호화 설정 확인 가능.
Binary Log Encryption
- 리두 로그와 언두 로그와 같이 따로 설정을 해주어야 암호화가 된다.
- 바이너리 로그와 릴레이 로그 파일 암호화 기능은 디스크에 저장된 로그 파일에 대한 암호화만 담당하고, MySQL 서버의 메모리 내부 또는 소스 서버와 레플리카 서버 간의 네트워크 구간에서 로그 데이터를 암호화하지는 않는다. 복제 멤버 간의 네트워크 구간에서도 바이너리 로그를 암호화하고자 한다면 MySQL 복제를 위한 계정이 SSL을 사용하도록 설정하면 된다. 복제 시 네트워크 구간으로 전송되는 데이터의 암호화에 대해서는 3장 참조.
- 바이너리 로그 암호화 키 변경 ALTER INSTANCE ROTATE BINLOG MASTER KEY;
- SHOW BINARY LOG;
mysqlbinlog 도구 활용
- 211 페이지
