데이터 암호화
- MySQL 5.7 버전부터 데이터 암호화 기능이 지원됐다.
- 처음에는 데이터 파일(테이블스페이스)에 대해서만 암호화 기능이 제공됐다.
- MySQL 8.0으로 업그레이드되면서 데이터 파일뿐만 아니라 리두 로그나 언두 로그, 복제를 위한 바이너리 로그 등도 모두 암호화 기능을 지원하기 시작했다.
- 응용 프로그램의 암호화는 주로 중요 정보를 가진 칼럼 단위로 암호화를 수행한다.
- 중요한 정보를 저장하는 서비스에서는 응용 프로그램에서 암호화한 데이터를 데이터베이스 서버에서 다시 암호화하는 이중 암호화 방법을 선택하기도 한다.
- 데이터베이스 수준에서는 테이블 단위로 암호화를 적용한다.
MySQL 서버의 데이터 암호화
- MySQL 서버의 암호화 기능은 데이터베이스 서버와 디스크 사이의 데이터 읽고 쓰기 지점에서 암호화 또는 복호화를 수행한다.
- MySQL 서버에서 디스크 입출력 이외의 부분에서는 암호화 처리가 전혀 필요치 않다.
- 즉, MySQL 서버(InnoDB 스토리지 엔진)의 I/O 레이어에서만 데이터의 암호화 및 복호화 과정이 실행되는 것이다.
TDE (Transparent Data Encryption)
- MySQL 서버에서 사용자의 쿼리를 처리하는 과정에서 테이블의 데이터가 암호화돼 있는지 여부를 식별할 필요가 없다.
- 암호화된 테이블도 그렇지 않은 테이블과 동일한 처리 과정을 거친다.
- 데이터 암호화 기능이 활성돼 있더라도 MySQL 내부와 사용자 입장에서는 아무런 차이가 없기 때문에 이러한 암호화 방식을 가리켜 “TDE” 혹은 “Data at Rest Encryption”이라고 한다.
- 여기서 “Data at Rest”는 메모리(In-Process)나 네트워크 전송(In-Transit) 단계가 아닌 디스크에 저장(At Rest)된 단계에서만 암호화된다는 의미로 사용되는 표현이다.
- MySQL 매뉴얼에서는 TDE라는 표현을 사용한다.
2단계 키 관리
- MySQL 서버의 TDE에서 암호화 키는 키링(KeyRing) 플러그인에 의해 관리된다.
- MySQL 8.0 버전에서 지원되는 키링 플러그인은 다음과 같다.
keyring_file
File-Based 플러그인
keyring_encrypted_file
Keyring 플러그인
keyring_okv
KMIP 플러그인
keyring_aws
Amazon Web Services Keyring 플러그인
- 이 중에 MySQL 커뮤니티 에디션에서는
keyring_file
플러그인만 사용 가능하다.
- 다양한 플러그인이 제공되지만 마스터 키를 관리하는 방법만 다를 뿐 MySQL 서버 내부적으로 작동하는 방식은 모두 동일하다.
- MySQL 서버의 키링 플러그인은 2단계(2-Tier) 키 관리 방식을 사용한다.
2단계 키 관리 동작 방식
- MySQL 서버의 데이터 암호화는 다음 두 가지 종류의 키를 가지고 있다.
- 마스터 키 (master key)
- 테이블스페이스 키 (tablespace key, private key)
- MySQL 서버는 외부 키 관리 솔루션(KMS, key Management Service) 또는 디스크의 파일(
keyring_file
또는 keyring_encrypted_file
플러그인 사용 시)에서 마스터 키를 가져온다.
- 예를 들어, HashiCorp Vault 같은 외부 키 관리 솔루션 사용
- 암호화된 테이블이 생성될 때마다 해당 테이블을 위한 임의의 테이블스페이스 키를 발급한다.
- MySQL 서버는 마스터 키를 이용해 테이블스페이스키를 암호화해서 각 테이블의 데이터 파일 헤더에 저장한다.
- 이렇게 생성된 테이블스페이스 키는 테이블이 삭제되지 않는 이상 절대 변경되지 않는다.
- 테이블스페이스 키는 절대 MySQL 서버 외부로 노출되지 않으므로, 주기적으로 변경하지 않아도 보안상 취약점이 되지는 않는다.
마스터 키 변경
2단계 암호화 방식을 사용하는 이유
- 암호화 키 변경으로 인한 과도한 시스템 부하를 피하기 위해서이다.
- 테이블스페이스 키가 변경된다면 MySQL 서버는 데이터 파일의 모든 데이터를 다시 복호화했다가 다시 암호화해야 한다.
- 이로 인해 키를 변경할 때마다 엄청난 작업을 해야 하며, 사용자 쿼리를 처리하는 데도 상당한 영향을 미치게 된다.
알고리즘
- MySQL 서버의 TDE에서 지원되는 암호화 알고리즘은 AES 256비트이다.
- 테이블스페이스 키는 AES-256 ECB (Electronic CodeBook) 알고리즘을 이용해 암호화된다.
- 실제 데이터 파일은 AES-256 CBC (Cipher Block Chaining) 알고리즘을 이용해 암호화된다.
암호화와 성능
복호화 지연
- MySQL 서버의 암호화는 TDE 방식이기 때문에 디스크로부터 한 번 읽은 데이터 페이지는 복호화되어 InnoDB의 버퍼 풀에 적재된다.
- 데이터 페이지가 한 번 메모리에 적재되면 암호화되지 않은 테이블과 동일한 성능을 보인다.
- 쿼리가 InnoDB 버퍼 풀에 존재하지 않는 데이터 페이지를 읽어야 하는 경우에는 복호화 과정을 거치기 때문에, 복호화 시간 동안 쿼리 처리가 지연될 것이다.
- SELECT, UPDATE, DELETE 명령은 변경하고자 하는 레코드를 InnoDB 버퍼 풀로 읽어와야 하기 때문에, 새롭게 디스크에서 읽어야 하는 데이터 페이지의 개수에 따라서 그만큼의 복호화 지연이 발생한다.
- 암호화된 테이블로 변경되면 다시 디스크로 동기화될 때 암호화돼야 하기 때문에 디스크에 저장할 때도 추가로 시간이 더 걸린다.
- 하지만 데이터 페이지 저장은 사용자의 쿼리를 처리하는 스레드가 아닌 MySQL 서버의 백그라운드 스레드가 수행하기 때문에 실제 사용자 쿼리가 지연되는 것은 아니다.
암호화 성능
- AES(Advanced Encryption Standard) 암호화 알고리즘은 암호화하고자 하는 평문의 길이가 짧은 경우 암호화 키의 크기에 따라 암호화된 결과의 용량이 더 커질 수 있다.
- 데이터 페이지는 이미 암호화 키보다 훨씬 크기 때문에 암호화 결과가 평문의 결과와 동일한 크기의 암호문을 반환한다.
- TDE를 적용한다고 해도 데이터 파일의 크기는 암호화되지 않은 테이블과 동일한 크기를 가진다.
- 즉, 암호화한다고 해서 InnoDB 버퍼 풀의 효율이 달라지거나 메모리 사용 효율이 떨어지는 현상은 발생하지 않는다.
암호화와 압축
- 같은 테이블에 대해 암호화와 압축이 동시에 적용되면, MySQL 서버는 압축을 먼저 실행하고 암호화를 적용한다.
압축이 먼저 실행되는 이유는 다음과 같다.
- 일반적으로 암호화된 결과물은 아주 랜덤한 바이트의 배열을 가지게 된다.
- 이는 압축률을 상당히 떨어뜨린다.
- 최대한 압축 효율을 높이기 위해 사용자의 데이터를 그대로 압축해서 용량을 최소화한 후 암호화를 적용한다.
- 암호화된 테이블의 데이터 페이지는 복호화된 상태로 InnoDB 버퍼 풀에 저장되지만, 압축된 데이터 페이지는 압축 또는 압축 해제의 모든 상태로 InnoDB 버퍼 풀에 존재할 수 있다.
- 암호화가 먼저 실행된다면 MySQL 서버는 InnoDB 버퍼 풀에 존재하는 데이터 페이지에 대해서도 매번 암복호화 작업을 수행해야 된다.
디스크 읽고 쓰기 속도
- 서적의 예제에 따르면 암호화된 테이블은 그렇지 않은 테이블에 비해 읽기는 3~5배 정도, 쓰기는 5~6배 정도 느리다.
- 밀리초 단위이므로 크게 체감되지 않을 수도 있다.
- 디스크 읽고 쓰기 속도는
performance_schema
의 file_summary_by_instance
테이블에 수집된 결과를 이용해 조회한다.
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 서버에서 기본적으로 모든 노드는 각자의 마스터 키를 할당해야 한다.
- 데이터베이스 서버의 로컬 디렉터리에서 마스터 키를 관리하는 경우, 소스 서버와 레플리카 서버가 다른 키를 가진다.
- 원격으로 키 관리 솔루션을 사용하는 경우에도 소스 서버와 레플리카 서버가 서로 다른 마스터 키를 갖도록 설정해야 한다.
- 마스터 키 자체가 레플리카로 복제되지 않기 때문에 테이블스페이스 키 또한 레플리카로 복제되지 않는다.
- 소스 서버와 레플리카 서버는 서로 각자의 마스터 키와 테이블스페이스 키를 관리한다.
- 복제 멤버들의 데이터 파일은 암호화되기 전의 값이 동일하더라도 실제 암호화된 데이터가 저장된 데이터 파일의 내용은 완전히 달라진다.
마스터 키 변경
keyring_file 플러그인 설치
keyring_flie 플러그인
- MySQL 서버의 TDE 암호화 키 관리는 플러그인 방식으로 제공되는데, MySQL 커뮤니티 에디션에서는
keyring_file
플러그인만 사용 가능하다.
keyring_file
플러그인은 테이블스페이스 키를 암호화하기 위한 마스터 키를 디스크의 파일로 관리한다.
- 마스터 키는 평문으로 디스크에 저장된다.
- 마스터 키가 저장된 파일이 외부로 노출되면 데이터 암호화는 무용지물이 된다.
- 따라서 MySQL 서버가 시작될 때만 키링 파일을 다른 서버로부터 다운로드해서 로컬 디스크에 저장한 후 MySQL 서버를 시작하는 방법을 고려해보자.
- MySQL 서버가 시작되면 (MySQL 서버가) 마스터 키를 메모리에 캐시하기 때문에 로컬 디스크의 키링 파일을 삭제해도 작동하는 데는 아무런 문제가 없다.
- 마스터 키를 로테이션하는 경우에는 로컬의 키링 파일이 최신이 되므로 다시 외부 서버에 복사해 둬야 한다.
💡 Percona Server는 HashiCorp Vault를 연동하는 키 관리 플러그인을 오픈소스로 제공한다.
MySQL 커뮤니티 에디션에서도 문제없이 사용할 수 있으므로, Percona Server의 keyring_vault 플러그인도 함께 검토해볼 것을 권장한다.
설치 과정
my.cnf에 설정
- MySQL 서버의 다른 플러그인과는 달리, TDE 플러그인은 MySQL 서버가 시작되는 단계에서도 가장 빨리 초기화돼야 한다.
- 그래서 MySQL 서버의 설정 파일(my.cnf)에서 early-plugin-load 시스템 변수에
keyring_file
플러그인을 위한 라이브러리를 명시하면 된다.
keyring_file
플러그인이 마스터 키를 저장할 키링 파일의 경로를 keyring_file_data
설정에 명시한다.
keyring_file_data
설정의 경로는 오직 하나의 MySQL 서버만 참조해야 한다.
- 하나의 리눅스 서버에 MySQL 서버가 2개 이상 실행 중이라면, 각 MySQL 서버가 서로 다른 키링 파일을 사용하도록 설정해야 한다.
## my.cnf 파일
early-plugin-load = keyring_file.so
keyring_file_data = /very/secure/directory/tde_master.key
keyring_file 플러그인 초기화
- MySQL 서버를 재시작하면 자동으로
keyring_file
플러그인이 초기화된다.
keyring_file
플러그인의 초기화 여부는 다음 명령어로 확인 가능하다.SHOW PLUGINS;
- MySQL 서버는
keyring_file
플러그인의 초기화와 동시에 keyring_file_data
시스템 변수의 경로에 빈 파일을 생성한다.
- 아직 마스터 키를 사용한 적이 없기 때문에 실제 키링 파일의 내용은 비어있다.
- 데이터 암호화 기능을 사용하는 테이블을 생성하거나 마스터 로테이션을 실행하면 키링 파일의 마스터 키가 초기화된다.
Reference
참고 서적
📔 Real MySQL 8.0