この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
こんにちは、nkhrです。
オンプレ環境では、データ漏洩(第三者による意図しないデータ取得)を防ぐために、メディア破棄の統制を行っていると思います。クラウドでは、利用者による物理的なメディア破棄が行えないため、統制を行う場合は別の方法を考える必要があります。
クラウド環境で利用できるデータ破棄の方法として、「Cryptographic Erase(CE:暗号化消去)」があります。
今回は、下記のブログで紹介されている暗号化消去(CE)を試してみました。暗号化消去は、NIST 800-88にも記載されている方法です。
クラウドにおける安全なデータの廃棄(Amazon Web Service ブログ)
NIST 800-88や暗号化消去(CE)って何?
NIST 800-88
NIST 800-88(媒体のサニタイズに関するガイドライン)は、メディア破棄の統制を定めるために広く利用されているガイドラインです。(NIST 800-88 Rev.1、IPAによる日本語版はリンク先を参照)
3つのサニタイズ方法が定義されており、データ機密性により適する手法を選択します。
- 削除(Clean)- デバイス再利用が可能:新しい値での上書きや、工場出荷時の状態へのリセット
- 除去(Purge)- デバイス再利用が可能:最先端のデータ復元技術を使っても、対象データが復元できない状態にする
- 破棄(Destroy)- デバイス再利用不可:最先端のデータ復元技術を使っても、どの破壊部分からも対象データが復元できない状態にする
暗号化消去
データを保存時に暗号化し、破棄時に暗号鍵を削除します。これにより、暗号化データを回復不能にします。NIST 800-88では、除去手法に分類されています。適用する場合は、以下の点に注意が必要です。
- 保存を開始する前に、暗号化が有効になっていること
- 適切な暗号鍵の強度や、暗号アルゴリズム/利用モードを使用していること
- 暗号鍵の管理が適切に行われていること
- 暗号鍵のバックアップが存在する場合、適切に保護されていること(また適切に削除されること)
ブログの流れ
ためしてみたコードを参照したい方は、「暗号化消去のリソース作成」を参照してください。
- 前提条件
- 今回のブロクで試す構成の前提条件を整理しています。組織の要件に合わせて前提を定義する必要があります。
- データ暗号化について
- 暗号化消去のリソース作成
- 動作確認
- 実際に暗号化消去を行い、消去通知を受け取ります
前提条件
対象としたサービス
今回は、以下のサービスの暗号化消去を試してみました。
- S3
- Redshift
データのライフサイクルについて
暗号化消去を考える場合、データのライフサイクルごとに鍵を作成する必要があります。(ライフサイクルが終了していないデータがある場合、鍵削除ができない)
今回の検証では、以下のライフサイクルを想定しています。
S3
- Bucket単位のデータライフサイクルを想定(Bucketごとに暗号鍵を作成し、Bucket削除時に鍵削除)
Redshift
- クラスタ単位でデータライフサイクルを想定(Clusterごとに暗号鍵を作成し、Cluster削除時に鍵削除、Snapshotは残さない)
- Snapshotも暗号化されるので、鍵を削除すると復号不可
- データを残したい場合は、S3にUnloadして長期保存用の鍵を作るなど別の考慮が必要
暗号化のための鍵生成
AWS Key Management Service (AWS KMS)を利用して鍵の生成および管理を行います。AWSではいくつかの暗号化方式が利用できます。今回は3番のKMSカスタマー鍵を利用します。
1. S3 Server Side Encryption
S3サービスが管理するデフォルト鍵を利用した暗号化、KMSでの管理外。
2. Customer Masker Key(CMK)※KMS登録なし
利用者側で独自に作成した暗号化鍵、KMS登録しない場合は、KMS管理外。
3. Customer Master Key (CMK) in KMS
KMSサービスで利用する暗号鍵。3パターンの作成方法があります。
- AWS_KMS:KMSで鍵を作成する方法 ★今回の鍵作成はこれを利用★
- EXTERNAL:KMSの外で鍵を生成し、KMSにImportする方法
- Externalの場合は、Importした鍵をAWSが生成した鍵でラップして管理します
- AWS_CLOUDHSM:専用ハードウェアセキュリティモジュール (HSM) インスタンスを使用して鍵作成、暗号化を行う方法
- 指定したリージョンのVPCにある専用CloudHSMクラスター内のHSMインスタンスで、シングルテナント管理
- AWS CloudHSMを利用した暗号化は、KMS利用料金に加えてCloudHSM インスタンス料金が発生
4. AWS managed Key in KMS
codecommitやS3、redshift、EBS、RDSなど、いくつかのAWSサービスは、AWS管理のKMS暗号鍵が利用できます。
Region間で鍵共有する場合
Region間で同じ鍵を利用したい場合は、Multi Region Keyが利用できます。今回はSingle Region Keyを作成しました。Multi Region Keyについては、以下のブログを参照してください。
暗号化消去のために利用するAWSサービス
- AWS KMS (暗号鍵の作成・管理)
- AWS Cloud Trail (ユーザアクティビティやAPI使用状況を追跡)
- 鍵削除の証跡イベントの一部は、CloudTrailで取得
- 暗号化消去の実施有無にかかわらず、AWSアカウントを使い始める際は、CloudTrailを必須で有効化したほうが良いです。以下のブログを参考にしてください
- CloudTiralを監査や、暗号化消去の証明として利用する場合、削除防止・改ざん防止が必要です。実施方法は以下のブログを参考にしてください
- 今回、CloudTrailログの保存先S3バケットは、リソース(S3, Redshift)と同じアカウント内に作成します。実運用では、監査ログ用に隔離されたAWSアカウントを作成し、保存することもあります。
- 鍵削除の証跡イベントの一部は、CloudTrailで取得
データ暗号化について
データ暗号化の考慮点
暗号化消去を行う場合、前提として適切なデータ暗号化が必要です。注意点は以下の通りです。
- 安全な暗号化方式の利用する
- 「電子政府における調達のために参照すべき暗号のリスト(CRYPTREC暗号リスト)」に安全な暗号リストがあります
- AWSのKMSで利用する暗号化については、「AWS Key Management Service暗号化の詳細」を参照してください
- 鍵の管理を適切に行う(鍵のバックアップを含む)
- AWS KMSで一元的に鍵管理を行うことで、バックアップも含めてKMS内で管理できます。
- CMKをKMS外で作成し、Importする場合、Import元のCMKの鍵管理や削除が必要です。
- データ格納前から暗号化が有効になっている
- 暗号化消去を考えている場合は、AWS上にデータを格納する前から暗号化を有効にしておく必要があります。
- どのレイヤーで保護したいかを意識する
- 今回は、物理的なメディア破棄ができない場合の暗号化消去を意識しているためハードウェアレベルの暗号化を想定しています
- アプリケーションレベルの保護が必要な場合は、KMS鍵へのアクセス権限をPolicyで制御するなど別の考慮が必要です
- データの機密レベルを意識する
- データ機密レベルに応じて、どのようなデータ破棄の統制が必要かを検討します
暗号化の強制方法
AWSサービスごとに、暗号化の強制(デフォルト暗号化の設定)方法が異なります。
S3 暗号化設定
S3では「Default Encryption (デフォルト暗号化)」を設定することで、ファイルアップロード時に自動でサーバサイドの暗号化が行われます。
バケット作成時にデフォルト暗号化を有効にせず、暗号化の指定なしにファイルをアップロードした場合は注意が必要です。後でデフォルト暗号化を有効にしても、有効化前のファイルは暗号化されません。暗号化が必要な場合は、バケット作成時に設定するようにしましょう。
S3 Bucket Keyとは
Bucket Keyは、KMSへのアクセス頻度を減らすために利用される鍵でKMSにアクセスする頻度を減らすことができます。(KMSサービスの料金)
「Bucket Key」は、デフォルト「Enable」です。Bucket Keyの詳細については、以下のブログを参考にしてください。
Redshift 暗号化設定
Redshiftでは、暗号化を有効にすると設定前のデータも含めて、クラスター内のデータおよび、スナップショットのデータを全て暗号化します。途中から暗号化を有効にした場合のRedshift動作は、以下の通りです。
- 暗号化を有効にした新規クラスターを起動
- 暗号化設定前のクラスター(既存クラスター)から、新クラスターへデータを移動
- 新しいクラスターのEndpointを変更
途中から暗号化した場合、データ破棄統制の観点からは、既存クラスターの破棄統制が行えません。そのため、暗号化消去を考える場合は、利用前から暗号化を有効にしておきましょう。
KMS暗号化後のデータアクセス制御
KMS鍵の利用制御は、Key PolicyとIAM Policyで行います。Policyが正しく設定されていない場合、データのアップロードやダウンロードができなくなります。KMSのPolicy制御については、下記のブログを参考にしてください。
- 【KMS】デフォルトのキーポリシーについて調べてみた
- AWS KMS CMK(Customer Master Key)のキーポリシーとIAMポリシーの組み合わせのアクセス制御と、キーポリシーのみのアクセス制御を試して設定の違いをみてみた
暗号化消去のリソース作成
ここからが実際のやってみたです。以下のイメージを構築します。
1. auditlogBucket&CloudTrail作成(手動作成)
事前に、監査ログ保存用のS3バケット作成と、CloudTrailの有効化を行います。
Auditlog Bucket 作成
今回は以下の設定で作成しました。Object Lock(削除防止)は一度有効化すると無効化できません。ログの保存要件を踏まえて、Object Lockの適切なモード/期間を設定します。Object Lockを設定したBucketは、空であれば削除可能です。
- Block all public access
- Bucket Versioning enabled
- Default encryption enabled (SSE-S3)
- Object Lock enabled
- Default retention enabled
- Default retention mode Governance
- Default retention period 10
CloudTrail設定
ログ出力先は、手動で作成したAuditlog Bucketにします。今回はCloudTrailから作成されるLog fileに対してSSE-KMSを有効化しません。要件に応じて、有効化してください。
ネットワークリソースの作成
以下のネットワークリソースは事前に作成しています。(Cloudformationテンプレートに含みません)
- VPC
- Public Subnet ※EC2/Redshiftの配置(通常、RedshiftはPrivate Subnetに配置すべきです)
- Route Table
- KeyPair
- S3 Gateway Endpoint
2. 削除の対象外リソース作成
暗号化消去の対象外(削除しない)リソースを作成します。サンプルコードは、以下のリソースを作成します。
- Lambda
- Lambda用Role
- EC2
- EC2用Role & InstanceProfile
- SecurityGroup
- Inboundを許可せず、Session Manager経由の接続のみ可
- SNS Topic
- CloudFormationで作成後に、指定したメールアドレスにConfirmationメールが届くのでConfirmが必要
- SNS Topic Policy
- EventBridgeからSNS TopicにPushするためのPolicy
- Event Rule
- KMS Keyの「CancelKeyDeletion」、 「ScheduleKeyDeletion」、 「DeleteKey」イベントをメール通知するルールを設定
- 鍵の完全削除の通知のために、EventBridgeのdetail-type「KMS CMK Deletion」のイベントを設定
- EventBrigeは同じRegionのCloudTrailのイベントのみ取得可能
サンプルコード
AWSTemplateFormatVersion: '2010-09-09'
Parameters:
VpcId:
Type: String
SubnetId:
Type: String
EC2AMI:
Type: AWS::SSM::Parameter::Value<AWS::EC2::Image::Id>
Default: /aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2
KeyName:
Type: AWS::EC2::KeyPair::KeyName
Email:
Type: String
Resources:
LambdaExecutionRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Statement:
- Action: sts:AssumeRole
Effect: Allow
Principal:
Service: lambda.amazonaws.com
MaxSessionDuration: 36000
ManagedPolicyArns:
- arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
Policies:
- PolicyName: lambda-s3empty-role
PolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Action:
- s3:ListBucket
- s3:ListBucketVersions
- s3:DeleteObject
- s3:DeleteObjectVersion
Resource: '*'
Path: "/"
RoleName: test-lambda-s3empty-role
LambdaForS3Empty:
Type: AWS::Lambda::Function
Properties:
FunctionName: empty-to-s3
Runtime: python3.8
Handler: index.lambda_handler
Role: !GetAtt LambdaExecutionRole.Arn
Timeout: 60
Code:
ZipFile: |
import json
import boto3
import cfnresponse
s3 = boto3.resource('s3')
def lambda_handler(event, context):
bucket = event['ResourceProperties']['BucketName']
try:
bucket = s3.Bucket(bucket)
if event['RequestType'] == 'Delete':
bucket.object_versions.delete()
bucket.objects.all().delete()
sendResponseCfn(event, context, cfnresponse.SUCCESS)
except Exception as e:
print(e)
sendResponseCfn(event, context, cfnresponse.FAILED)
def sendResponseCfn(event, context, responseStatus):
response_body = {'Status': responseStatus,
'Reason': 'Log stream name: ' + context.log_stream_name,
'PhysicalResourceId': context.log_stream_name,
'StackId': event['StackId'],
'RequestId': event['RequestId'],
'LogicalResourceId': event['LogicalResourceId'],
'Data': json.loads("{}")}
cfnresponse.send(event, context, responseStatus, response_body)
EC2Role:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Statement:
- Action: sts:AssumeRole
Effect: Allow
Principal:
Service: ec2.amazonaws.com
MaxSessionDuration: 36000
ManagedPolicyArns:
- arn:aws:iam::aws:policy/AmazonS3FullAccess
- arn:aws:iam::aws:policy/AmazonRedshiftFullAccess
- arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore
Policies:
- PolicyName: kms-key-usage-policy
PolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Action:
- kms:Decrypt
- kms:Encrypt
- kms:GenerateDataKey
Resource: '*'
Path: "/"
RoleName: test-ec2-role
IAMInstanceProfile:
Type: AWS::IAM::InstanceProfile
Properties:
Roles:
- !Ref EC2Role
Path: "/"
EC2TestInstance:
Type: AWS::EC2::Instance
DeletionPolicy: Delete
CreationPolicy:
ResourceSignal:
Timeout: PT30M
Properties:
IamInstanceProfile: !Ref IAMInstanceProfile
ImageId: !Ref EC2AMI
InstanceType: t3a.micro
KeyName: !Ref KeyName
InstanceInitiatedShutdownBehavior: stop
DisableApiTermination: false
Monitoring: false
BlockDeviceMappings:
- DeviceName: /dev/xvda
Ebs:
VolumeType: gp3
DeleteOnTermination: true
Encrypted: true
VolumeSize: 20
NetworkInterfaces:
- AssociatePublicIpAddress: true
DeviceIndex: 0
SubnetId: !Ref SubnetId
GroupSet:
- !Ref EC2SecurityGroup
UserData:
Fn::Base64: !Sub
- |
#!/bin/bash
yum update -y
echo '---------------- update aws cli ----------------'
yum -y install jq gcc
curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"
unzip awscliv2.zip
./aws/install
echo '---------------- install amazon redshift rsql ----------------'
yum -y install unixODBC
curl "https://s3.amazonaws.com/redshift-downloads/drivers/odbc/1.4.40.1000/${ODBCFILE}" -o ./${ODBCFILE}
yum -y --nogpgcheck localinstall ./${ODBCFILE}
echo "export ODBCINI=\$HOME/.odbc.ini" >> /etc/profile
echo "export ODBCSYSINI=/opt/amazon/redshiftodbc/Setup" >> /etc/profile
echo "export AMAZONREDSHIFTODBCINI=/opt/amazon/redshiftodbc/lib/64/amazon.redshiftodbc.ini" >> /etc/profile
curl "https://s3.amazonaws.com/redshift-downloads/amazon-redshift-rsql/1.0.1/${RSQLFILE}" -o ./${RSQLFILE}
rpm -i ./${RSQLFILE}
echo '---------------- send cfn-signal ----------------'
/opt/aws/bin/cfn-signal -e $? --stack ${AWS::StackName} --resource EC2TestInstance --region ${AWS::Region}
- {
RSQLFILE: "AmazonRedshiftRsql-1.0.1-1.x86_64.rpm",
ODBCFILE: "AmazonRedshiftODBC-64-bit-1.4.40.1000-1.x86_64.rpm"
}
EC2SecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
VpcId: !Ref VpcId
GroupName: ec2-test-securitygroup
GroupDescription: ec2-test-securitygroup
SNSTopic:
Type: AWS::SNS::Topic
Properties:
TopicName: notify-mail-cloudtrail-kms-event
Subscription:
- Endpoint: !Ref Email
Protocol: email
SNSTopicPolicy:
Type: AWS::SNS::TopicPolicy
Properties:
Topics:
- !Ref SNSTopic
PolicyDocument:
Version: 2012-10-17
Statement:
- Sid: TopicPolicy
Effect: Allow
Principal:
Service: events.amazonaws.com
Action:
- sns:Publish
Resource: !Ref SNSTopic
KMSKeyDeletionRule:
Type: AWS::Events::Rule
Properties:
Name: cloudtrail-test-cf-event-rule
State: ENABLED
EventPattern: |
{
"source": ["aws.kms"],
"detail-type": ["AWS API Call via CloudTrail"],
"detail": {
"eventSource": ["kms.amazonaws.com"],
"eventName": ["CancelKeyDeletion", "ScheduleKeyDeletion", "DisableKey", "DeleteKey"]
}
}
Targets:
- Arn: !Ref SNSTopic
Id: KMSKeyAlert
CMKDeletionRule:
Type: AWS::Events::Rule
Properties:
Name: cloudtrail-test-aws-event-rule
State: ENABLED
EventPattern: |
{
"source": ["aws.kms"],
"detail-type": ["KMS CMK Deletion"]
}
Targets:
- Arn: !Ref SNSTopic
Id: KMSKeyAlert
Outputs:
EC2SecurityGroupId:
Value: !GetAtt EC2SecurityGroup.GroupId
EC2TestInstancePrivateIP:
Value: !GetAtt EC2TestInstance.PrivateIp
LambdaArn:
Value: !GetAtt LambdaForS3Empty.Arn
SendEmail:
Value: !Ref Email
3. S3Bucket & KMS Key作成
サンプルでは以下のリソースを作成しています。
- S3 Bucket
- Custom Resource (LambdaによるS3 Bucket削除用)
- KMS Key
サンプルコード
AWSTemplateFormatVersion: '2010-09-09'
Parameters:
S3BucketName:
Type: String
Default: ttn-test-encrypt-data
AuditBucketName:
Type: String
Default: ttn-test-audit-logs
LambdaFunctionName:
Type: String
Default: empty-to-s3
Resources:
LambdaForS3Empty:
Type: Custom::cleanupbucket
Properties:
ServiceToken:
!Sub 'arn:aws:lambda:${AWS::Region}:${AWS::AccountId}:function:${LambdaFunctionName}'
BucketName: !Ref S3BucketName
DependsOn: Bucket
Bucket:
Type: AWS::S3::Bucket
Properties:
BucketName: !Ref S3BucketName
AccessControl: Private
PublicAccessBlockConfiguration:
BlockPublicAcls: TRUE
BlockPublicPolicy: TRUE
IgnorePublicAcls: TRUE
RestrictPublicBuckets: TRUE
LoggingConfiguration:
DestinationBucketName: !Ref AuditBucketName
LogFilePrefix: !Sub s3accesslogs/${S3BucketName}/
BucketEncryption:
ServerSideEncryptionConfiguration:
- ServerSideEncryptionByDefault:
SSEAlgorithm: aws:kms
KMSMasterKeyID: !GetAtt S3BucketSSEKMS.KeyId
BucketKeyEnabled: true
S3BucketSSEKMS:
Type: AWS::KMS::Key
Properties:
Description: s3 kms key sample
Enabled: true
# SYMMETRIC_DEFAULT is AES-256-GCM
KeySpec: SYMMETRIC_DEFAULT
MultiRegion: false
EnableKeyRotation: true
PendingWindowInDays: 7
KeyPolicy:
Version: 2012-10-17
Id: s3-sse-key-default
Statement:
- Sid: Enable IAM User Permissions
Effect: Allow
Principal:
AWS: !Sub arn:aws:iam::${AWS::AccountId}:root
Action: 'kms:*'
Resource: '*'
S3KmsKeyAlias:
Type: AWS::KMS::Alias
Properties:
AliasName: alias/test-s3-kms-key
TargetKeyId: !Ref S3BucketSSEKMS
Outputs:
KmsKeyAlias:
Value: !Ref S3KmsKeyAlias
BucketArn:
Value: !GetAtt Bucket.Arn
サンプルを実行すると、S3 BucketとS3 BucketのKMS Keyが自動生成されます。
4. Redshift & KMS Key作成
サンプルでは以下のリソースを作成しています。
- Redshift Cluster (SubnetGroup & Cluster Group)
- SecurityGroup
- KMS Key
サンプルコード
AWSTemplateFormatVersion: "2010-09-09"
Parameters:
VpcId:
Type: AWS::EC2::VPC::Id
SubnetId:
Type: AWS::EC2::Subnet::Id
EC2SecurityGroupId:
Type: AWS::EC2::SecurityGroup::Id
# 作成したEC2にアタッチしたSecurity Groupを選択
ClusterName:
Type: String
Default: test-redshit
MasterUsername:
Type: String
Default: test_admin
MasterUserPassword:
# SecretManagerやParameter Storeを利用したほうが良いです
Type: String
Port:
Type: String
Default: 5439
Resources:
S3AccessRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Statement:
- Action: sts:AssumeRole
Effect: Allow
Principal:
Service: redshift.amazonaws.com
MaxSessionDuration: 3600
ManagedPolicyArns:
- arn:aws:iam::aws:policy/AmazonS3FullAccess
Policies:
- PolicyName: kms-key-usage-policy
PolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Action:
- kms:Decrypt
- kms:Encrypt
- kms:GenerateDataKey
Resource: '*'
Path: "/"
RoleName: RedshiftS3AccessRole
SubnetGroup:
Type: AWS::Redshift::ClusterSubnetGroup
Properties:
Description: Redshift cluster subnet group
SubnetIds:
- !Ref SubnetId
SecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
VpcId: !Ref VpcId
GroupName: test-redshift-sg
GroupDescription: test-redshift-sg
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: !Ref Port
ToPort: !Ref Port
SourceSecurityGroupId: !Ref EC2SecurityGroupId
ClusterParameterGroup:
Type: AWS::Redshift::ClusterParameterGroup
Properties:
Description: 'dwh test redshift'
ParameterGroupFamily: redshift-1.0
Parameters:
- ParameterName: require_ssl
ParameterValue: true
Cluster:
Type: AWS::Redshift::Cluster
Properties:
AllowVersionUpgrade: true
AquaConfigurationStatus: disabled
AvailabilityZone: ap-northeast-1a
Classic: false
ClusterIdentifier: !Ref ClusterName
ClusterParameterGroupName: !Ref ClusterParameterGroup
ClusterSubnetGroupName: !Ref SubnetGroup
ClusterType: single-node
NodeType: dc2.large
Encrypted: true
EnhancedVpcRouting: true
IamRoles:
- !Sub arn:aws:iam::${AWS::AccountId}:role/aws-service-role/redshift.amazonaws.com/AWSServiceRoleForRedshift
- !GetAtt S3AccessRole.Arn
KmsKeyId: !GetAtt RedshiftKMS.KeyId
DBName: test
Port: !Ref Port
MasterUsername: !Ref MasterUsername
MasterUserPassword: !Ref MasterUserPassword
AutomatedSnapshotRetentionPeriod: 1
ManualSnapshotRetentionPeriod: 1
PreferredMaintenanceWindow: 'Sun:07:00-Sun:07:30'
PubliclyAccessible: false
VpcSecurityGroupIds:
- !Ref SecurityGroup
RedshiftKMS:
Type: AWS::KMS::Key
Properties:
Description: redshift kms key sample
Enabled: true
# SYMMETRIC_DEFAULT is AES-256-GCM
KeySpec: SYMMETRIC_DEFAULT
MultiRegion: false
EnableKeyRotation: true
PendingWindowInDays: 7
KeyPolicy:
Version: 2012-10-17
Id: redshift-key-default
Statement:
- Sid: Enable IAM User Permissions
Effect: Allow
Principal:
AWS: !Sub arn:aws:iam::${AWS::AccountId}:root
Action: 'kms:*'
Resource: '*'
RedshiftKmsKeyAlias:
Type: AWS::KMS::Alias
Properties:
AliasName: alias/test-redshift-kms-key
TargetKeyId: !Ref RedshiftKMS
Outputs:
Cluster:
Value: !Ref Cluster
Endpoint:
Value: !GetAtt Cluster.Endpoint.Address
Port:
Value: !GetAtt Cluster.Endpoint.Port
DatabaseName:
Value: Cluster
Username:
Value: !Ref MasterUsername
AccessCmd:
Value: !Sub "rsql -h ${Cluster.Endpoint.Address} -U ${MasterUsername} -d test"
サンプルを実行すると、Redshift ClusterとKMS Keyが自動生成されます。
データ投入とKMS暗号化確認
S3ファイルアップロード
[ec2-user@ip-10-0-0-33 ~]$ echo "test file" > test.txt
[ec2-user@ip-10-0-0-33 ~]$ aws s3 cp test.txt s3://ttn-test-encrypt-data/
upload: ./test.txt to s3://ttn-test-encrypt-data/test.txt
アップロードしたファイルは、自動でKMS鍵により、サーバサイド暗号化されます。(ファイルの「プロパティ>サーバ側の暗号化設定」で確認)
Redshiftへの接続
S3バケットのKMS暗号化ファイルをRedshiftにコピーできるか確認します。
[ec2-user@ip-10-0-0-33 ~]$ rsql -h test-redshit.cxrqsub7rc82.ap-northeast-1.redshift.amazonaws.com -U test_admin -d test
(test-redshit) test_admin@test=# CREATE TABLE test(col1 INT, col2 VARCHAR(100), col3 INT);
(test-redshit) test_admin@test=# COPY test from 's3://ttn-test-encrypt-data/redshift/copy_data.csv' iam_role 'arn:aws:iam:::role/RedshiftS3AccessRole' csv IGNOREHEADER 1;
INFO: Load into table 'test' completed, 2 record(s) loaded successfully.
(test-redshit) test_admin@test=# select * from test;
col1 | col2 | col3
------+------+------
1 | aaa | 3
2 | bbb | 4
(2 rows)
暗号化消去の動作確認
S3Bucket削除 & KMS鍵削除
CloudFormationスタックを削除し、S3 BucektとKMS鍵を削除します。
KMS Keyは削除保留中の状態になります。
Event Bridgeにより、ScheduleKeyDeletion(スケジュール削除)イベントの結果がメール通知されます。
Redshiftクラスター削除 & KMS鍵削除
CloudFormationスタックを削除し、RedshiftとKMS Keyを削除します。
Event Bridgeにより、ScheduleKeyDeletionイベントの結果がメール通知されます。メール内容は、S3 Bucket用のKMS鍵の削除で送信されるメッセージと同様です。
削除予約したKMS鍵の復元
KMS鍵は、削除保留期間の設定が必須であるため(最低7日)、削除保留期間中は鍵の削除をキャンセルできます。
完全削除の通知
削除保留期間が経過した鍵は、AWSにより自動で削除されます。EventBridge経由のSNS通知で以下のようなメールを取得できます。
まとめ
今回は、データ消去の統制を行うための仕組みを構築し、鍵削除の通知をメールで受け取れることを確認しました。
通知メール内容は、少し読みにくいので、SNSのメール通知前に、EventBridgeと他のサービス(LambdaやStep Function)を組み合わせて、レポートを作成したり、作成レポートをS3保存してもよいと思います。
以上、nkhrでした。
参考資料
- クラウドにおける安全なデータの廃棄(Amazon Web Service ブログ)
- クラウドにおける安全なデータの廃棄(実践編)****(****Amazon Web Service ブログ)
- 電子政府における調達のために参照すべき暗号のリスト(CRYPTREC暗号リスト)
- AWS Key Management Service暗号化の詳細