Amazon ECS용 Fargate 임시 스토리지의 AWS KMS 키 관리하기
Amazon ECS용 Fargate 임시 스토리지의 AWS KMS 키 관리하기
Fargate 임시 스토리지(ephemeral storage)를 암호화하기 위해 AWS KMS 키를 만들거나 가져온 후에는, 다른 AWS KMS 키와 같은 방식으로 관리하면 돼요.
출처: 문서
본문
Fargate 임시 스토리지를 암호화하기 위해 AWS KMS 키를 만들거나 가져온 후에는, 다른 AWS KMS 키와 같은 방식으로 관리합니다.
AWS KMS 키의 자동 회전
자동 키 회전을 활성화하거나 키를 수동으로 회전할 수 있습니다. 자동 키 회전은 키에 대한 새 암호화 자료를 생성해 매년 키를 회전시킵니다. AWS KMS는 키의 모든 이전 버전의 암호화 자료도 저장하므로, 이전 키 버전을 사용한 데이터는 계속 복호화할 수 있습니다. 회전된 자료는 키를 삭제할 때까지 AWS KMS가 삭제하지 않습니다.
자동 키 회전은 선택 사항이며 언제든 활성화하거나 비활성화할 수 있습니다.
AWS KMS 키 비활성화 또는 폐기(revoke)
AWS KMS에서 고객 관리형 키(customer managed key)를 비활성화해도 실행 중인 태스크에는 영향이 없으며, 태스크는 수명주기 동안 계속 동작합니다. 새 태스크가 비활성화되거나 폐기된 키를 사용하면 키에 접근할 수 없기 때문에 태스크가 실패합니다. 비활성화된 키가 이미 암호화된 데이터를 복호화하는 데 필요해지지 않도록 CloudWatch 알람 등을 설정해야 합니다.
AWS KMS 키 삭제
키 삭제는 항상 최후의 수단이어야 하며, 삭제한 키가 다시는 필요하지 않다는 것이 확실할 때만 해야 합니다. 삭제된 키를 사용하려는 새 태스크는 키에 접근할 수 없기 때문에 실패합니다. AWS KMS는 키를 삭제하는 대신 비활성화할 것을 권고합니다. 키를 삭제해야 한다고 생각되면, 먼저 비활성화하고 키가 필요하지 않은지 확인하기 위해 CloudWatch 알람을 설정할 것을 권장합니다. 키를 삭제한다면 AWS KMS는 마음을 바꿀 수 있는 최소 7일의 시간을 제공합니다.
AWS KMS 키 접근 감사
CloudTrail 로그로 AWS KMS 키에 대한 접근을 감사할 수 있습니다. CreateGrant, GenerateDataKeyWithoutPlaintext, Decrypt AWS KMS 작업을 확인할 수 있어요. 이 작업들은 CloudTrail에 기록되는 EncryptionContext의 일부로 aws:ecs:clusterAccount와 aws:ecs:clusterName도 보여줍니다.
다음은 GenerateDataKeyWithoutPlaintext, GenerateDataKeyWithoutPlaintext (DryRun), CreateGrant, CreateGrant (DryRun), RetireGrant에 대한 예제 CloudTrail 이벤트입니다(빨간 값은 본인의 값으로 바꾸세요).
GenerateDataKeyWithoutPlaintext
{
"eventVersion": "1.08",
"userIdentity": {
"type": "AWSService",
"invokedBy": "ec2-frontend-api.amazonaws.com"
},
"eventTime": "2024-04-23T18:08:13Z",
"eventSource": "kms.amazonaws.com",
"eventName": "GenerateDataKeyWithoutPlaintext",
"awsRegion": "us-west-2",
"sourceIPAddress": "ec2-frontend-api.amazonaws.com",
"userAgent": "ec2-frontend-api.amazonaws.com",
"requestParameters": {
"numberOfBytes": 64,
"keyId": "arn:aws:kms:us-west-2:account-id:key/a1b2c3d4-5678-90ab-cdef-EXAMPLE11111",
"encryptionContext": {
"aws:ecs:clusterAccount": "account-id",
"aws:ebs:id": "vol-xxxxxxx",
"aws:ecs:clusterName": "cluster-name"
}
},
"responseElements": null,
"requestID": "a1b2c3d4-5678-90ab-cdef-EXAMPLE22222",
"eventID": "a1b2c3d4-5678-90ab-cdef-EXAMPLE33333",
"readOnly": true,
"resources": [
{
"accountId": "AWS Internal",
"type": "AWS::KMS::Key",
"ARN": "arn:aws:kms:us-west-2:account-id:key/a1b2c3d4-5678-90ab-cdef-EXAMPLE11111"
}
],
"eventType": "AwsApiCall",
"managementEvent": true,
"recipientAccountId": "account-id",
"sharedEventID": "a1b2c3d4-5678-90ab-cdef-EXAMPLEaaaaa",
"eventCategory": "Management"
}
GenerateDataKeyWithoutPlaintext (DryRun)
{
"eventVersion": "1.08",
"userIdentity": {
"type": "AWSService",
"invokedBy": "fargate.amazonaws.com"
},
"eventTime": "2024-04-23T18:08:11Z",
"eventSource": "kms.amazonaws.com",
"eventName": "GenerateDataKeyWithoutPlaintext",
"awsRegion": "us-west-2",
"sourceIPAddress": "fargate.amazonaws.com",
"userAgent": "fargate.amazonaws.com",
"errorCode": "DryRunOperationException",
"errorMessage": "The request would have succeeded, but the DryRun option is set.",
"requestParameters": {
"keyId": "arn:aws:kms:us-west-2:account-id:key/a1b2c3d4-5678-90ab-cdef-EXAMPLE11111",
"dryRun": true,
"numberOfBytes": 64,
"encryptionContext": {
"aws:ecs:clusterAccount": "account-id",
"aws:ecs:clusterName": "cluster-name"
}
},
"responseElements": null,
"requestID": "a1b2c3d4-5678-90ab-cdef-EXAMPLE22222",
"eventID": "a1b2c3d4-5678-90ab-cdef-EXAMPLE33333",
"readOnly": true,
"resources": [
{
"accountId": "AWS Internal",
"type": "AWS::KMS::Key",
"ARN": "arn:aws:kms:us-west-2:account-id:key/a1b2c3d4-5678-90ab-cdef-EXAMPLE11111"
}
],
"eventType": "AwsApiCall",
"managementEvent": true,
"recipientAccountId": "account-id",
"sharedEventID": "a1b2c3d4-5678-90ab-cdef-EXAMPLEaaaaa",
"eventCategory": "Management"
}
CreateGrant
{
"eventVersion": "1.08",
"userIdentity": {
"type": "AWSService",
"invokedBy": "ec2-frontend-api.amazonaws.com"
},
"eventTime": "2024-04-23T18:08:13Z",
"eventSource": "kms.amazonaws.com",
"eventName": "CreateGrant",
"awsRegion": "us-west-2",
"sourceIPAddress": "ec2-frontend-api.amazonaws.com",
"userAgent": "ec2-frontend-api.amazonaws.com",
"requestParameters": {
"keyId": "arn:aws:kms:us-west-2:account-id:key/a1b2c3d4-5678-90ab-cdef-EXAMPLE11111",
"granteePrincipal": "fargate.us-west-2.amazonaws.com",
"operations": [
"Decrypt"
],
"constraints": {
"encryptionContextSubset": {
"aws:ecs:clusterAccount": "account-id",
"aws:ebs:id": "vol-xxxx",
"aws:ecs:clusterName": "cluster-name"
}
},
"retiringPrincipal": "ec2.us-west-2.amazonaws.com"
},
"responseElements": {
"grantId": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"keyId": "arn:aws:kms:us-west-2:account-id:key/a1b2c3d4-5678-90ab-cdef-EXAMPLE11111"
},
"requestID": "a1b2c3d4-5678-90ab-cdef-EXAMPLE22222",
"eventID": "a1b2c3d4-5678-90ab-cdef-EXAMPLE33333",
"readOnly": false,
"resources": [
{
"accountId": "AWS Internal",
"type": "AWS::KMS::Key",
"ARN": "arn:aws:kms:us-west-2:account-id:key/a1b2c3d4-5678-90ab-cdef-EXAMPLE11111"
}
],
"eventType": "AwsApiCall",
"managementEvent": true,
"recipientAccountId": "account-id",
"sharedEventID": "a1b2c3d4-5678-90ab-cdef-EXAMPLEaaaaa",
"eventCategory": "Management"
}
CreateGrant (DryRun)
{
"eventVersion": "1.08",
"userIdentity": {
"type": "AWSService",
"invokedBy": "fargate.amazonaws.com"
},
"eventTime": "2024-04-23T18:08:11Z",
"eventSource": "kms.amazonaws.com",
"eventName": "CreateGrant",
"awsRegion": "us-west-2",
"sourceIPAddress": "fargate.amazonaws.com",
"userAgent": "fargate.amazonaws.com",
"errorCode": "DryRunOperationException",
"errorMessage": "The request would have succeeded, but the DryRun option is set.",
"requestParameters": {
"keyId": "arn:aws:kms:us-west-2:account-id:key/a1b2c3d4-5678-90ab-cdef-EXAMPLE11111",
"granteePrincipal": "fargate.us-west-2.amazonaws.com",
"dryRun": true,
"operations": [
"Decrypt"
],
"constraints": {
"encryptionContextSubset": {
"aws:ecs:clusterAccount": "account-id",
"aws:ecs:clusterName": "cluster-name"
}
}
},
"responseElements": null,
"requestID": "a1b2c3d4-5678-90ab-cdef-EXAMPLE22222",
"eventID": "a1b2c3d4-5678-90ab-cdef-EXAMPLE33333",
"readOnly": false,
"resources": [
{
"accountId": "AWS Internal",
"type": "AWS::KMS::Key",
"ARN": "arn:aws:kms:us-west-2:account-id:key/a1b2c3d4-5678-90ab-cdef-EXAMPLE11111"
}
],
"eventType": "AwsApiCall",
"managementEvent": true,
"recipientAccountId": "account-id",
"sharedEventID": "a1b2c3d4-5678-90ab-cdef-EXAMPLEaaaaa",
"eventCategory": "Management"
}
RetireGrant
{
"eventVersion": "1.08",
"userIdentity": {
"type": "AWSService",
"invokedBy": "AWS Internal"
},
"eventTime": "2024-04-20T18:37:38Z",
"eventSource": "kms.amazonaws.com",
"eventName": "RetireGrant",
"awsRegion": "us-west-2",
"sourceIPAddress": "AWS Internal",
"userAgent": "AWS Internal",
"requestParameters": null,
"responseElements": {
"keyId": "arn:aws:kms:us-west-2:account-id:key/a1b2c3d4-5678-90ab-cdef-EXAMPLE11111"
},
"additionalEventData": {
"grantId": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
"requestID": "a1b2c3d4-5678-90ab-cdef-EXAMPLE22222",
"eventID": "a1b2c3d4-5678-90ab-cdef-EXAMPLE33333",
"readOnly": false,
"resources": [
{
"accountId": "AWS Internal",
"type": "AWS::KMS::Key",
"ARN": "arn:aws:kms:us-west-2:account-id:key/a1b2c3d4-5678-90ab-cdef-EXAMPLE11111"
}
],
"eventType": "AwsApiCall",
"managementEvent": true,
"recipientAccountId": "account-id",
"sharedEventID": "a1b2c3d4-5678-90ab-cdef-EXAMPLEaaaaa",
"eventCategory": "Management"
}
이런 CloudTrail 이벤트들을 검토하면 어떤 태스크·클러스터가 언제 KMS 키를 사용했는지 감사할 수 있어요.
더 알아보기 (Learn more)
- AWS KMS 키 관리와 Fargate 스토리지 암호화에 대한 자세한 내용은 AWS 공식 문서를 참고해 주세요.