AWSの部屋

AWS学習者向けのブログです

スポンサーリンク

KMS を使ってデータの暗号化と復号化をしてみる

はじめに

機密性の高いデータを運用するには、暗号化の施策が必要になります。その際に重要になるのが、暗号化や復号化のための鍵の管理です。今回は KMS を使ってデータの暗号化と復号化をしてみようと思います。

KMS とは

AWS Key Management Service のことで CMK(カスタマーマスターキー)を管理して、データキーを生成・暗号化・復号するなど、暗号化に必要なキー管理、キーオペレーションを提供するマネージドサービスです。

対称暗号化とは

KMS は対称暗号化と非対称暗号化をサポートしており、今回は対称暗号化について書きます。対称暗号化では一つのデータキーを使った暗号化と復号を行います。

KMS の機能

機能 用途
Encrypt データの暗号化
Decrypt データの復号化
GenerateDataKey ユーザがデータを暗号化するための CMK を生成

CMK(カスタマーマスターキー)と CDK(カスタマーデータキー)

CMK は CDK を暗号化するための鍵で、CDK はデータを暗号化するための鍵です。KMS では CDK でデータを暗号化してから、CDK を CMK で暗号化する手法をとっています。これは CDK の保護のためで、この手法はエンベロープ暗号化と言われています。

KMS を使った暗号化

以下の順番でデータの暗号化を行います。
1. CMK を使って暗号化されている CDK と暗号化されていない CDK を作成する
2. 暗号化されていない CDK を使ってデータを暗号化する
3. 暗号化されていない CDK を削除する

KMS を使った復号化

以下の順番でデータの復号化を行います。
1. CMK を使って暗号化されている CDK を復号化する
2. 復号化された CDK を使って暗号化されているデータを復号化する

手順

  1. CMK の作成
  2. 暗号化
    1. CMK を使って暗号化されている CDK と暗号化されていない CDK を作成する
    2. 暗号化されていない CDK を使ってデータを暗号化する
    3. 暗号化されていない CDK を削除する
  3. 復号化
    1. CMK を使って暗号化されている CDK を復号化する
    2. 復号化された CDK を使って暗号化されているデータを復号化する

1. CMK の作成

キータイプを対称とします。

エイリアスを設定します。

キー管理者を設定します。

CMK が作成されました。

暗号化

1. CMK を使って暗号化されている CDK と暗号化されていない CDK を作成する

以下のように CMK に紐づく CDK を作成します。

aws kms generate-data-key --key-id arn:aws:kms:ap-northeast-1:xxxxxxxxxxxx --key-spec AES_256 

このような結果が得られます。

{
    "CiphertextBlob": "AQIDAH...",
    "Plaintext": "f6xFX4p...",
    "KeyId": "arn:aws:kms:ap-northeast-1:xxxxxxxxxxxxxxx:key/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
}
  • Plaintext・・・暗号化されていない CDK
  • CiphertextBlob・・・暗号化されている CDK

作成した CDK を保存します。

echo [Plaintext] > plain-data-key
echo [CiphertextBlob] | base64 --decode > encrypted-data-key
2. 暗号化されていない CDK を使ってデータを暗号化する

以下のデータを暗号化してみます。

[ec2-user@ip-10-0-1-245 ~]$ cat test-document
Welcome to Kamata!

暗号化されていない CDK を用いてデータを暗号化する。

openssl aes-256-cbc -e -in test-document -out encrypted-document -pass file:plain-data-key

このようにデータが暗号化されたことがわかります。

[ec2-user@ip-10-0-1-245 ~]$ cat encrypted-document
Salted__ク^・_~%?ステ黑゚鮱゚~ネ_マW-ヨ・@!蘋
3. 暗号化されていない CDK を削除する

暗号化されていない CDK (plain-data-key)を削除してください。

rm plain-data-key

3. 復号化

1. CMK を使って暗号化されている CDK を復号化する

暗号化されている CDK を復号化します。

aws kms decrypt --ciphertext-blob fileb://encrypted-data-key --output text --query Plaintext > decrypted-datakey
2. 復号化された CDK を使って暗号化されているデータを復号化する

暗号化されているデータを復号化します。

openssl aes-256-cbc -d -in encrypted-document -out decrypted-document -pass file:decrypted-data-key

このようにデータが復号化されたことがわかります。

[ec2-user@ip-10-0-1-245 ~]$ cat decrypted-document
Welcome to Kamata!

さいごに

KMS は AWS 認定試験において必ず出題されるサービスの一つで何となく理解したつもりでいたのですが、自分の中でモヤモヤする部分もありました。今回、実際に KMS を使うことによってサービスに対するイメージがより具体的になりました。次回は KMS とその他のサービスを連携させてみようと思います。

CloudWatch のログで特定の文字列を検出した際に Lambda と SNS でメール送信を行う

はじめに

システム運用時にエラーはつきものかと思いますが、そのエラーをいかに早く検知し対処を行うかが安定したシステム運用につながります。本日は CloudWatch に蓄積されたログから特定の文字列(エラーログに出力されている内容等)を自動で検出し、それをメールで通知するということをやってみます。

使用するサービス

  • Amazon CloudWatch・・・AWS リソースと AWS で実行するアプリケーションのモニタリングサービス
  • AWS Lambda・・・サーバーをプロビジョニングしたり管理しなくてもコードを実行できるコンピューティングサービス
  • Amazon Simple Notification Service (Amazon SNS)・・・モバイルプッシュ通知やSMS送信など様々なメディアに対応した分散型フルマネージド通知サービス

アーキテクチャ

本エントリーではログ内の「error」という文字列を検出しようと思います。

手順

  1. メール通知用 SNS トピックの作成
  2. Lambda 関数に割り当てるロールを作成
  3. SNS でメール送信を行う Lambda 関数の作成
  4. CloudWatch でサブスクリプションフィルタを作成
  5. 動作確認

1. メール通知用 SNS トピックの作成

こちらのエントリーを参照してください。

aws-room.hatenablog.com

2. Lambda 関数に付与するロールを作成

Lambda に対して以下のポリシーを割り当てたロールを作成します。

・CloudWatchLogsFullAccess
・AmazonSNSFullAccess

このようにロールを作成しました。

3. SNS でメール送信を行う Lambda 関数の作成

このような関数を作成します。(前工程で作成したロールを割り当てます)

以下のコードをデプロイします。

import base64
import json
import zlib
import datetime
import os
import boto3
from botocore.exceptions import ClientError

print('Loading function')


def lambda_handler(event, context):
    data = zlib.decompress(base64.b64decode(event['awslogs']['data']), 16+zlib.MAX_WBITS)
    data_json = json.loads(data)
    log_entire_json = json.loads(json.dumps(data_json["logEvents"], ensure_ascii=False))
    log_entire_len = len(log_entire_json)

    print(log_entire_json)

    for i in range(log_entire_len): 
        log_json = json.loads(json.dumps(data_json["logEvents"][i], ensure_ascii=False))

        try:
            sns = boto3.client('sns')
    
            #SNS Publish
            publishResponse = sns.publish(
                TopicArn = os.environ['SNS_TOPIC_ARN'],
                Message = log_json['message'],
                Subject = os.environ['NOTIFICATION_SUBJECT']
            )
    
        except Exception as e:
            print(e)

デプロイが完了したら環境変数を設定します。

キー
SNS_TOPIC_ARN SNSのトピックの ARN
NOTIFICATION_SUBJECT SNS で通知される際の件名

4. CloudWatch でサブスクリプションフィルタを作成

まず CloudWatch でこのようにロググループを作成します。

ログストリームも作成します。

Lambda サブスクリプションフィルターを作成します。

項目
Lambda 関数 前工程で作成したLambda 関数
ログの形式 JSON
ログの形式 検出する文字列・パターン

5. 動作確認

AWS CLI で CloudWatch にログを出力することができるので、以下のようにしてログを出力しました。

aws logs put-log-events --log-group-name Error --log-stream-name Error-log-stream --log-events timestamp=1653457849182,message="System error"

ログ出力後、このように SNS からメールが送信されることが確認できました。

さいごに

同じことを自分で実装しようと思ったら非常に大変な作業になると思いますが、AWS のようなクラウドのサービスを活用するとメールでのアラート機能を簡単に作ることができました。CloudWatch を初めてしっかりと使ってみたのですが、やはり自分で手を動かすことでサービスに対する理解が深まりますね。これからもどんどん色々なサービスを使っていこうと思います。

EC2 を使ってプロキシサーバを構築してみる

はじめに

本日は EC2 をプロキシサーバとして構築し、プライベートサブネット内のサーバからパブリックサブネットのプロキシサーバを経由してインターネットに接続してみようと思います。

使用するサービス

  • Amazon EC2・・・AWS が提供するコンピューティングプラットフォーム

アーキテクチャ

パブリックサブネットにプロキシサーバ(Squid をインストール)、プライベートサブネットに DBサーバを置く構成にします。

Squid とは

プロキシサーバ、ウェブキャッシュサーバなどに利用されているオープンソースソフトウェア。本日はプロキシサーバとして使用します。

手順

  1. ネットワーク・サーバ構築
  2. Squid のインストール
  3. Squid の設定
  4. DBサーバからプロキシサーバを経由するための設定
  5. 動作確認

1. ネットワーク・サーバ構築

以下のようにサブネット、ルートテーブルなどを作成しネットワーク・サーバを構築します。詳細は割愛しますが、ネットワーク・サーバ構築に関してはこちらの書籍がおすすめなのでぜひ読んでみてください。

<ルートテーブル>

ルートテーブル名 設定
public-route-table 10.0.0.0/16, 0.0.0.0/0
private-route-table 10.0.0.0/16

<サブネット>

サブネット名 ルートテーブル
public-subnet public-route-table
private-subnet private-route-table

<セキュリティグループ>

セキュリティグループ名 インバウンドルール
public-security-group ポート22,3128,80,443を許可(SSH,Squid,HTTP,HTTPSのポート)
private-security-group ポート22を許可(SSHのポート)

<EC2>

ホスト名 OS セキュリティグループ
proxy-server Amazon Linux 2 public-security-group
db-server Amazon Linux 2 private-security-group

2. Squid のインストール

以下コマンドで Squid をインストールします。

sudo yum install squid -y

Squid自動起動を有効にします。

sudo systemctl enable squid

3. Squid の設定

squid.conf(Squid の設定ファイル)を開きます。

sudo vi /etc/squid/squid.conf

設定ファイルに以下を追加します。

acl private-subnet src 10.0.2.0/24 # ADD for private-subnet
http_access allow private-subnet   # ADD access from private-subnet

Squid を再起動をします。

sudo service squid restart

4. DBサーバからプロキシサーバを経由するための設定

yumwget の設定ファイルにプロキシの設定をします(プロキシサーバを経由して、DBサーバから yumwget でインターネットにアクセスするために)。

まずはDBサーバの秘密鍵ファイルをプロキシサーバにアップロードし、以下のようにDBサーバに SSH 接続します。

ssh -i <秘密鍵ファイル名> ec2-user@DBサーバのプライベートIPアドレス
yum の設定

yum.conf を開きます。

sudo vi /etc/yum.conf

プロキシ設定を追加します。(Squid が使うポートを設定します)

proxy=http://<プロキシサーバのプライベートIPアドレス>:3128
wget の設定

wget の設定ファイルを開きます。

sudo vi /etc/wgetrc

プロキシ設定を追加します。(Squid が使うポートを設定します)

http_proxy=http://<プロキシサーバのプライベートIPアドレス>:3128/
https_proxy=http://<プロキシサーバのプライベートIPアドレス>:3128/
ftp_proxy=http://<プロキシサーバのプライベートIPアドレス>:3128/

5. 動作確認

yum

MariaDB をインストールしてみます。

sudo yum -y install mariadb-server

インストールすることができました。

wget

以下のWebサイトをダウンロードしてみます。

wget https://www.hatena.ne.jp/

Webサイトのダウンロードできました。

さいごに

パブリックサブネットに NATゲートウェイを構築すれば同じことをもっと簡単にできたとは思いますが、今回は勉強のためにあえて EC2 をプロキシサーバとして構築してみました(やはり手を動かして何かを作るのは楽しいですね)。AWS認定ソリューションアーキテクト-プロフェッショナル合格に向けて今後も色々なサービスを楽しみながら使っていこうと思います。

DynamoDB はじめの一歩

はじめに

AWS 認定試験を受けるにあたって避けては通れないサービスの一つが DynamoDB です。DynamoDB は NoSQL データベースということで何となく理解はしているものの実際に使ったことがなく、いまいちイメージが湧きませんでした。そういった経緯があり、今回のエントリーを機に DynamoDB を使ってみることにしました。

使用するサービス

  • Amazon DynamoDB・・・フルマネージド、サーバーレスの key-value NoSQL データベース

サービスに対する詳細な仕様の説明は本エントリーでは割愛しますので、こちらをご参照ください。

手順

  1. テーブルを作成
  2. データをテーブルにロード
  3. データにクエリを実行

1. テーブルを作成

今回はこちらのサイトで紹介されている ProductCatalog テーブルを作成してみます。
以下のような設定でテーブルを作成します。パーティションキーやソートキーについてはこちらをご参照ください。

項目 設定値
テーブル名 ProductCatalog
パーティションキー Id(数値)
ソートキー -

2. データをテーブルにロード

サンプルデータをダウンロードし、以下コマンドでデータをテーブルにロードします。

aws dynamodb batch-write-item --request-items file://ProductCatalog.json

ダウンロードしたデータの中で今回使用するのは以下の JSON です。

3. データにクエリを実行

DynamoDB コンソールで対象のテーブルでクエリを設定し、実行するボタンを押します。

このように結果が取得できます。

コマンドでのクエリの実行に関しては、こちらを参照してください。

さいごに

まだ初歩的な部分だけしか使っていないですが、これだけでも何となく DynamoDB の感覚が掴めた気がします。今後は他のサービスと組み合わせて DynamoDB を使っていこうと思います。

独自ドメインでSSL化した静的 Web サイトを S3 でホスティングしてみる

はじめに

本日は過去のエントリー(S3 で静的WebサイトをホスティングしてみるCloudFront を使用して S3 に格納された画像ファイルにアクセスしてみる)の発展として、独自ドメインSSL化(https)した静的 Web サイトを S3 でホスティングしてみようと思います。

使用するサービス

アーキテクチャ

少し複雑かもしれませんが、名前解決や SSL通信の流れがわかるかと思います。

今回使用する HTML ファイル

シンプルですが、以下の HTML ファイルを使ってみようと思います。

<html>
<head>
<meta charset="utf-8">
<title>AWSの部屋</title>
</head>
<body>
AWSの部屋へようこそ!
</body>
</html>

手順

  1. S3 に静的Webサイトをホスティング
  2. CloudFront を使用して静的Webサイトにアクセス
  3. ドメインを取得
  4. Route53でホストゾーンの作成
  5. ACMSSL証明書を発行する
  6. CloudFrontにSSL証明書を設定する
  7. Route53でDNSレコードを登録
  8. 動作確認

1. S3 に静的Webサイトをホスティング

以下のエントリーに一連の手順を記載していますのでこちらを参照してください。

aws-room.hatenablog.com

今回はこのようなWebサイトをホスティングします。

2. CloudFront を使用して静的Webサイトにアクセス

以下のエントリーに一連の手順を記載していますのでこちらを参照してください。

aws-room.hatenablog.com

3. ドメインを取得

お名前.comで「aws-room.com」というドメインを取得しました。

無料ドメインが欲しいという方はこちらのサイトを参考に取得してみてください。

4. Route53でホストゾーンの作成

ホストゾーンの作成をクリックします。

ドメイン名に取得したドメイン名を入力し、ホストゾーンの作成を押します。

登録をするとドメインに関連付けされたNSレコード4つとSOAレコードが表示されます(お名前.com側にNSレコードの設定が必要になります)。

ns-xxx.awsdns-51.net.
ns-xxx.awsdns-17.org.
ns-xxx.awsdns-53.com.
ns-xxx.awsdns-53.co.uk.

最後にお名前.comでネームサーバーの設定をします。こちらのサイトに手順がまとまっているので参考にしてください。

5. ACMSSL証明書を発行する

まず、リージョンを「米国東部 (バージニア北部) us-east-1」に変更する必要があるようです。(出典:AWS リージョン 用の AWS Certificate Manager

リージョンを「米国東部 (バージニア北部) (us-east-1)」に変更し、「証明書をリクエスト」を押します。

パブリック証明書をリクエストにチェックをして次へをクリックします。

ドメイン名を入力してリクエストをクリックします。

このように証明書が発行されました。

Route53にレコードを作成します(CNAMEレコードを作成します)。

6. CloudFront へ SSL証明書を設定する

CloudFront のディストリビューションを編集します。

発行されたSSL証明書を入力します。

7. Route53でDNSレコードを登録

Route53 で管理することになったドメインと、CloudFront+S3構築を紐づけるためのレコードを作成します。

シンプルルーティングを選択します。

「シンプルなレコードを定義」を押して以下を入力します。

レコードを作成ボタンを押します。(Aレコードを作成します)

8. 動作確認

作成したドメインにブラウザでアクセスすると Webサイトが表示されることが確認できました。

さいごに

今回は様々なサービスを使いましたが、無事目標を達成することができました。今までは座学でしか Route53 のことを理解していなかったのですが、実際に自分で手を動かして使ってみるとサービスに対する理解がより深まりました。まだまだ初歩的なことしか理解できていませんが、少しずつスキルを上げてAWS認定ソリューションアーキテクト-プロフェッショナル合格を目指していこうと思います。

API Gateway + Lambda + Amazon Translateを使って翻訳API を作成してみる

はじめに

筆者はAWS認定ソリューションアーキテクト-プロフェッショナル合格に向けて勉強中ですが、座学はあまり性に合わずできるだけ手を動かして勉強したいため、本ブログを通じて AWS の様々なサービスを使ってみようと思っています。今回は API Gateway、Lambda、Amazon Translate を使って 翻訳API を作成してみようと思います。

使用するサービス

  • Amazon API Gateway・・・API の作成、配布、保守、監視、保護が行えるサービス
  • AWS Lambda・・・サーバレスでコードを実行することが出来るサービス
  • Amazon Translate・・・AWS でサポートされている言語間で翻訳を行うサービス

構成

手順

  1. Amazon Translate を使った英語→日本語翻訳サンプルの作成
  2. Lambda に付与する IAMロールを作成
  3. Lambda関数を作成
  4. API Gateway の設定
  5. 動作確認

1. Amazon Translate を使った英語→日本語翻訳サンプルの作成

Boto3 を使って英語を日本語に翻訳するサンプルを作成します。翻訳する英語は今回「good morning」とします。

import boto3

translate = boto3.client('translate')

# good morning を日本語に翻訳
response = translate.translate_text(
    Text='good morning',
    SourceLanguageCode='en',
    TargetLanguageCode='ja'
)

output_text =response.get('TranslatedText')

print(output_text)

結果は以下のようになります。

このコードをベースにして後の工程で Lambda 関数を作成します。

2. Lambda に付与する IAMロールを作成

Lambda が Amazon Translate と連携できるように 以下のような手順でIAMロールを作成します(ロール名はLambda-Translate-Accessとしました)。

3. Lambda関数を作成

以下のコードで translate-en2ja という Lambda関数を作ってみます。

import json
import boto3

translate = boto3.client(service_name='translate')

def lambda_handler(event, context):

    input_text = event['queryStringParameters']['input_text']
    response = translate.translate_text(
        Text=input_text,
        SourceLanguageCode="en",
        TargetLanguageCode="ja"
    )

    output_text = response.get('TranslatedText')

    return {
        'statusCode': 200,
        'body': json.dumps({
            'output_text': output_text
        }),
        'isBase64Encoded': False,
        'headers': {}
    }

関数の作成を押します。

関数名に「translate-en2ja」と入力します。

「2. Lambda に付与する IAMロールを作成」で作成したロールを選択します。

ラムダ関数をデプロイします。

4. API Gateway の設定

今回は REST API を使ってみようと思います。API の名前は sanvarie-traslate-api とします。

REST API の「構築」ボタンを押します。

AP I名を sanvarie-traslate-api とします。

リソースを作成します。

「3. Lambda関数を作成」で設定した関数名を入力します。

メソッドリクエストを押します。

「URL クエリ文字列パラメータ」に「input_text」と入力します。

Lambda関数の画面を開くと API Gateway が設定されている事がわかります。

API をデプロイします。

デプロイ後にエンドポイントの URLが表示されます

5. 動作確認

エンドポイントの URL に以下のようなリクエストを送ってみます。

https://gj73t4j7rg.execute-api.ap-northeast-1.amazonaws.com/development/translate?input_text=good morning

「good morning」という文章に対して「おはよう」という翻訳結果が得られたことがわかります。

別の文章も試してみました。「I want to eat Sushi」という文章に対しても「お寿司が食べたい」という正しい翻訳結果が得られました。

さいごに

API Gateway を使うことによって API の作成が簡単にできることがわかりました。今回は翻訳の API でしたが、今後は AWS の他の機能と組み合わせて全然違う API も作ってみたいですね。

CloudFront を使用して S3 に格納された画像ファイルにアクセスしてみる

はじめに

筆者はAWS認定ソリューションアーキテクト-プロフェッショナル合格に向けて勉強中ですが、座学はあまり性に合わずできるだけ手を動かして勉強したいため、本ブログを通じて AWS の様々なサービスを使ってみようと思っています。今回は Cloudfront を使用して S3 に格納された画像ファイルにアクセスしてみようと思います。

Amazon CloudFront とは

Amazon CloudFront は、ユーザーへの静的および動的なウェブコンテンツ (.html、.css、.js、イメージファイルなど) の配信を高速化するウェブサービスです。CloudFront では、エッジロケーションというデータセンターの世界的ネットワークを経由してコンテンツを配信します。CloudFront でサービスを提供しているコンテンツをユーザーがリクエストすると、リクエストはエッジロケーションにルーティングされ、レイテンシー (遅延時間) が最小になります。これにより、コンテンツは可能な限り最高のパフォーマンスで配信されます。(出典:Amazon CloudFront とは何ですか?

今回のゴール

  • CloudFront 経由で S3 に格納された画像ファイルにアクセスする
  • 以下のように、S3への直接アクセスはせずに、CloudFront経由でのみ画像へのアクセスを許可する

[イメージ]

使用する画像

こちらのはねぴょんの画像を使用します。

手順

  1. S3 にバケットを作成
  2. S3 に画像ファイルをアップロードする
  3. 画像ファイルへの直接アクセスを確認
  4. CloudFrontディストリビューションを構築する
  5. 動作確認

1. S3 にバケットを作成

以下のバケットを作成します。

「パブリックアクセスをすべてブロック」のチェックを入れてバケットを作成してください。

2. S3 に画像ファイルをアップロードする

作成した S3 バケットを選択し、「アップロード」をクリックします。

ファイルを追加して「アップロード」をクリックします。

3. 画像ファイルへの直接アクセスを確認

オブジェクト URL にブラウザでアクセスします。

バケットのパブリックアクセスがブロックされていることが確認できます。

4. CloudFrontディストリビューションを構築する

以下のように設定しディストリビューションを作成します。

  • オリジナルドメイン・・・フィールドにフォーカスを当てると作成したバケットに対するドメインが選択できます。
  • 名前・・・オリジナルドメインを入力すると自動的に入力されます。
  • S3バケットアクセス・・・「はい、OAIを使用します」を選択します。
  • オリジナルアクセスアイデンティティ・・・新しいOAIボタンからOAIを作成します。
  • バケットポリシー・・・「はい、バケットポリシーを自動で更新します」を選択します。

このように CloudFrontディストリビューションが作成されます。

5. 動作確認

CloudFront経由で画像ににアクセスします。URLは以下のように設定します。今回の設定だと"https://d34ct53yaxe9lx.cloudfront.net/hanepyon.png"になります。

"CloudfrontDomainName"/"S3のファイル名"

このように画像にアクセスすることができました。

さいごに

AWS認定試験でも頻繁に出題される CrontFront ですが、実際に手を動かしてみると座学をするよりもイメージが湧きますね。今度は Route53 を使って独自ドメインからのアクセスにも挑戦してみようと思います。