初めてのDocker&ECS

ちょっとDockerを勉強してみたついでにまとめました。

前提知識

スライド作りました。良ければ見てください。

speakerdeck.com

実際にやってみる

参考:Amazon ECS における Docker の基本

Dockerイメージ作成用のEC2インスタンスの作成

1. EC2インスタンスの起動

  • AMIはAmazon Linux 2を使う
  • 自動割り当てパブリックIPは有効化にする
  • SGは最低でも22番と80番を許可しておく

2. Dockerのインストール

Ⅰ. 起動したEC2インスタンスssh接続したら「yum update」を行う。

$ sudo yum update -y

Ⅱ. Dockerをインストールする。

$ sudo amazon-linux-extras install docker

Ⅲ. Dockerを起動する。

$ sudo systemctl start docker.service

Ⅳ. ec2-userをdockerグループに追加する。これをやるとsudoを使用せずにDockerコマンドを実行できる。

$ sudo usermod -a -G docker ec2-user

Ⅴ. 一度ログアウトし、もう一度ssh接続して下記コマンドを実行する。Dockerの環境情報が出力されればOK(Ⅳを実行したことでsudo無しでコマンド実行できるようになった)。

$ docker info

※Dockerの環境情報を表示される。

Dockerイメージの作成

  1. ディレクトリを作成する。
$ mkdir docker_test
$ cd docker_test

Ⅱ. 下記3つのファイルを作成する。

  • ファイル名:dockerfile
FROM php:8-apache
COPY php.ini /usr/local/etc/php/
COPY index.php /var/www/html/

※補足

FROM php:8-apache

dockerhubにあるphp:8-apacheというイメージを取得するという意味。このイメージを用いるとPHP8とapacheがインストールされたコンテナが立ち上げる。

COPY php.ini /usr/local/etc/php/ COPY index.php /var/www/html/

PHP8とapacheをインストールしたら /usr/local/etc/php/ 配下に php.ini/var/www/html/ 配下に index.php をコピーするという意味。

  • ファイル名:index.php
<?php echo 'Hello World'; ?>
  • ファイル名:php.ini
[Date]
date.timezone = "Asia/Tokyo"
[mbstring]
mbstring.internal_encoding = "UTF-8"
mbstring.language = "Japanese"

Ⅲ. DockerfileからDockerイメージを作成する。

$ docker build -t hello-world .

-t :Dockerイメージの名前

※Dockerイメージが作成されたかは下記コマンドで確認できる

$ docker images

Ⅳ. Dockerイメージを実行する。上手く動作すればコンテナIDが出力される。

$ docker run -d -p 80:80 --name hello-world hello-world:latest

-d:コンテナをバックグラウンドで実行し、コンテナ ID を表示

-p:ポートマッピング

--name:コンテナの名前

Ⅴ. 起動したインスタンスのパブリックIPにアクセスし、「Hello World」と表示されたらOK。

Ⅵ. 実行したDockerイメージを停止する。コンテナIDはⅣで出力されているもの。

$ docker stop <コンテナID>

Ⅶ. 起動したインスタンスのパブリックIPにアクセスし、「Hello World」と表示されなくなっている事を確認する。

DockerイメージをECRへプッシュ

1. IAMロールの作成

  • AmazonEC2ContainerRegistryPowerUserをアタッチしたIAMロールを作成する。
  • Dockerイメージ作成用のEC2インスタンスにこのロールをアタッチする。
  • これによりEC2インスタンスからDockerイメージをECRへプッシュできるようになる。

2. ECRの作成

Ⅰ. AWSのサービス一覧から「ECR」を選択する。

Ⅱ. 「リポジトリの作成」を押す。

Ⅲ. リポジトリ名を入力しリポジトリの作成を押す。

Ⅳ. 作成されたリポジトリを選択し「プッシュコマンドの表示」を押す。

Ⅴ. プッシュコマンドが表示されるのでEC2インスタンス上で順番に実行する。実行例も載せておきます。

Ⅵ. AWSコンソール画面に戻ってリポジトリ名をクリックしDockerイメージがプッシュされていることを確認できればOK。

Ⅶ. プッシュされたDockerイメージをクリックしイメージURI予めコピーしておく。(タスク定義の作成で使用します。)

タスク定義の作成

Ⅰ. AWSのサービス一覧からECSを選択する。

Ⅱ. タスク定義を押す。

Ⅲ. 新しいタスク定義の作成を押す。

Ⅳ. EC2を選択して次のステップ

Ⅴ. 「タスク定義名」を入力(故なきは例としてhello-worldにしました)

Ⅵ. 下にスクロールしてコンテナの定義から「コンテナの追加」を押す。

Ⅶ. 下記項目を入力する。

コンテナ名 *:hello-world(任意)
イメージ *:2.ECRの作成のⅦでコピーしたイメージURIを貼り付ける
メモリ:128M(任意)
ポートマッピング:ホストポート 80、コンテナポート 80
CPUユニット:1

Ⅷ. 入力が終わったら適用を押す。

Ⅸ. タスクとコンテナの定義の設定の画面に戻るので「作成」を押す。

Ⅹ. 「タスク定義が正常に作成されました」と表示されればOK。

クラスターの作成

Ⅰ. Amazon ECSのクラスターを押す。

Ⅱ. クラスターの作成を押す。

Ⅲ. 「EC2 Linux + ネットワーキング」を選択して「次のステップ」を押す。

Ⅳ. 下記入力例を参考に埋めていく。

クラスター名*:hello-world
EC2 インスタンスタイプ*:t2.micro
インスタンス数*:1
キーペア:任意
ネットワーキング:必要に応じてVPCやSG等を設定する。この辺はEC2作成するのと同じ要領でやればOK。

Ⅶ. 入力が完了したら作成を押す。するとクラスターの作成が始まる(1分ほどかかる)。

Ⅷ. 全て正常に実行されたら「クラスターの表示」を押す。

Ⅸ. 「タスク」を押し、「新しいタスクの実行」を押す。

Ⅹ. 下記項目を入力する。

起動タイプ:EC2
タスク定義:hello-world:1
タスクの数:1

Ⅺ. 入力が終わったら「タスクの実行」を押す。

Ⅻ. 下記のように状態が「RUNNING」になっていればOK。

動作確認

Ⅰ. 「ECSインスタンス」をクリックするとコンテナが起動されているEC2インスタンスが表示される。

Ⅱ. インスタンスIDをクリックしてパブリックIPにアクセスし「Hello World」と表示されていればOK。

Ⅲ. ECSインスタンスssh接続してみる。

Ⅳ. コンテナ情報が出力されることを確認する。

$ docker ps

Ⅴ. Dockerのコンテナの中に入ってみる

$ docker exec -it <CONTAINER ID> /bin/bash

/var/www/html に移動すると index.php があることを確認できる。

後片付け

Ⅰ. 作成したクラスターを削除する。

Ⅱ. 作成したタスクを選択し登録解除のボタンを押す。

Ⅲ. Dockerイメージ作成用のEC2インスタンスの作成を削除する。

AWS CloudShell が実装されて個人的に嬉しかったこと

f:id:kikuchi_et_al:20210309030822p:plain

AWS CloudShell とは

aws.amazon.com

本日、AWSAWS CloudShell をローンチしました。これは、AWS 対応のシェルプロンプトの作業を簡単かつセキュアにし、できるだけ手間を少なくすることを目的としたものです。CloudShell で実行するすべてのシェル環境には、AWS コマンドラインインターフェイス (CLI) (v2) がインストールおよび設定されており、AWS のコマンドを即座に実行できます。環境には Python と Node のランタイムも含まれ、今後さらに多くのランタイムを追加する予定です。

コンソール画面上からターミナル画面を起動出来て CLI の実行が出来る機能です。Google Cloud にもあったやつですね。

AWS re:Invent 2020 で発表され、今のところ(2021年3月現在)、米国東部 (バージニア北部)、米国東部 (オハイオ)、米国西部 (オレゴン)、欧州 (アイルランド)、およびアジアパシフィック (東京) リージョンで利用できます。

個人的に AWS CloudShell が実装されて嬉しい点は下記の2つです。

1. 認証情報を設定する必要がない

2. AWS CLI 等のツールをインストールしておく必要が無い

1. 認証情報を設定する必要がない

管理しているアカウントの数が少なければ大したことないのですが、監視業務を行なっている現場では多数の AWS アカウントにログインする必要があり、AWS CLI を使用する場合は都度認証情報を切り替える必要がありました。

もちろん direnv 等便利なツールは存在しますが、1日で多くの AWS アカウントを行った来たりしていると対象アカウントを間違えてコマンドを実行してしまう…等といった危険がありました。

CloudShell を用いれば認証情報を端末に設定する必要が無く、コンソール画面にログインをすれば AWS CLI 等を実行できる環境が手に入ります。

もちろんログインする AWS アカウントを間違えてしまうと元も子もないですが… AWS アカウントへのログイン方法は各社工夫がされていると思いますので、認証情報の切り替え間違えよりはリスクが低いのかなと個人的には考えています。

2. AWS CLI 等のツールを事前にインストールしておく必要がない

AWS CLI には現状バージョン1と2が存在しており、当たり前ですがバージョン1がインストールされている環境ではバージョン2で記述されたコマンドは実行されません。

つまり夜間対応等をMSP部隊にお願いする際は、対応者の端末にインストールされている AWS CLI のバージョンをあらかじめ調べておく必要があったり、チーム内でバージョンを統一しておく必要がありました。

AWS CloudShell を用いれば AWS CLI は既にインストールされているので、上記のような懸念を無くすことができ、また常に事前に想定された環境で CLI を実行することが可能になります。

さらに使用するスクリプトによっては jq コマンドを使ったりするケースもあると思うのですが、こういったものも既にインストールされているのでとても頼もしいです。

ランタイム – Python およびノードランタイムに加えて、BashPowerShell、jq、git、ECS CLI、SAM CLI、npm、pip は既にインストールされており 、ご利用いただけます。

注意点

AWS CloudShell はデフォルトでは AdministratorAccess や PowerUerAccess のポリシー、もしくは AWSCloudShellFullAccess ポリシーを割り当てても利用できます。

反対に、明示的に AWS CloudShell を使えないようにするには以下のポリシーを割り当てる必要があります。

{
    "Version": "2012-10-17",
    "Statement": [{
        "Sid": "DenyCloudShell",
        "Effect": "Deny",
        "Action": [
            "cloudshell:*"
        ],
        "Resource": "*"
    }]
}

docs.aws.amazon.com

また、現状だと実行ログを CloudWatch Logs に転送する機能は無いため、監査が厳しい案件では使用は出来なさそうです。(むしろ使用出来ないようにしておいた方が良いかもですね。)

障害対応の時に一番大事にしていること

f:id:kikuchi_et_al:20210228191108p:plain

障害対応を行う時、復旧対応よりもまずは素早くお客様に連絡することが大事であると僕は考えています。

2021年2月20日(日本時間)0時過ぎにAWSで障害が発生しました。

7:09 AM PST 現在、東京リージョン AP-NORTHEAST-1 のひとつのアベイラビリティゾーン apne1-az1 において、インスタンスに影響を及ぼす接続性の問題が発生しており、対応を行っております。 | We are investigating connectivity issues affecting instances in a single Availability Zone (apne1-az1) in the AP-NORTHEAST-1 Region.

https://status.aws.amazon.com/

東京リージョンの一部のAZで障害が発生し、インスタンスがダウンもしくは起動しなくなるといったことが発生しました。

このレベルの障害が発生すると監視業務を行なっている現場ではアラートを100件以上検知し、障害対応に追われることになります。

少し誤解を生むような言い方にはなりますが、障害対応を行う際は復旧完了時間が少し遅くなったとしても、お客様への報告は優先的に行う方が良いです。

対応を優先し報告を後回しにすると、復旧作業がが行われているのかどうかがお客様からは見えず不安になるからです。

分かっていても意外と盲点で、復旧を優先させてお客様への連絡を怠るケースは新米エンジニアのあるあるかなと思います。

また、お客様に障害報告する時は調査内容等といったことは記載する必要はないです。

今起きてることを端的に伝え、詳細な内容は障害対応が一通り終わってから報告すれば良いです。

そして、復旧に時間がかかる時は1時間にに1回程度でも良いので経過報告するとお客様側でも状況を把握することが可能になるので安心感を与えることが出来ます。

新入社員研修について考える

f:id:kikuchi_et_al:20210130232716p:plain

はじめに

最近は新入社員の研修を任されることが多くなってきました。

新入社員の中には未経験の方もいればプログラミングスクール出身の方など様々な人がいます。

これからも研修を行うことがあると思うので今後自分がいつでも見返せるように、研修で取り組んだこと等をまとめました。

研修の目的

OJT研修を始める前に最低限の基礎知識を身につけてもらい、現場配属後スムーズに研修を行えるようにすること。

やったこと

僕の部署では主にAWSを用いたインフラの運用保守を行なっているので

  • 一般的なITスキル
  • AWSに関する基礎知識
  • 自社サービス内容に関する理解
  • インシデントもしくはイレギュラー発生時

こういった内容を2週間(80時間)かけて教育しています。


一般的なITスキル

  • ITの基礎
    • サーバーとは、OSとは、アプリとは何か
    • 絶対パス相対パスの違い
    • パーミション
    • 公開鍵認証
  • Linuxの基本コマンド
    • ls
    • cd
    • mkdir
    • cp
    • mv
    • ssh
    • grep
    • オプション
    • パイプライン
  • ネットワークに関する最低限の知識

AWSに関する基礎知識

  • オンプレとの違い、クラウドを使うメリット
  • 責任共有モデル
  • AWSの主なサービスに関して
    • VPC(説明するのが難しいので事前に資料を用意しておくこと)
    • EC2
    • SG
    • ELB
    • RDS
    • CloudWatch
    • IAM
  • AWSサポートに関して
    • 問い合わせ時の注意点
    • 上限緩和申請
    • 暖気申請

自社サービス内容に関する理解

  • MSPとは
  • 自社で発行しているホワイトペーパーの内容を解説
  • SLA/SLOについて
  • アラート検知してから報告するまでの流れ
    • どういったツールを用いて業務を行なっているのか
  • 顧客からくる依頼内容について
  • スケールアップ/ スケールダウン
  • スケールイン/スケールアウト

インシデントもしくはイレギュラー発生時

  • インシデントは何か
  • どういった所でインシデントは発生しやすいのか
  • インシデントを発生させないための工夫
  • もしインシデントを起こしてしまったら
  • AWS等のサービスで大規模障害発生時の動き方

研修をやる上で気をつけているポイント


理論的に説明するように心がける

例えばスケールアウト/インというものはそれぞれ

こういった意味を持っているのですが、未経験者の多くはこれを反対に理解している人が多いです。(アウトという言葉からなんとなくインスタンスを減らすような意味を連想してしまうから…?)

こういったことを教育する際、スケールアウトは台数を増やすこと、スケールインは台数を減らすこと、というようにただ記憶させるような教え方はしないように気をつけています。

その理由としては入社したての頃は研修で大量にインプットが行われるため、全てを記憶してもらうようなやり方で教育を行うとパンクしてしまい、知識が定着しない可能性があるからです。

上記の例ではアウト/インの語源に関してまず教え、身近なものの例を使っ説明すると良く理解してくれます。

例)

  • スケールアウト
    • "アウト"は「外に」といった意味がある
    • ズームアウトの"アウト"と同じ意味
    • ズムーアウトすることで画角が外側に広がる -> 台数が多くなる

学んだことをアウトプットしてもらう

何度か説明しても理解してもらえない時はメモ帳に今自分が理解していることを書いてもらうようにしています。

これをする理由は、相手が今どこまで理解していて何が分かっていないのかを教育者側が理解するためです。

メモ帳にアウトプットしてもらったら足りていない知識をインプットさせ、その内容をメモに追記してもらいます。

こうすことで知識の整理が行われ内容を理解してもらいやすくなるのでおすすめです。


難しい内容はを2日間に分けて説明する

難しいことを一発で理解してもらえることはなかなか少ないです。

なのでそういった内容を教える時は1日目で広く浅く教えて、2日目に難しく感じたところをヒアリングし、その箇所に関して重点的に教えていくようなやり方を行いました。

2日間に分けることで1日目で教えた内容に関して相手が何を理解していないのかを分析することが出来るのでおすすめです。


質問されたけど自分には分からないものは素直に分からないと言う

研修をする上で自分が全てを理解していないといけないと思いがちですが、その必要はないと僕は考えてます。

むしろ自分が分からないことにも関わらず、てきとうな内容を教えてしまうほうがいけないことです。

分からない時は素直に分からないと言い、後日自分で調べるかもしくはその分野に関して詳しい人を呼ぶ等をするべきです。

AWS Backupの設定およびBackupジョブ失敗時の通知設定方法

この記事は

今年の1月にAWS Backupの機能がアップデートされ、AMIも自動で取得できるようになりました。

この記事ではタイトルにも記載されている通り、AWS Backupの設定およびBackupジョブ失敗時の通知設定方法を紹介します。

また、手順にも記載されておりますがBackupジョブの通知先としてSNSを設定する際、現状CLIを使った操作が必ず必要になるので注意してください。

①. Backupジョブ失敗時の通知先となるSNSトピックを作成

①-1. SNSトピックを作成

f:id:kikuchi_et_al:20200524215301p:plain

①-2. JSONエディタを編集

SNSのARN(2箇所あるので注意)AWSアカウントID の箇所は適宜置き換えること。 SNSのARNは arn:aws:sns:リージョン名:AWSアカウントID:SNSトピック名

{
    "Version": "2008-10-17",
    "Id": "__default_policy_ID",
    "Statement": [
        {
            "Sid": "__default_statement_ID",
            "Effect": "Allow",
            "Principal": {
                "AWS": "*"
            },
            "Action": [
                "SNS:Publish",
                "SNS:RemovePermission",
                "SNS:SetTopicAttributes",
                "SNS:DeleteTopic",
                "SNS:ListSubscriptionsByTopic",
                "SNS:GetTopicAttributes",
                "SNS:Receive",
                "SNS:AddPermission",
                "SNS:Subscribe"
            ],
            "Resource": "SNSのARN",
            "Condition": {
                "StringEquals": {
                    "AWS:SourceOwner": "AWSアカウントID"
                }
            }
        },
        {
            "Sid": "__console_pub_0",
            "Effect": "Allow",
            "Principal": {
                "Service": "backup.amazonaws.com"
            },
            "Action": "SNS:Publish",
            "Resource": "SNSのARN"
        }
    ]
}

②. バックアップボールトの作成

②-1. AWS Backupのコンソールへ移動

②-2. バックアップボールトを作成

f:id:kikuchi_et_al:20200524215325p:plain


f:id:kikuchi_et_al:20200524215338p:plain

②-3. AWS CLI を使用して、-backup-vault-events を BACKUP_JOB_COMPLETED に設定して put-backup-vault-notifications コマンドを実行

現状、コンソール画面から設定する手段が無いため、CLIを使って操作する必要があります。

  • endpoint-url: バックアップボールトがある AWS リージョンのエンドポイントを入力 ※東京リージョンなら https://backup.ap-northeast-1.amazonaws.com
  • backup-vault-name: バックアップボールトの名前を入力
  • sns-topic-arn: 作成した SNS トピックの ARN を入力
aws backup put-backup-vault-notifications --endpoint-url https://backup.eu-west-1.amazonaws.com --backup-vault-name examplevault --sns-topic-arn arn:aws:sns:eu-west-1:111111111111:exampletopic --backup-vault-events BACKUP_JOB_COMPLETED

※公式ドキュメントから引用

②-4. get-backup-vault-notifications コマンドを実行し、SNSの設定が反映されていることを確認

  • backup-vault-name: バックアップボールトの名前を入力
aws backup get-backup-vault-notifications --backup-vault-name examplevault

以下のように出力されればOKです。

{
    "BackupVaultName": "examplevault",
    "BackupVaultArn": "arn:aws:backup:eu-west-1:111111111111:backup-vault:examplevault",
    "SNSTopicArn": "arn:aws:sns:eu-west-1:111111111111:exampletopic",
    "BackupVaultEvents": [
        "BACKUP_JOB_COMPLETED"
    ]
}

※公式ドキュメントから引用

③. サブスクリプションの作成

③-1. SNSのコンソールへ移動後、①で作成したSNSトピックをクリック

③-2. サブスクリプションの作成を押す

f:id:kikuchi_et_al:20200524215359p:plain

③-3. 詳細箇所を入力する

  • トピック ARN:①で作成したSNSトピックを選択

プロトコル、エンドポイントは通知先に応じて適宜変更してください。 エンドポントにDatadogのWebhook URLを指定すると、Backupジョブの失敗通知をDatadogで受け取ることができます。

■参考記事:Datadog で AWS SNS を受け取る (RDS/ElastiCacheイベント)

今回はメールで失敗通知の受信を行います。

③-4. サブスクリプションフィルターポリシーに下記を貼り付ける

{
  "State": [
    {
      "anything-but": "COMPLETED"
    }
  ]
}

f:id:kikuchi_et_al:20200524215418p:plain

④. AWS Backupの構築

④-1. AWS Backupのコンソールへ移動

④-2. 「バックアッププランを作成」を押す

f:id:kikuchi_et_al:20200524215431p:plain

④-3. 「新しいプランを立てる」を押し、バックアッププラン名を入力

f:id:kikuchi_et_al:20200524215447p:plain

④-4. スケジュールを設定

下記設定で毎日、06:00 AM 〜 07:00 AM (JST) の間にAMI取得が開始される。

f:id:kikuchi_et_al:20200524215512p:plain

④-5. ライフサイクル設定

以下の設定でBackup世帯数が2になる。バックアップボールトには②で作成したものを選択すること。

f:id:kikuchi_et_al:20200524215530p:plain

④-6. 「リソースを割り当てる」を押す

f:id:kikuchi_et_al:20200524215543p:plain

④-7. リソースを割り当てる

今回はタグで管理してます。インスタンスIDを直接指定することも可能です。

f:id:kikuchi_et_al:20200524215606p:plain

④-8. Backupを取得したい対象リソースに対してタグを付ける

f:id:kikuchi_et_al:20200524215622p:plain

これで設定は完了です。

⑤. Backupジョブ失敗の通知テスト

※公式ドキュメントから引用

⑤-1. 保護されたリソースからオンデマンドバックアップの作成を押す

f:id:kikuchi_et_al:20200524215639p:plain

⑤-2. 設定を行いオンデマンドバックアップを作成を押す

ここの設定画面で大事な箇所は以下の2点

  • 今すぐバックアップを作成
  • バックアップボールトを②で作成したものにする

f:id:kikuchi_et_al:20200524215654p:plain

⑤-3. バックアップジョブが実行されるのを確認

⑤-4. もう一度オンデマンドバックアップを作成を押す(設定もさっきと同じでOK)

f:id:kikuchi_et_al:20200524215709p:plain

⑤-5. 今度はバックアップジョブ IDをクリック

f:id:kikuchi_et_al:20200524215724p:plain

⑤-6. 停止を押す

f:id:kikuchi_et_al:20200524215736p:plain

⑤-7. ステータスが「中止しました」になることを確認

⑤-8. 停止したジョブの方のみ通知がきていることを確認

ジョブを停止してから約8分後に通知が届きました。

f:id:kikuchi_et_al:20200524215754p:plain

おまけ

AWS Backupで作成したAMIを削除するには

バックアップボールトから②で作成したものを選択

f:id:kikuchi_et_al:20200524220027p:plain

作成したAMIを選択し削除を押す

f:id:kikuchi_et_al:20200524220040p:plain

実際にAMI Backupの取得に失敗した際に通知される内容

AMI Backupの取得が実際に失敗すると下記のように、 An AWS Backup job failed. というメッセージが通知されるようです。

An AWS Backup job failed. Resource ARN : arn:aws:ec2:*****:*****:instance/*****. BackupJob ID : *****

AWS Elastic BeanstalkでEBSボリュームを暗号化するには?

背景

現状Elastic Beanstalkのサービスとして、EBSを暗号化するための設定を行う機能はありません。

EBSを暗号化するには下記のうち、どちらかの方法をとる必要があります。

(1) EBSボリュームがデフォルトで暗号化されるよう設定する

(2) Elastic Beanstalk環境用のAMI から、EBSボリュームに対して暗号化の設定を行なったカスタムAMIを作成し、そのAMIを使用する

今回は(1)の方法を使ってEBSを暗号化する方法を紹介します。

この方法の注意点としてはデフォルト暗号化を有効化すると、以降設定したリージョン内で構築されるEBSが全て暗号化されます。

手順

KMSを作成する

デフォルトKMSキーを使用する場合はこの手順は飛ばして問題ないです。

※デフォルトKMSキーを使用すると暗号化したスナップショットをAWSアカウント間でコピーが行えなくなるので注意

カスタマーキーを作成する際、注意点としてオートスケーリングで使用するサービスロールからKMSへのアクセス許可をキーポリシーで明示しておく必要があります。

Elastic Beanstalkはオートスケーリングを使ってEC2を起動するため、サービスロールがKMSへのアクセスができないとEC2が起動できずターミネートされてしまいます。

f:id:kikuchi_et_al:20200427010740p:plain

キーポリシー例

{
    "Id": "key-consolepolicy-3",
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "Enable IAM User Permissions",
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::アカウントID:root"
            },
            "Action": "kms:*",
            "Resource": "*"
        },
        {
            "Sid": "Allow use of the key",
            "Effect": "Allow",
            "Principal": {
                "AWS": "オートスケーリングのサービスロール"
            },
            "Action": [
                "kms:Encrypt",
                "kms:Decrypt",
                "kms:ReEncrypt*",
                "kms:GenerateDataKey*",
                "kms:DescribeKey"
            ],
            "Resource": "*"
        },
        {
            "Sid": "Allow attachment of persistent resources",
            "Effect": "Allow",
            "Principal": {
                "AWS": "オートスケーリングのサービスロール"
            },
            "Action": [
                "kms:CreateGrant",
                "kms:ListGrants",
                "kms:RevokeGrant"
            ],
            "Resource": "*",
            "Condition": {
                "Bool": {
                    "kms:GrantIsForAWSResource": "true"
                }
            }
        }
    ]
}

※躓きメモ 僕は最初Elastic Beanstalkのサービスロールをキーポリシーで許可していました。

何度やってもEC2が立ち上がらず苦戦していたのですが、「どのサービスがEC2を起動しているのか?」を考えたら分かりました。

Elastic Beanstalkはオートスケーリングの設定を行う所までしか関与して良いないので、オートスケーリング側に対してKMSへのアクセス許可を与えてあげる必要があります。

EBSのデフォルト暗号化設定

KMSを作成したらEC2が起動する際にEBSがデフォルトで暗号化されるようにします。

EC2のダッシュボード画面から「設定」を押してください。

f:id:kikuchi_et_al:20200427010804p:plain

設定画面が表示されるので以下のように設定してください。デフォルトKMSキーを使用する場合は「(デフォルト)aws/ebs」というものをデフォルトの暗号化キーで指定してください。

f:id:kikuchi_et_al:20200427010819p:plain

Elastic Beanstalkを使って環境を作成する

これで準備は完了です。特にElastic Beanstalk側で設定を変更する必要は無いです。いつも通りのやり方でElastic Beanstalkを使って環境を作成すればEBSが暗号化された状態で構築されます。

まとめ

Elastic BeanstalkでEBSを暗号化するには現状だと少し工夫が必要になります。

カスタムAMIを作成して暗号化を行う方法だと別途AMIの作成を行う必要があるため工数がかかりますが、デフォルト暗号化を使った方法だと簡潔に実現できます。

カスタムAMIを作成する方法はいずれまた別の記事として投稿しようかなと考えてます。

Beanstalkで使用されるEC2のSGの設定を変更するには?

背景

Beanstalk を使用してWindowsサーバーを構築し、 RDP 接続も行えるようにしたい。

RDP 接続を行うためには EC2 のキーペア(秘密鍵)がログインパスワードを取得するのに必要になる。

Beanstalk の設定画面で「 EC2 キーペア」を有効にすると、 Beanstalk (正確に言うと CloudFormation )によって自動生成されるセキュリティグループに22番ポートが 0.0.0.0/0 で許可される。

やりたかったこと

Beanstalk によって自動で作成されるセキュリティグループだと22番ポートがフル解放されるため、これを使わずに予め自分で作成しておいたセキュリティグループのみ使って構築したい。

試したこと

Beanstalk の設定画面にある「インタンスの変更」の「インスタンスセキュリティグループ」で、既存のセキュリティグループを選択すれば自動でセキュリティグループは作成されないと考えていた。 f:id:kikuchi_et_al:20200419225217p:plain

結果

「インタンスの変更」で選択した既存のセキュリティグループと、Beanstalk によって自動で作成されたセキュリティグループが使用された。

次に試したこと

Beanstalk はアプリケーションをデプロイする際に ebextensions を追加することで、Beanstalk のコンソール画面からでは設定できない項目もカスタマイズすることができる。

ebextensions に既存のセキュリティグループのみを使って構築するような設定を記載すれば、やりたいことが実現できると考えていたが、これはどうやらできないらしい。

22番ポートをフル解放させないためには

Beanstalk の仕様上セキュリティグループが必ず作成されてしまい、キーペア使用すると22番ポートがデフォルトではフル解放される。

作成されたセキュリティグループは必ず使用されてしまうので、 22番ポートが許可されたセキュリティグループを使わないという考えから、22番ポートの許可設定を変更しセキュリティリスクを下げるという考えにシフトする必要がある

下記 ebextensions を追加することで22番ポートの許可設定を変更することができる。

option_settings:
  - namespace:  aws:autoscaling:launchconfiguration
    option_name: SSHSourceRestriction
    value: tcp, 22, 22, 127.0.0.1/32

この ebextensions を追加してデプロイすると、 Beanstalk の設定画面で「 EC2 キーペア」を有効にしても22番ポートが 127.0.0.1/32 の IP のみ、つまり自分自身の IP のみ通信を許可するような設定にすることができる。

これにより、不用意に22番ポートをフル解放せずに構築を行うことができる。

結論

EC2 で使用されるセキュリティグループは Beanstalk によって自動で作成される、予め自分で用意したセキュリティグループのみ使って構築するということはできない。

自動で作成されるセキュリティグループの中身は Beanstalk の設定画面で「 EC2 キーペア」を選択すると22番ポートが 0.0.0.0/0 で許可される。

作成されたセキュリティグループは必ず使用されてしまうので、22番ポートの許可設定をオーバライドするような ebextensions を追加する必要がある。

そもそも、インスタンスにログインしないように構築することがベストではあるが、お客様の要件によっては必要になるケースも存在すると思い記事を投稿した。

因みに ELB であれば Beanstalk によって自動で作成されるセキュリティグループを使わずに、既存のセキュリティグループを使用するような設定を行うことができる。 参考:https://aws.amazon.com/jp/premiumsupport/knowledge-center/security-group-elastic-beanstalk/