AWS의 다양한 서비스들을 이용하다 보면 리소스를 생성하는 과정을 마주하게 된다.
그 과정 속에서 간간히 KMS라는 단어를 볼 수 있는데, 대부분의 상황에서 이 KMS 설정은 기본값으로 두거나 아예하지 않고 넘어갔었다. 매번 마주했지만 그 기능에 대해 깊게 공부해본 경험은 없었다.
그나마 SAA 공부할 때 잠깐 얕게 공부해본게 전부라 이 참에 내용을 정리하는 겸 KMS를 활용해보도록 한다.
KMS
Key Management Service, 데이터를 암호화할때 사용되는 암호화 Key에 대한 전체적인 관리를 해주는 서비스
암호화 Key의 클라우드 서비스를 통해 중앙 집중식으로 관리해준다는 목적을 가진다.
KMS의 대표적인 특징은 아래와 같다.
특징 | 내용 |
중앙집중식 제어 | KMS 키의 수명 주기와 권한을 중앙집중식으로 제어할 수 있다. |
AWS 서비스들과 연계 | KMS는 다양한 AWS 서비스들과 연계가 잘 되어있다. KMS 키를 이용해 데이터를 암호화 저장하거나 서명/인증 등의 프로세스에 적용하는 것으로 확인할 수 있다. |
감사 모니터링 | CloudTrail을 통해 KMS에 대한 모든 요청들을 로깅할 수 있으며, CloudTrail에 연동된 S3 버킷으로 로깅된 내용들이 저장된다. 따라서 로깅된 내용이 저장된 S3 버킷을 통해 KMS 서비스 사용 내역을 모니터링 할 수 있다. |
보안 규정 준수 | KMS는 각 국가 별로 지정되어있는 규정 준수 체제의 인증과 검증을 받고 운영된다. 국내 인증인 ISMS(K-ISMS)도 여기에 포함되어 있다. |
KMS에서 제공하는 Key의 유형에는 3가지 방식이 존재한다.
AWS Managed Key
AWS 관리형 키라고도 불리며, AWS의 서비스가 계정에 생성해주는 방식의 KMS 키이다. 이 키를 통해 AWS 서비스들이 KMS 키를 자동으로 사용하게된다.
AWS Managed Key는 키 내용과 정책을 보거나 사용내역 로깅은 가능하지만, 키 속성의 변경이나 교체/삭제 등의 제어는 할 수 없다. 즉, 키에 대한 제어가 필요하지 않은 경우에 적용할 수 있다. AWS Managed Key는 매년 자동으로 교체된다고 한다.
Customer Managed Key
사용자가 직접 계정에 Key를 생성/관리하는 방식이다. AWS Managed Key와는 다르게 생성한 키에 대한 완전한 제어 권한을 갖는다. Customer Managed Key는 사용한 만큼 요금이 발생된다.
AWS Owned Key
AWS 서비스가 Key를 서비스 계정에서 생성하는 방식이다. Owned Key는 사용자의 계정에 종속이 아니라 AWS 서비스 계정에 종속되어있다. 따라서 사용자는 Owned Key에 대해 어떠한 권한도 가지지 못한다.
KMS 동작 과정
KMS의 Customer Managed Key가 동작하는 방식은 아래와 같다.
먼저, KMS에서 Customer Master Key 키를 생성한다.
이후 Customer Master Key를 이용해 GenerateDataKey 메소드를 호출하여 유니크한 DataKey를 생성한다.
(하나는 DataKey의 평문, 다른 하나는 Plaintext DataKey가 Customer Master Key로 암호화된 Encrypted DataKey)
암호화에서는 Plaintext DataKey를 이용해 데이터를 암호화한다.
암호화를 진행하면 Plaintext DataKey는 폐기한다.
이제 이 암호화한 데이터를 복호화를 해야한다.
다만, 암호화에 사용된 Plaintext DataKey는 폐기되었는데, 이때 이를 다시 복구하기 위해 Encrypted DataKey와 Customer Master Key가 사용된다.
Customer Master Key를 이용해 Encrypted DataKey에서 Plaintext DataKey를 다시 복호화한다.
이렇게 되찾은 Plaintext DataKey로 암호화된 데이터를 복호화할 수 있게 된다.
결론적으로 Customer Master Key라는 개념을 두고 하나의 DataKey를 생성해 데이터를 암/복호화하는 과정을 거치게되는 것이다. 즉, 데이터 뿐만 아니라 암호화에 사용되는 키 마저도 암호화하게 되는 것이다.
이와 같은 암호화 방식을 '봉투 암호화'라고 한다.
봉투 암호화에서 AWS와 같은 CSP가 Master Key를 보관해줌으로써 사용자는 더욱 안심하고 편안하게 암/복호화 작업을 진행할 수 있다.
또한, 봉투 암호화는 데이터를 암/복호화하는데에 사용된 Plaintext DataKey가 사용됨과 동시에 폐기되어 암호화에 사용된 키의 탈취가 매우 어렵다는 점이 있다.
KMS(CMK)
Boto3로 KMS API를 호출해서 간단하게 데이터를 암/복호화 해보도록 한다.
먼저, KMS에서 Key를 하나 생성해준다.
웹 콘솔의 KMS 서비스에서 '고객 관리형 키'를 생성
생성할 키는 '대칭'형의 '암호화 및 해독'용으로 설정한 후, 이 키의 관리 권한과 사용 권한을 지정해주어 키를 생성한다.
이후 생성된 키의 ID를 바탕으로 메시지를 암/복호화하는 간단한 코드를 작성한다.
boto3 client나 변수를 정의한 후, 먼저 Key Id를 바탕으로 DataKey를 생성한다. (GenerateDataKey)
kms = boto3.client('kms', region_name='ap-northeast-2', aws_access_key_id=AWS_ACCESS_KEY, aws_secret_access_key=AWS_SECRET_KEY)
message = "Hello, This is test msg for kms."
if __name__ == "__main__":
print(f'[*] Test for KMS Encryption / Decryption')
print(f'[*] Message : {message}')
data_key = kms.generate_data_key(KeyId=KeyId, KeySpec='AES_256')
plaintext_data_key = data_key['Plaintext']
encrypted_data_key = data_key['CiphertextBlob']
print(f'[*] Data Key : {data_key}')
GenerateDataKey API를 호출하면 결과 JSON이 반환된다. 여기에는 설정한 Master KeyId 기반으로 생성된 DataKey인 Plaintext와 이 DataKey가 암호화된 CiphertextBlob이 담겨있다.
이 둘을 바탕으로 암/복호화를 진행하는 것이다.
다음으로 메시지를 암호화한다.
def encryption(msg):
response = kms.encrypt(KeyId='3a4fd1ad-8a99-4ed1-a0ba-24ffcae804ff', Plaintext=msg)
print(f'[*] Encryption Response: {response}')
return response
boto3에서 제공하는 encrypt 메소드를 이용했으며, Master KeyId와 암호화할 평문 메시지를 넣어준다.
encryption의 반환값에는 암호화된 메시지(CiphertextBlob)가 포함되어있다.
다음으로 암호화된 메시지를 복호화한다.
def decryption(msg):
response = kms.decrypt(CiphertextBlob=msg, KeyId=KeyId)
print(f'[*] Decryption Response: {response}')
return response['Plaintext']
마찬가지로 boto3에서 제공하는 decrypt 메소드를 이용했다.
CiphertextBlob에 암호화된 메시지를 넘겨준다.
decryption의 반환값에서 복호화된 메시지(Plaintext)를 확인할 수 있다.
이렇게 boto3 sdk를 사용하는 것 이외에도 KMS는 AWS Encryption SDK라는 클라이언트 라이브러리도 제공한다.