AWS SDK for Ruby で S3 の暗号化(サーバサイド/クライアントサイド)を試してみた

S3 でオブジェクトの暗号化を検討する場合,大きく2種類ある.

AWS 認定試験にも関係するし,知識としては知っていたけど,実際に試したことがなかったので AWS SDK for Ruby を使って動作確認をしてみた.

前提

適当なログファイルを用意した.

$ cat sample.log
1
2
3
4
5

暗号化なし

ドキュメントの通りに実装すればオブジェクトをアップロードすることができる.

require 'aws-sdk'
require 'pp'

s3 = Aws::S3::Client.new

File.open('./sample.log') do |file|
  s3.put_object(
    bucket: 'xxx',
    key: 'sample.log',
    body: file
  )
end

サーバサイド暗号化 : AES256

put_object() のパラメータとして server_side_encryption: 'AES256' を指定するだけで良い.

require 'aws-sdk'
require 'pp'

s3 = Aws::S3::Client.new

File.open('./sample.log') do |file|
  s3.put_object(
    bucket: 'xxx',
    key: 'sample2.log',
    body: file,
    server_side_encryption: 'AES256'
  )
end

pp s3.head_object(
  bucket: 'xxx',
  key: 'sample2.log',
)

head_object() でメタデータを確認したら,server_side_encryption の値が AES256 になっていた.

#<struct Aws::S3::Types::HeadObjectOutput
(中略)
 server_side_encryption="AES256",
(中略)
 parts_count=nil>

管理コンソールから確認することもできる.さらに AES256 の場合,自由に暗号化 ON/OFF を切り替えることができる.サーバサイド暗号化のメリットと言えるかもしれない.

f:id:kakku22:20161114204928p:plain

サーバサイド暗号化 : KMS

put_object() のパラメータとして server_side_encryption: 'aws:kms' を指定する.

require 'aws-sdk'
require 'pp'

s3 = Aws::S3::Client.new

File.open('./sample.log') do |file|
  s3.put_object(
    bucket: 'xxx',
    key: 'sample3.log',
    body: file,
    server_side_encryption: 'aws:kms'
  )
end

pp s3.head_object(
  bucket: 'xxx',
  key: 'sample3.log',
)

head_object() でメタデータを確認したら,server_side_encryption の値が aws:kms になっていた.また事前に KMS でキーを生成しなくても,自動的に KMS で S3 用のマスターキーが生成されていた.

#<struct Aws::S3::Types::HeadObjectOutput
(中略)
 server_side_encryption="aws:kms",
 ssekms_key_id="arn:aws:kms:ap-northeast-1:111111111111:key/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
(中略)
 parts_count=nil>

管理コンソールから確認することもできる.ただし,KMS の場合,暗号化 ON/OFF を切り替えることはできなかった.

f:id:kakku22:20161114205800p:plain

クライアントサイド暗号化 : 独自キー

クライアントサイド暗号化を行う場合は Aws::S3::Client ではなく Aws::S3::Encryption::Client でクライアントを生成する必要がある.とは言え,実装はほとんど変わらず,クライアントの初期化で encryption_key を指定するぐらい.

require 'aws-sdk'
require 'pp'
require 'openssl'

s3_encryption = Aws::S3::Encryption::Client.new(
  encryption_key: OpenSSL::PKey::RSA.new(1024)
)

File.open('./sample.log') do |file|
  s3_encryption.put_object(
    bucket: 'xxx',
    key: 'sample4.log',
    body: file
  )
end

クライアントで暗号化をしているため,オブジェクトを取得する場合も Aws::S3::Encryption::Client を使う必要がある.Aws::S3::Client を使ってしまうと暗号化されたまま取得されてしまう.

require 'aws-sdk'
require 'pp'
require 'openssl'

s3_encryption = Aws::S3::Encryption::Client.new(
  encryption_key: OpenSSL::PKey::RSA.new(1024)
)

# "1\n2\n3\n4\n5"
pp s3_encryption.get_object(
  bucket: 'xxx',
  key: 'sample4.log',
).body.read

s3 = Aws::S3::Client.new

# "@\xEF-]@\xE5\xC7\u0015\x8DH'S\xB08\xCFB"
pp s3.get_object(
  bucket: 'xxx',
  key: 'sample4.log',
).body.read

クライアントサイド暗号化 : KMS

KMS を使ってクライアントサイド暗号化をする例はうまく動かなかった.もう少し調査しないと...!

オマケ : Gitter

ドキュメントを読んでたら Gitter と連携してることに気付いた.Issue を立てるほどじゃないけど,サクッと聞きたいこともあるし,Gitter のカジュアルさは相性が良さそう!

f:id:kakku22:20161114194007p:plain