KMS란? 암호화 키의 라이프사이클을 관리하는 전용 시스템으로 암호화 키의 생성, 저장, 백업, 복구, 파기 등의 기능을 제공하는 시스템으로 CMK 제어 및 관리, AES-256 / RSA(SHA_256)을 지원.
다만 CMK는 4KB까지 데이터만 암호화 가능.
따라서 4KB 이하의 데이터 보다 큰 데이터들을 암호화할 때는 데이터키를 활용.
[암호화]
1) CMK의 generate를 이용하여 데이터키와 암호화 된 데이터키를 생성.
2) 원본 데이터키를 이용하여 데이터를 암호화.
3) 원본 데이터키를 삭제.
[복호화]
1) CMK를 이용하여 암호화 된 데이터키를 복호화.
2) 복호화 된 원본 데이터키를 이용하여 데이터를 복호화.
3) 복호화 된 원본 데이터키를 삭제.
암호화 방식은 아래 링크에 잘 설명되어 있음.
Python Boto3를 이용하여 CMK를 사용해보자 (대칭키 사용 / python v3 / fernet 이용)
https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/kms.html
1) KMS에서 CMK를 사용할 User나 Role을 정하고 Policy를 생성.
https://docs.aws.amazon.com/kms/latest/developerguide/key-policy-default.html
[권한 관리 생성]
kms_policy.json
Root User, Master Role: KMS 관리
Dev User: 암복호화 용도
{
"Id": "key-policy",
"Version": "2012-10-17",
"Statement": [
{
"Sid": "Enable IAM User Permissions",
"Effect": "Allow",
"Principal": {
"AWS": [
"arn:aws:iam::557xxxxx50:root",
"arn:aws:iam::557xxxxx750:role/master"
]
},
"Action": "kms:*",
"Resource": "*"
},
{
"Sid": "Allow attachment of persistent resources",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::557xxx750:user/dev"
},
"Action": [
"kms:CreateGrant",
"kms:ListGrants",
"kms:RevokeGrant"
],
"Resource": "*",
"Condition": {
"Bool": {
"kms:GrantIsForAWSResource": "true"
}
}
}
]
}
[CMK 생성]
주의: KeySpec과 keyUsage 파라미터를 정의하면 비대칭키로 생성
import boto3
import base64
import json
kms_client = boto3.client("kms")
# Key Policy
def get_policy():
with open("./kms_policy.json", "r") as f:
json_data = json.load(f)
kms_policy = json.dumps(json_data)
return kms_policy
# Create KMS
def create_kms(kms_policy):
response = kms_client.create_key(
Policy = kms_policy,
Description = "Learning KMS",
Origin = "AWS_KMS",
BypassPolicyLockoutSafetyCheck = False,
Tags = [
{
"TagKey": "Name",
"TagValue": "KMS_TEST"
}
]
)
return response["KeyMetadata"]["KeyId"], response["KeyMetadata"]["Arn"]
def create_alias(keyId):
response = kms_client.create_alias(
AliasName = "alias/demo_cmk",
TargetKeyId = KeyId
)
if __name__ == "__main__":
kms_policy = get_policy()
KeyId, Arn = create_kms(kms_policy)
create_alias(KeyId)
AWS KMS Console에 아래와 같이 CMK가 생성되는 것을 확인
Key ID를 저장
별첨: 기본적으로 4K 이하의 데이터는 아래와 같이 데이터키 없이 사용 가능
import boto3
import base64
import json
kms_client = boto3.client("kms")
KEY_ID = "9dafea1b-9d8c-4e43-8fe3-4003747629b4"
PW = "qwer1234"
def encrypt(keyId, data):
encrypt_result = kms_client.encrypt(KeyId=keyId, Plaintext=data)
print(encrypt_result)
return base64.b64encode(encrypt_result["CiphertextBlob"])
def decrypt(encrypted_data):
decrypt_result = kms_client.decrypt(CiphertextBlob=base64.b64decode(encrypted_data))
print(decrypt_result["Plaintext"].decode("utf8"))
return decrypt_result
if __name__ == "__main__":
encrypted_data = encrypt(KEY_ID, PW)
decrypted_data = decrypt(encrypted_data)
2) CMK와 boto3의 generate_data_key를 사용하여 데이터키, 암호화 된 데이터키 생성
그리고 Fernet과 encrypt를 이용하여 암호화 된 Data 저장
encrypted_key.txt에는 암호화 된 데이터키 저장 / secret.txt에는 암호화 된 데이터 저장
import boto3
import base64
import json
from cryptography.fernet import Fernet
kms_client = boto3.client("kms")
KEY_ID = "alias/demo_cmk"
SECRET = "qwer1234"
def create_generate_data_key(KEY_ID):
response = kms_client.generate_data_key(
KeyId = KEY_ID,
KeySpec = "AES_256"
)
return base64.b64encode(response["CiphertextBlob"]), base64.b64encode(response["Plaintext"])
def save_encrypted_key(encrypted_key):
f = open("./encrypted_key.txt", "wb")
f.write(encrypted_key)
f.close()
def encrypt_data(SECRET, plain_key):
cipher_suite = Fernet(plain_key)
cipher_data = cipher_suite.encrypt(SECRET.encode('utf-8'))
f = open("./secret.txt", "wb")
f.write(cipher_data)
f.close()
return cipher_data
if __name__ == "__main__":
encrypted_key, plain_key = create_generate_data_key(KEY_ID)
save_encrypted_key(encrypted_key)
cipher_data = encrypt_data(SECRET, plain_key)
3) 암호화 된 데이터키를 이용하여 암호화 된 데이터를 복호화
import boto3
import base64
import json
from cryptography.fernet import Fernet
kms_client = boto3.client("kms")
KEY_ID = "alias/demo_cmk"
def decrypt_data():
f_s = open("./secret.txt", "rb")
e_secret = f_s.readline()
f_e = open("./encrypted_key.txt", "rb")
encrypted_key = f_e.readline()
response = kms_client.decrypt(CiphertextBlob=base64.b64decode(encrypted_key))
plain_key = base64.b64encode(response["Plaintext"])
cipher = Fernet(plain_key)
secret = cipher.decrypt(bytes(e_secret))
print(secret)
if __name__ == "__main__":
chipher_data = decrypt_data()
그럼 위 그림과 같이 암호화 된 데이터키를 통해 데이터를 복호화 할 수 있음.
추가로 AWS KMS의 key는 export가 불가능하기 때문에 삭제 후에는 데이터를 복호화 할 방법이 없음.
다만 AWS CloudHSM을 사용할 경우, key의 export가 가능.
어느 정도 규모가 있는 정보통신사업자(연 매출 100억 이상 등)라면 키 관리 시스템에 대한 감사가 있기 때문에 주로 법적인 문제로 KMS를 쓰는 경우가 많음. (ISMS-P 등)
그러나 법적인 문제 외에도 애플리케이션을 통해 암호화 할 경우 SHA-1, MD5 등 위험 요소가 있는 알고리즘 사용으로 보안 문제 및 유지보수의 어려움이 발생할 수 있기 때문에 중요한 데이터의 경우에도 KMS 사용을 권장.
KMS, HSM은 키 관리에 대한 보안, 성능, 관리 세 가지 목적을 위해 사용되는데, FIPS 등 인증을 받은 전용 장치이기 때문에 보다 안전하고, 애플리케이션이 암복호화에 처리해야 할 작업에 대한 부하를 줄여주기도 함.
HSM란? 암호화 키를 필요로 하는 다양한 애플리케이션이 있을 경우 생성, 저장, 백업, 복구 파기 등의 기능을 제공하는 물리 시스템.
'Security&Identity' 카테고리의 다른 글
AWS Config 5분만에 이해하기 (0) | 2021.10.14 |
---|