- 投稿日:2019-07-27T18:18:10+09:00
AWS EC2インスタンスへのSSH接続の仕方
AWS EC2へのSSH接続の仕方
今更だが、AWSに触ったキッカケはServerlessアプリを作るところからだったのでEC2を使うのが始めてだったりする。備忘録。マイマシンはubuntu18.04です。
AWSでEC2インスタンスを作成
なんでもいいけど
"Ubuntu Server 16.04 LTS (HVM), SSD Volume Type - ami-bec974d8"で作成した。t2.microというタイプ。ウィザードは全部デフォルト。これだと月に10ドルくらい。
AWS 月額料金チートシート
最後に.pemファイルをダウンロードすること。キー名というのを設定するがそれがpemファイルの名前になるだけ。.pemファイルのアクセス権を変更
.pem ファイルを自分のマシンの適当な場所に移動して(たとえば~/pathフォルダなどを作る)、そこに対するアクセス許可を0777 ではなく 0400にする。
$ cd ~/ $ mkdir path $ mv ***.pem path $ chmod 400 pathsshで接続
以下のコマンド。
$ sudo ssh -i path/***.pem ubuntu@ec2-11-11-111-111.ap-northeast-1.compute.amazonaws.com@の前のデフォルトユーザ名は以下の通り。
https://docs.aws.amazon.com/ja_jp/AWSEC2/latest/UserGuide/connection-prereqs.html以下のようなレスポンスが来て、yesと答えると、
The authenticity of host 'ec2-111-11-111-1.compute-1.amazonaws.com (10.254.142.33)' can't be established. RSA key fingerprint is 1f:51:ae:. Are you sure you want to continue connecting (yes/no)?こう返ってくる。
Warning: Permanently added 'ec2-111-11-111-1.compute-1.amazonaws.com' (RSA) to the list of known hosts.https://docs.aws.amazon.com/ja_jp/AWSEC2/latest/UserGuide/AccessingInstancesLinux.html
プロンプトはこうなっているはず。繋がった。
ubuntu@ip-111-11-11-111:~$
rootユーザーになるには?
rootのパスワードは設定されていない。次のコマンドでrootになれる。
~$ sudo su -作業を終えたらexitコマンド。
ファイルをEC2へアップロードする
Googleのdebパッケージをアップロードするには下記のコマンド
sudo scp -i path/***.pem google-chrome-stable_current_amd64.deb ubuntu@ec2-1-111-11-111.ap-northeast-1.compute.amazonaws.com:/home/ubuntu
- 投稿日:2019-07-27T17:31:31+09:00
AWS Cloud9にSymfonyを構築する
テスト環境としてSymfonyが使える環境が欲しいと思い、Cloud9上に構築してみました。
今回構築したときの備忘録です。PHPのインストール
Cloud9のOSは、2019年7月時点でAmazon Linux2ではなく、以前のAmazon Linuxでした。
なので、amazon-linux-extras
は使えませんでした。$ cat /etc/system-release Amazon Linux AMI release 2018.03$ sudo yum -y update $ sudo yum -y install php72 php72-mbstring php72-pdo $ sudo unlink /usr/bin/php $ sudo ln -s /etc/alternatives/php7 /usr/bin/php $ php -v PHP 7.2.19 (cli) (built: Jun 12 2019 20:55:29) ( NTS ) Copyright (c) 1997-2018 The PHP Group Zend Engine v3.2.0, Copyright (c) 1998-2018 Zend Technologieshttps://qiita.com/kidatti/items/2d6a4a24f89dc71eb66e
Symfonyのインストール
$ wget https://get.symfony.com/cli/installer -O - | bash $ export PATH="$HOME/.symfony/bin:$PATH" >> .bash_profile $ sudo mv /home/ec2-user/.symfony/bin/symfony /usr/local/bin/symfony $ source .bash_profile $ symfony -v Symfony CLI version v4.6.2 (c) 2017-2019 Symfony SASComposerのインストール
$ php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');" $ php -r "if (hash_file('sha384', 'composer-setup.php') === '48e3236262b34d30969dca3c37281b3b4bbe3221bda826ac6a9a62d6444cdb0dcd0615698a5cbe587c3f0fe57a54d8f5') { echo 'Installer verified'; } else { echo 'Installer corrupt'; unlink('composer-setup.php'); } echo PHP_EOL;" $ php composer-setup.php $ php -r "unlink('composer-setup.php');" $ sudo mv composer.phar /usr/local/bin/composer $ composer -v ______ / ____/___ ____ ___ ____ ____ ________ _____ / / / __ \/ __ `__ \/ __ \/ __ \/ ___/ _ \/ ___/ / /___/ /_/ / / / / / / /_/ / /_/ (__ ) __/ / \____/\____/_/ /_/ /_/ .___/\____/____/\___/_/ /_/ Composer version 1.8.6 2019-06-11 15:03:05https://getcomposer.org/download/
http://symdoc.kwalk.jp/doc/book/installationSymfonyの起動
Cloud9では外部からアクセスできるポート番号が決まっているため、ポート番号を指定して起動する必要があります。
$ symfony new --full my_project $ cd my_project/ $ php bin/console server:start *:8080メニュー > Preview > Preview Running Applicationを押すと実行ページのプレビューが表示されます。
Symfonyの停止
$ php bin/console server:stop
(補足)アプリの状態をするコマンド
$ php bin/console about
- 投稿日:2019-07-27T17:28:11+09:00
手動で立ち上げた EC2 に ECS をつなぐ方法
EC2 で ECS を動かす記事をよく見ますが
ECS から設定された EC2 を立ち上げる記事はありますが
自分で立ち上げた EC2 から ECS に連携させる方法の記事が見つからなかったのでメモします
尚、個人的見解ですが、ECS やるなら Fargate 使うほうがおすすめです
EC2 にはパブリック IP が付与されているものとしますAMIを確認する
AWS で ECS 向けに最適化された AMI が公開されているので使います。
まずは、ECS用に最適化されたAMIの情報を確認します
https://docs.aws.amazon.com/ja_jp/AmazonECS/latest/developerguide/ecs-optimized_AMI.html
英語版のほうが更新が早いので英語版も念の為見ておくと良いです
https://docs.aws.amazon.com/AmazonECS/latest/developerguide/ecs-optimized_AMI.htmlECSを動かせるロールを作成
AmazonEC2ContainerServiceforEC2Role
ポリシーを付与した EC2 向けのロールを作成します
すでにロールがある場合は、ポリシーをアタッチしてくださいEC2の設定
EC2 の インスタンスの設定画面で
ECS を動かすのに必要なロールを付与高度な詳細をクリックして開き、
ユーザーデータの部分に以下を追記
HOGE_CLUSTER_NAME を自分の名前クラスター名にする#!/bin/bash echo ECS_CLUSTER=HOGE_CLUSTER_NAME >> /etc/ecs/ecs.configあとはよしなににしてどうぞ
参考: https://docs.aws.amazon.com/ja_jp/AmazonECS/latest/developerguide/launch_container_instance.html
- 投稿日:2019-07-27T17:28:11+09:00
手動で立ち上げる EC2 に ECS をつなぐ方法
EC2 で ECS を動かす記事をよく見ますが
ECS から設定された EC2 を立ち上げる記事はありますが
自分で立ち上げた EC2 から ECS に連携させる方法の記事が見つからなかったのでメモします
尚、個人的見解ですが、ECS やるなら Fargate 使うほうがおすすめです
EC2 にはパブリック IP が付与されているものとしますAMIを確認する
ECS用に最適化されたAMIの情報を確認します
https://docs.aws.amazon.com/ja_jp/AmazonECS/latest/developerguide/ecs-optimized_AMI.html
英語版のほうが更新が早いので英語版も念の為見ておくと良いです
https://docs.aws.amazon.com/AmazonECS/latest/developerguide/ecs-optimized_AMI.htmlECSを動かせるロールを作成
AmazonEC2ContainerServiceforEC2Role
ポリシーを付与した EC2 向けのロールを作成します
すでにロールがある場合は、ポリシーをアタッチしてくださいEC2の設定
EC2 の インスタンスの設定画面で
ECS を動かすのに必要なロールを付与高度な詳細をクリックして開き、
ユーザーデータの部分に以下を追記
HOGE_CLUSTER_NAME を自分の名前クラスター名にする#!/bin/bash echo ECS_CLUSTER=HOGE_CLUSTER_NAME >> /etc/ecs/ecs.configあとはよしなににしてどうぞ
参考: https://docs.aws.amazon.com/ja_jp/AmazonECS/latest/developerguide/launch_container_instance.html
- 投稿日:2019-07-27T15:44:19+09:00
Amazon EC2 のスポットインスタンスを AWS Cloud9 から使用する
目的
- AWS Cloud9 (以降 Cloud9 とする) を使うためにかかる費用をとにかく安くする!!!
- 初回の環境構築手順は多少複雑でもよい。
- 環境構築後の日々の Cloud9 起動手順はできるかぎり簡単にする。
Cloud9 の使用構成
どれだけ費用を削減できるのか比較するために、今回作成するオレオレ構成とは別に基本構成を考える。
- 基本構成
- Environment Type を EC2 にして出来る限りデフォルト設定で作成した構成。
- オレオレ構成。
- 費用が安くなるように工夫した構成。
基本構成
Environment Type を EC2 にして出来る限りデフォルト設定で作成した構成。
- 概要
- t2.micro のオンデマンドインスタンス。
- ルートデバイス用 EBS 8G。
- AMI は 2019 年 3 月 28 日時点では Cloud9Default-2019-02-18T10-14 (ami-0f5f5c726eabf14a2) で任意変更はできない。
- メリット
- 環境構築が楽。
- 自動停止によってインスタンス停止を忘れても安心。
- デメリット
- オンデマンドインスタンスなので高い。
- ルートデバイス用の EBS 8G を維持し続ける必要があり、月あたり約1ドルの固定費が必要。
- AMI を変更できない。
- 作成した EC2 はほぼ Cloud9 専用。
オレオレ構成
費用が安くなるように工夫した構成。
- 概要
- EC2 のリージョン。
- Cloud9 以外の目的での使用も考慮して EC2 は東京リージョンで運用。
- EC2 のアベイラビリティーゾーン。
- インスタンスと EBS のアベイラビリティーゾーンは同じにする必要あるので、スポットインスタンス作成時は要注意。
- t2.micro のスポットインスタンス。
- 基本構成との比較用に同じ t2.micro としている。
- ルートデバイス用 EBS 8G。
- スポットインスタンスを停止する際は削除する。
- データ用 EBS 1G。
- スポットインスタンスの停止に関係なく維持する。
- 独自ドメイン。
- 他目的で使用している独自ドメインを流用。
- Route53
- 他目的で使用している独自ドメインの管理で使用しているのを流用。
- メリット
- EC2 を好きに用意できる。
- デメリット
- 自動停止がない。
- 日々の Cloud9 起動手順にスポットインスタンス作成という手順が増えている。
費用比較
費用単価
簡易化のために1ヶ月は 750 時間で計算する。
項目 単価 Type=EC2構成 オレオレ構成 t2.micro (On-Demand) 0.0152 [USD/1H] 利用時間 ─ t2.micro (Spot) 0.0046 [USD/1H] ─ 利用時間 EBS 8G (root device) 0.00128 [USD/1H] 750時間 利用時間 EBS 1G (data) 0.00016 [USD/1H] ─ 750時間 独自ドメイン 1.000 [USD/1M] ─ 750時間 Route53 Hosted Zone 0.500 [USD/1M] ─ 750時間 利用時間に対する費用
オレオレ1:独自ドメインと Route53 の費用を含めた場合。
オレオレ2:独自ドメインと Route53 の費用を含めない場合。私個人としては独自ドメインおよび Route53 は別目的で運用しているものを流用するので、Cloud9 を使うためにかかる費用としては
オレオレ2
が該当。オレオレ構成の構築手順
初回の環境構築
- ≪AWS Console≫ Route53 に A レコードを作成。
- ≪AWS Console≫ 初期設定用にインスタンス(インスタンスA)を作成。
- ≪AWS Console≫ 永続データ用の EBS を作成。
- ≪AWS Console≫ インスタンスAに永続データ用 EBS をアタッチ。
- ≪SSH Client≫ インスタンスAに SSH ログイン。
- ≪SSH Client≫
力尽きた・・・。
Cloud9が東京リージョンにきたし、そのうち整理しなおして投稿しなおす。
- 投稿日:2019-07-27T15:16:30+09:00
AWS Chatbot(beta版)を使ってみた
AWSがチャットボートサービス「AWS Chatbot」のβ版を更改(2019/7/24)されました。
https://aws.amazon.com/jp/chatbot/
公式に簡単なハンズオン(英語)があったので、日本語で手順を書いておきます。AWS ChatBot概要
Amazon Simple Notification Service(SNS)を使って、SlackやAWS Chimeにメッセージ通知を行える。
連携可能なサービス
現時点(7/27)で連携可能なサービスは以下。
https://docs.aws.amazon.com/ja_jp/chatbot/latest/adminguide/related-services.html
- Amazon CloudWatch
- AWS Health
- AWS Budgets
- AWS Security Hub
- Amazon GuardDuty
- AWS CloudFormation料金
AWS Chatbotは無料(7/27時点)
ハンズオン(15分程度)
公式でお試し設定方法が書いてたので試してみました。
https://docs.aws.amazon.com/ja_jp/chatbot/latest/adminguide/setting-up.html
公式は英語なので、日本語で手順書きます。
今回はSlackへのメッセージ通知をやります。概要
CloudWatchアラームを設定し、アラーム通知をSlackチャンネルに送ります。
0.事前確認
- Slackチャンネルの用意
- AWS SNSのトピック設定(DynamoDBなど使ってる人はデフォルトで設定されてます)
1.IAMユーザ作成
Adminレベルのユーザを作ります。
1. IAMコンソール( https://console.aws.amazon.com/iam/) 開く
2. 「ユーザ」選択
3. 「ユーザを追加」選択
3. ユーザ名:Administrator
4. 「AWS マネジメントコンソールへのアクセス」をチェック
5. コンソールのパスワード:カスタムパスワード
6. パスワード入力
7. 「パスワードのリセットが必要」チェック外す(どっちでもOK)
8. 「次のステップ:アクセス権限」選択
9. 「グループの作成」選択
10. グループ名:Administrators
11. 「ポリシーのフィルタ」を選択
12. 「AWS 管理のジョブ機能」をチェック
13. 「AdministratorAccess」をチェック
14. 「グループの作成」を選択
15. 「次のステップ:タグ」を選択
16. 「次のステップ:確認」を選択
17. 「ユーザの作成」を選択2.ChatBotの設定
AWS ChatBotを設定します。
1. ChatBotコンソール(https://console.aws.amazon.com/chatbot/) を開く
2. 「Configure new client」を選択
3. Slackの連携ページが開くので、連携先Slackワークスペースを選択して「confirm」を選択
4. Slack Channel:連携したいChannelを選択
5. IAM permissions(RoleName):適当なロール名を入力(なんでもOK)
6. SNS topics(SNS Region):どこでもOK(SNSトピックがあるとこ)
7. SNS topics(SNS topics):どれでもOK
8. 「configure」を選択3.CloudWatchアラームの設定
アラームを設定します。
1. CloudWatchコンソール(https://console.aws.amazon.com/cloudwatch/) を開く
2. 「アラーム」を選択
3. 「アラームの作成」を選択
4. 「メトリクスの選択」を選択
5. 検索欄:SNS
6. SNS>トピックメトリクス
7. 適当なトピック名をチェック(どれでもOK)
8. 条件(しきい値の種類):静的
9. 条件(アラーム条件を定義):以下
10. 条件(しきい値を定義します):1
11. 「次へ」を選択
12. 通知(アラーム状態):アラーム状態
13. 通知(SNSトピック):既存のSNSトピックを選択
14. 通知(通知の送信先):適当に選択
15. 「次へ」を選択
16. アラーム名:なんでもOK
17. アラームの説明:なんでもOK
18. 「次へ」を選択
19. 「アラームの作成」を選択4.結果を確認
Slackチャンネルをみましょう。3分くらい待てば通知が来るはずです。
おわりに
今までチャットボットはLambdaなどで手作りでしたが、これだと設定だけで簡単にBotが使えますね。
GuardDutyの不正アクセス通知とかは欲しかったので試してみようかと思います。
今後の機能拡張に期待です。
- 投稿日:2019-07-27T11:29:24+09:00
CloudWatchのロググループに手動でテスト用ログを投入したい。
はじめに / やりたいこと
前回の続きで、AWSを使っての作業メモになります。
いくつか挙げていたやりたいことの中の、こちらを試します。
- ログをよしなに見れるようにする
- ログで何かのパターンを検出したらアラームを生成する
- 必要に応じて通知設定をする
ログ周りの設定なのですが、基本はアプリケーションが出すログをチェックするので、メトリクスやアラームの設定が妥当なのかどうかは、タイミングが悪いとなかなか確認できません。
アプリケーション作成側にお願いするには、ちょっと手間がかかります。手動でテスト用ログを突っ込みたい
ある程度はコンソールで出来ますが、やはりログ生成(ベント送信)のところが悩みどころ。
- CloudWatchにロググループを作成する (コンソールで作成可能)
- ロググループ宛にログストリームを作成する (コンソールで作成可能)
- ログストリームに対してイベントを流す(ログを送る)
- これはコンソールからはできない...(キャプチャ参照)
- ここはアプリケーションにエージェントを仕込むか送信する処理を組み込む
- メトリクスを作成する (コンソールで作成可能)
- アラームを作成する (コンソールで作成可能)
ログストリームはつくれてもイベントが送れない...
もしかしたら画面からでもイベントを登録できるかもしれませんが...。
AWSの操作は、実際はAPIを介して色々な操作をしますので、正しいお作法でデータを投げれば、あアプリケーションに代わってダミーのログを投入することができるはず...。(わざわざログを送信するアプリケーションを作るのは辛い)
aws cliを眺めていたら、どうやら
aws logs put-log-events
が使えることが判明。
下記の記事にもとても詳しく書かれていて、非常に助かりました!これでなんとか試せそうです。
また、イベントの送信以外にコンソールから出来る作業も、できれば何をしたか記録がわかりやすいようにTerraformでやってみたい。
ということで、今回は以下を使うことにしました。
- Terraform
- aws cli (とshell script)
Terraformを使ってロググループ&メトリクスを作る
Terraformの設定自体は省略します。
また、今回はCloudWatchの機能を使うだけなので、特に他のリソース(EC2やS3ちったもの)も必要ありません。ロググループの作成
sample.tf# TestLogGroupというロググループを定義 resource "aws_cloudwatch_log_group" "test-log-group" { name = "TestLogGroup" retention_in_days = 0 tags = {} }実行は以下。(ターゲットを指定して1つずつやっていきます)
% terraform plan --target=aws_cloudwatch_log_group.test-log-group Terraform will perform the following actions: # aws_cloudwatch_log_group.test-log-group will be created + resource "aws_cloudwatch_log_group" "test-log-group" { + arn = (known after apply) + id = (known after apply) + name = "TestLogGroup" + retention_in_days = 0 } Plan: 1 to add, 0 to change, 0 to destroy. % terraform apply --target=aws_cloudwatch_log_group.test-log-group .... aws_cloudwatch_log_group.test-log-group: Creating... aws_cloudwatch_log_group.test-log-group: Creation complete after 0s [id=TestLogGroup]ということで、空っぽのロググループが出来ました。この段階では、ログストリームはありませんね。
メトリクスの作成
こちらも続けてメトリクスを設定します。対象のロググループがわかればいいのですが、そこはTerraformが解決してくれるので、設定は以下の通り。
log_group_name = "${aws_cloudwatch_log_group.test-log-group.name}"
ここでどのロググループへのフィルタかを設定しています。
(直接、AWSのコンソールからarnを参照して、その値を入れても大丈夫)metric.tf# ERRORというパターンを拾います resource "aws_cloudwatch_log_metric_filter" "error_test-log-group" { name = "ErrorCount_TestLogGroup" pattern = "ERROR" log_group_name = "${aws_cloudwatch_log_group.test-log-group.name}" metric_transformation { name = "ErrorCount_TestLogGroup" namespace = "Logs" value = "1" } }こちらも、target指定でplan & applyします。
% terraform apply --target=aws_cloudwatch_log_metric_filter.error_test-log-group aws_cloudwatch_log_group.test-log-group: Refreshing state... [id=TestLogGroup] ... aws_cloudwatch_log_metric_filter.error_test-log-group: Creating... aws_cloudwatch_log_metric_filter.error_test-log-group: Creation complete after 0s [id=ErrorCount_TestLogGroup]こんな感じで、ロググループにフィルタが1つ設定されました。(ここからコンソール側でも調整できます)
aws cliを利用してログストリームを作成しログを投入
さて、メトリクスフィルタを設定しても、ここからログを実際に流さないとなにも表示がされません。ここから先は、aws cliを使っていきます。
参考にさせていただいた記事 の通りで、以下の流れになります。
- ログストリームを作る
- 1回目はこのログストリームに対して、まず初回のイベントを登録
- 同じログストリームにイベントをつなげる場合は、2回目はログストリームのuploadSequenceTokenを指定して送信する
参考: 文字列をCloudWatchLogsにPUTしてみた (by DevelopersIO)
わたしの場合は、こんな感じにしています。
- スクリプトを実行するたびに、別のログストリームを作成する
- そのログストリームに対して11個分のイベントを送信する
- 2回目以降のイベントはERRORを含むものと含まないものを偶数奇数で分ける
log-stream-push.shTIME_EPOCH="`date +%s`000" STREAM_DATETIME="`date +%Y%m%d%H%M%S`" LOG_GROUP_NAME="TestLogGroup" LOG_STREAM_NAME="test-stream-${STREAM_DATETIME}" # イベントメッセージを生成する関数 function generate_msg() { LOG_TIMESTAMP=`date +%Y-%m-%dT%H:%M:%S%z` # サンプルのログメッセージを生成(適度に場合わけ) if [ $1 -eq 0 ]; then LOG_MSG="[INFO]${LOG_TIMESTAMP}: : Rendered layouts/_common.html.erb (2.5ms)" else LOG_MSG="[ERROR]${LOG_TIMESTAMP}: : Something error occurred: xxxxx" fi # shellの関数はreturnだと数値しか返せないので、echoで送って、 # MSG=`generate_msg 引数` で受ける echo ${LOG_MSG} } # 1回目はテスト用のstreamを作成 LOG_MSG=`generate_msg 0` LOG_EVENTS="timestamp=${TIME_EPOCH},message=\"${LOG_MSG}\"" aws logs create-log-stream \ --log-group-name ${LOG_GROUP_NAME} \ --log-stream-name ${LOG_STREAM_NAME} aws logs put-log-events \ --log-group-name ${LOG_GROUP_NAME} \ --log-stream-name ${LOG_STREAM_NAME} \ --log-events "${LOG_EVENTS}" # 2回目以降はstreamのトークンを取得して実行 for i in {1..10} ; do MSG_PATTERRN=$(( $i & 1 )) LOG_MSG=`generate_msg $MSG_PATTERRN` # 出来上がったログストリームから、uploadSequenceTokenを取得 LOG_PUT_TOKEN=`aws logs describe-log-streams --log-group-name ${LOG_GROUP_NAME} \ --log-stream-name-prefix ${LOG_STREAM_NAME} \ --query 'logStreams[].uploadSequenceToken' --output text` \ && echo ${LOG_PUT_TOKEN} LOG_EVENTS="timestamp=${TIME_EPOCH},message=\"${LOG_MSG}\"" aws logs put-log-events \ --log-group-name ${LOG_GROUP_NAME} \ --log-stream-name ${LOG_STREAM_NAME} \ --log-events "${LOG_EVENTS}" \ --sequence-token ${LOG_PUT_TOKEN} done実行してみます。確認用にuploadSequenceTokenを出力しています。
% sh log-stream-push.sh { "nextSequenceToken": "49594xxxxxxxxxxx082" } { "nextSequenceToken": "49594xxxxxxxxxxx634" } ....aws cliからの結果はダンマリですが、コンソール側を確認すると、ちゃんとログが登録されています。(タイムスタンプ改良の余地が...)
ログストリーム投入後のメトリクス
イベント(ログ)が投入される様になると、メトリクス側にも反映されてきます。
何回かスクリプトを回して、5回エラーが出たり、10回エラーが出ていることが分かります。Terraformでアラームを設定してみる
手動でのベント登録でもなんとかなりそう!
では、上記で設定したメトリクスをつかって、アラーム設定をしてみます。
こちらもTerraformで設定します。
- テスト用なので、perod (間隔)を60秒に
- 合計で6回以上検出されたらアラームを出す
- 手元で1分につきスクリプトを1回だけ実行のときはアラームが出ません
- 手元で1分につきスクリプトを2回以上実行すると、アラームが出るはず
- Emailなどでアクションを起こす場合はalarm_actionsに対象のトピックを登録
- 今回は空っぽにします
alarm.tf# 上記で設定したメトリクスをつかって、アラーム設定 resource "aws_cloudwatch_metric_alarm" "alarm_error_test-log-group" { actions_enabled = true alarm_actions = [ ] alarm_description = "ERRORを検出してアラート" alarm_name = "Alerm_ErrorCount_TestLogGroup" comparison_operator = "GreaterThanOrEqualToThreshold" datapoints_to_alarm = 1 dimensions = {} evaluation_periods = 1 insufficient_data_actions = [] metric_name = "ErrorCount_TestLogGroup" namespace = "Logs" ok_actions = [] period = 60 statistic = "Sum" tags = {} threshold = 6 treat_missing_data = "notBreaching" }こちらもapplyしてみます。
terraform apply --target=aws_cloudwatch_metric_alarm.alarm_error_test-log-groupコンソールでの画面
数回試してみました。
以下は、3回出現の場合はOKに。その後9回出現してアラームが発生した例です。3回なので閾値には該当しません。
その後、9回検出したので、アラームが1件上がって来ました。
こんな感じでうまくいったようです。
あとは通知先のアクションに、トピックを紐づければよさそうです。
まとめ
以上、ちょっとした作り込みでしたが、なんとかスクリプトからログを生成してテスト用のアラームを発生させるところまで出来ました。
アラーム自体が適切に設定されていれば、あとは実際のアプリケーションのロググループに対して同じ様にしていけば良さそうです。
また、アプリケーションがなくても手動でログを流してアラアーム発生させて、Lambdaのテストをするといったこともやりやすそうです。あらためて、インフラの設定をしつつも、「API叩いてるんだなあ...」というのを感じた作業です。
- 投稿日:2019-07-27T00:38:33+09:00
Amazon Linux 1 に acme.sh (HTTP-01 challenge)で Let's Encrypt を入れる
概要
- とある有償SSLサーバ証明書の有効期限がそろそろ切れるので、これを機に、これまでの有償+手動更新から、Let's Encrypt を利用した 無償+自動更新 で幸せになろうと思ったけど、インストールするサーバが Amazon Linux 1 でしかも古いバージョンのため、Let's Encrypt の SSLサーバ証明書をインストールするのにいろいろ試行錯誤した記録。
環境
- Let's Encrypt の SSLサーバ証明書を入れるサーバ
- Amazon Linux 1(AMI release 2015.09)←古すぎ!
$ cat /etc/system-release Amazon Linux AMI release 2015.09Webサーバ
- Nginx(BASIC認証でアクセス制限している)
- ドキュメントルート /usr/share/nginx/html
ドメイン
- foo.staging.co.jp(今回の説明用のダミードメイン)
IPアドレス/ポート番号制限
- 任意のIPアドレスから http://foo.staging.co.jp, https://foo.staging.co.jp への接続は全開放
Certbot の断念
無償のSSLサーバ証明書といえば『Let's Encrypt』ということで、公式サイトのGetting Startedを読むと、Certbot ACME client を推奨している。ということで、まずはサーバに Certbot のインストールを試みる。
Amazon Linux 1 は CentOS 6 のパッケージを使えるので、Let's Encrypt 総合ポータル サイトの "CentOS 6 / RHEL 6" のインストール方法 に書いてある通り、EPEL6 リポジトリから入れようと思ったら、certbot パッケージが無いというエラー。確かに、EPEL 6: x86_64 リポジトリ にcertbotパッケージが無い。。
なので、Let's Encrypt 総合ポータル サイトの "その他の UNIX 系 OS" のインストール方法に書いてある通り実行すると・・・FATAL: Amazon Linux support is very experimental at present...
「--debug」オプションを付けて再度実行してみると、次のパッケージの Install/Update をしろと、、$ wget https://dl.eff.org/certbot-auto $ chmod a+x certbot-auto $ ./certbot-auto Requesting to rerun ./certbot-auto with root privileges... FATAL: Amazon Linux support is very experimental at present... if you would like to work on improving it, please ensure you have backups and then run this script again with the --debug flag! Alternatively, you can install OS dependencies yourself and run this script again with --no-bootstrap.$ ./certbot-auto --debug 〜略〜 Installing: augeas-libs gcc48 replacing libquadmath48-devel.x86_64 4.8.3-9.109.amzn1 gcc48-c++ replacing libstdc++48-devel.x86_64 4.8.3-9.109.amzn1 libffi-devel python27-tools Updating: ca-certificates gcc openssl openssl-devel python27-devel python27-pip python27-virtualenv system-rpm-config Installing for dependencies: libgfortran Updating for dependencies: cpp48 gcc-c++ gcc-gfortran gcc48-gfortran libffi libgcc48 libgomp libstdc++48 libtool python27 python27-libsLet's Encrypt 総合ポータル サイトに、しれっと注意書きがある。。
うーん、、 Install/Update するのは怖いよね。。
ということで、certbot は諦めて、別の ACME client を使ってみようということで、ACME v2 Compatible Clientsからacme.sh を選択。acme.sh はシェルスクリプトで書かれていて、シェルが動く環境であれば導入が楽ですぐに使えるらしい。
acme.sh を使って Let's Encrypt SSLサーバ証明書をインストールする
acme.sh をインストールする
公式サイトの通りに実行、
# cd /root # curl https://get.acme.sh | sh % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0 curl: (35) Cannot communicate securely with peer: no common encryption algorithm(s).あれ、curl が古い。。nssをアップグレードする。
# yum upgrade nss再度、、
# cd /root # curl https://get.acme.sh | sh % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 705 0 705 0 0 4617 0 --:--:-- --:--:-- --:--:-- 4607 % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 184k 100 184k 0 0 492k 0 --:--:-- --:--:-- --:--:-- 492k [Fri Jul 19 12:11:23 JST 2019] Installing from online archive. [Fri Jul 19 12:11:23 JST 2019] Downloading https://github.com/Neilpang/acme.sh/archive/master.tar.gz [Fri Jul 19 12:11:24 JST 2019] Extracting master.tar.gz [Fri Jul 19 12:11:24 JST 2019] It is recommended to install socat first. [Fri Jul 19 12:11:24 JST 2019] We use socat for standalone server if you use standalone mode. [Fri Jul 19 12:11:24 JST 2019] If you don't use standalone mode, just ignore this warning. [Fri Jul 19 12:11:24 JST 2019] Installing to /root/.acme.sh [Fri Jul 19 12:11:24 JST 2019] Installed to /root/.acme.sh/acme.sh [Fri Jul 19 12:11:24 JST 2019] Installing alias to '/root/.bashrc' [Fri Jul 19 12:11:24 JST 2019] OK, Close and reopen your terminal to start using acme.sh [Fri Jul 19 12:11:24 JST 2019] Installing alias to '/root/.cshrc' [Fri Jul 19 12:11:24 JST 2019] Installing alias to '/root/.tcshrc' [Fri Jul 19 12:11:24 JST 2019] Installing cron job [Fri Jul 19 12:11:24 JST 2019] Good, bash is found, so change the shebang to use bash as preferred. [Fri Jul 19 12:11:24 JST 2019] OK [Fri Jul 19 12:11:24 JST 2019] Install success!入った。
crontab (/var/spool/cron/root) に次のような設定(自動更新用)が追加される。24 0 * * * "/root/.acme.sh"/acme.sh --cron --home "/root/.acme.sh" > /dev/nullNginx mode で SSLサーバ証明書を発行してみる
- acme.sh のオプション
- --issue・・・SSLサーバ証明書発行
- --nginx・・・Nginx mode
- -d・・・SSLサーバ証明書を発行するドメイン
# cd /root/.acme.sh # ./acme.sh --issue --nginx -d foo.staging.co.jp [Fri Jul 19 12:17:47 JST 2019] Create account key ok. [Fri Jul 19 12:17:47 JST 2019] Registering account [Fri Jul 19 12:17:48 JST 2019] Registered [Fri Jul 19 12:17:48 JST 2019] ACCOUNT_THUMBPRINT='1W2zh17CQyWXgr3TCI5DVgl_728ut2X7oi5r4RByFwg' [Fri Jul 19 12:17:48 JST 2019] Creating domain key [Fri Jul 19 12:17:48 JST 2019] The domain key is here: /root/.acme.sh/foo.staging.co.jp/foo.staging.co.jp.key [Fri Jul 19 12:17:48 JST 2019] Single domain='foo.staging.co.jp' [Fri Jul 19 12:17:48 JST 2019] Getting domain auth token for each domain [Fri Jul 19 12:17:49 JST 2019] Getting webroot for domain='foo.staging.co.jp' [Fri Jul 19 12:17:49 JST 2019] Verifying: foo.staging.co.jp [Fri Jul 19 12:17:49 JST 2019] Nginx mode for domain:foo.staging.co.jp [Fri Jul 19 12:17:49 JST 2019] Found conf file: /etc/nginx/nginx.conf [Fri Jul 19 12:17:49 JST 2019] Backup /etc/nginx/nginx.conf to /root/.acme.sh/foo.staging.co.jp/backup/foo.staging.co.jp.nginx.conf [Fri Jul 19 12:17:49 JST 2019] Check the nginx conf before setting up. [Fri Jul 19 12:17:49 JST 2019] OK, Set up nginx config file [Fri Jul 19 12:17:49 JST 2019] nginx conf is done, let's check it again. [Fri Jul 19 12:17:49 JST 2019] Reload nginx [Fri Jul 19 12:17:54 JST 2019] foo.staging.co.jp:Verify error:Invalid response from http://foo.staging.co.jp/.well-known/acme-challenge/6Tb5KM3d0jhtiRJ6eoqfa68u_0BFBF1eqgdvtH7g4sU [x.x.x.x]: 401 [Fri Jul 19 12:17:54 JST 2019] Restoring from /root/.acme.sh/foo.staging.co.jp/backup/foo.staging.co.jp.nginx.conf to /etc/nginx/nginx.conf [Fri Jul 19 12:17:54 JST 2019] Reload nginx [Fri Jul 19 12:17:54 JST 2019] Please add '--debug' or '--log' to check more details. [Fri Jul 19 12:17:54 JST 2019] See: https://github.com/Neilpang/acme.sh/wiki/How-to-debug-acme.shエラー出た。。
Verify error:Invalid response from http://foo.staging.co.jp/.well-known/acme-challenge/6Tb5KM3d0jhtiRJ6eoqfa68u_0BFBF1eqgdvtH7g4sU [x.x.x.x]: 401そもそも、何やっているの?
acme.sh は SSLサーバ証明書を発行する際に HTTP-01 challenge で検証を行っている。
acme.sh --issue 実行時に、acme.sh は Nginx の "ルートディレクトリ/.well-known/acme-challenge/" ディレクトリ内にトークンファイルを一時的に作成して、acme.sh がトークンファイルの準備が出来たことを Let's Encrypt に伝えたら、Let's Encrypt は "http://foo.staging.co.jp/.well-known/acme-challenge/トークン" にアクセスを試みる。Let's Encrypt が正しい応答を得られたら検証は成功とみなされ、SSLサーバ証明書が発行される。Nginx mode は、自動的に nginx コンフィグファイルを探して、"ルートディレクトリ/.well-known/acme-challenge/トークンファイル" へのアクセス設定を施して、検証が終わったら、設定を元に戻す。
今回は、Nginx で Basic 認証を行っているため、Let's Encrypt からのアクセスが 401 となり、検証が失敗してしまった。
ちなみに、HTTP-01 challenge アクセスは、Let's Encryptの接続元IPアドレスは公開していないため、クライアント側は HTTP ポート80番で任意のIPアドレスからの接続を許可しておく必要がある。
トークンへのアクセスはBASIC認証対象外として、ノーマルモードで SSLサーバ証明書を発行してみる
まずは、HTTP-01 challenge 用のディレクトリを手動で作成する。
# cd /usr/share/nginx/html # mkdir -p .well-known/acme-challenge # chmod -R 755 .well-known/acme-challenge # chown -R nginx:nginx /usr/share/nginx/html/.well-known/acme-challenge"http://foo.staging.co.jp/.well-known/acme-challenge/トークン" へのアクセスは BASIC認証対象外とする
/etc/nginx/nginx.conf 設定例〜 location /.well-known { satisfy any; allow all; } location /.well-known/acme-challenge { satisfy any; allow all; } 〜nginx 再起動
# service nginx configtest # service nginx restartノーマルモードでSSLサーバ証明書を発行する
- acme.sh のオプション
- -w・・・ドキュメントルート
# cd /root/.acme.sh # ./acme.sh --issue -d foo.staging.co.jp -w /usr/share/nginx/html [Fri Jul 26 12:48:13 JST 2019] Create account key ok. [Fri Jul 26 12:48:13 JST 2019] Registering account [Fri Jul 26 12:48:14 JST 2019] Registered [Fri Jul 26 12:48:14 JST 2019] ACCOUNT_THUMBPRINT='6k1I3oh7R3iEIrnWIEWMsRt0rmUzf4T2CXgn9TaXvoE' [Fri Jul 26 12:48:14 JST 2019] Creating domain key [Fri Jul 26 12:48:14 JST 2019] The domain key is here: /root/.acme.sh/foo.staging.co.jp/foo.staging.co.jp.key [Fri Jul 26 12:48:14 JST 2019] Single domain='foo.staging.co.jp' [Fri Jul 26 12:48:14 JST 2019] Getting domain auth token for each domain [Fri Jul 26 12:48:15 JST 2019] Getting webroot for domain='foo.staging.co.jp' [Fri Jul 26 12:48:15 JST 2019] Verifying: foo.staging.co.jp [Fri Jul 26 12:48:18 JST 2019] Success [Fri Jul 26 12:48:18 JST 2019] Verify finished, start to sign. [Fri Jul 26 12:48:18 JST 2019] Lets finalize the order, Le_OrderFinalize: https://acme-v02.api.letsencrypt.org/acme/finalize/62039946/782487887 [Fri Jul 26 12:48:20 JST 2019] Download cert, Le_LinkCert: https://acme-v02.api.letsencrypt.org/acme/cert/03d9bc51c44775de73e376f19b890cc6f5bf [Fri Jul 26 12:48:20 JST 2019] Cert success. -----BEGIN CERTIFICATE----- MIIFcjCCBFqgAwIBAgISA9m8UcRHdd5z43bxm4kMxvW/MA0GCSqGSIb3DQEBCwUA 〜略〜 5Kh5eZhP -----END CERTIFICATE----- [Fri Jul 26 12:48:20 JST 2019] Your cert is in /root/.acme.sh/foo.staging.co.jp/foo.staging.co.jp.cer [Fri Jul 26 12:48:20 JST 2019] Your cert key is in /root/.acme.sh/foo.staging.co.jp/foo.staging.co.jp.key [Fri Jul 26 12:48:20 JST 2019] The intermediate CA cert is in /root/.acme.sh/foo.staging.co.jp/ca.cer [Fri Jul 26 12:48:20 JST 2019] And the full chain certs is there: /root/.acme.sh/foo.staging.co.jp/fullchain.cerおぉ、発行された!
発行されたSSLサーバ証明書を確認する。
# ./acme.sh --list Main_Domain KeyLength SAN_Domains Created Renew foo.staging.co.jp "" no Fri Jul 26 03:48:20 UTC 2019 Tue Sep 24 03:48:20 UTC 2019発行されたSSLサーバ証明書を Nginx にインストールする
cert keyファイルと、full chain certs ファイルをを置くディレクトリを作成する。
# mkdir -p /etc/nginx/certs/letsencrypt/foo.staging.co.jp/etc/nginx/certs/letsencrypt/foo.staging.co.jp ディレクトリに、foo.staging.co.jp.key ファイルと、fullchain.cer ファイルをインストール (--install-cert) する。
# cd /root/.acme.sh/ # ./acme.sh --install-cert -d foo.staging.co.jp --key-file /etc/nginx/certs/letsencrypt/foo.staging.co.jp/foo.staging.co.jp.key --fullchain-file /etc/nginx/certs/letsencrypt/foo.staging.co.jp/fullchain.cernginx コンフィグファイルで証明書のパスを設定する
/etc/nginx/conf.d/ssl.conf 設定例〜 ssl_certificate /etc/nginx/certs/letsencrypt/foo.staging.co.jp/fullchain.cer; ssl_certificate_key /etc/nginx/certs/letsencrypt/foo.staging.co.jp/foo.staging.co.jp.key; 〜nginx 再起動
# service nginx configtest nginx: the configuration file /etc/nginx/nginx.conf syntax is ok nginx: configuration file /etc/nginx/nginx.conf test is successful # service nginx restart Stopping nginx: [ OK ] Starting nginx: [ OK ]ブラウザから https://foo.staging.co.jp へアクセスして、SSLサーバ証明書を確認する。
インストール出来た。
自動更新設定
自動更新では、SSLサーバ証明書発行後に、"--install-cert でインストールしてnginxをリロード" させる。
そのジョブを実行する。# /root/.acme.sh # ./acme.sh --install-cert -d foo.staging.co.jp --key-file /etc/nginx/certs/letsencrypt/foo.staging.co.jp/foo.staging.co.jp.key --fullchain-file /etc/nginx/certs/letsencrypt/foo.staging.co.jp/fullchain.cer --reloadcmd "service nginx force-reload" [Fri Jul 19 17:18:49 JST 2019] Installing key to:/etc/nginx/certs/letsencrypt/foo.staging.co.jp/foo.staging.co.jp.key [Fri Jul 19 17:18:49 JST 2019] Installing full chain to:/etc/nginx/certs/letsencrypt/foo.staging.co.jp/fullchain.cer [Fri Jul 19 17:18:49 JST 2019] Run reload cmd: service nginx force-reload Reloading nginx: [ OK ]これで、cronによる自動更新ジョブで、SSLサーバ証明書発行後に、"--install-cert でインストールしてnginxをリロード" するようになる。
acme.sh インストール時に crontab に自動更新のコマンドが追加されているので、
crontab (/var/spool/cron/root)24 0 * * * "/root/.acme.sh"/acme.sh --cron --home "/root/.acme.sh" > /dev/nullこれを使って、手動で強制的 (--force) に更新処理を実行してみる。
# "/root/.acme.sh"/acme.sh --cron --home "/root/.acme.sh" --force [Fri Jul 26 13:24:13 JST 2019] ===Starting cron=== [Fri Jul 26 13:24:13 JST 2019] Renew: 'foo.staging.co.jp' [Fri Jul 26 13:24:14 JST 2019] Single domain='foo.staging.co.jp' [Fri Jul 26 13:24:14 JST 2019] Getting domain auth token for each domain [Fri Jul 26 13:24:15 JST 2019] Getting webroot for domain='foo.staging.co.jp' [Fri Jul 26 13:24:15 JST 2019] foo.staging.co.jp is already verified, skip http-01. [Fri Jul 26 13:24:15 JST 2019] Verify finished, start to sign. [Fri Jul 26 13:24:15 JST 2019] Lets finalize the order, Le_OrderFinalize: https://acme-v02.api.letsencrypt.org/acme/finalize/62039946/782634405 [Fri Jul 26 13:24:16 JST 2019] Download cert, Le_LinkCert: https://acme-v02.api.letsencrypt.org/acme/cert/037597c36c53830c77a547a4c949f57d0974 [Fri Jul 26 13:24:17 JST 2019] Cert success. -----BEGIN CERTIFICATE----- MIIFcjCCBFqgAwIBAgISA3WXw2xTgwx3pUekyUn1fQl0MA0GCSqGSIb3DQEBCwUA 〜略〜 7AFa7o7V -----END CERTIFICATE----- [Fri Jul 26 13:24:17 JST 2019] Your cert is in /root/.acme.sh/foo.staging.co.jp/foo.staging.co.jp.cer [Fri Jul 26 13:24:17 JST 2019] Your cert key is in /root/.acme.sh/foo.staging.co.jp/foo.staging.co.jp.key [Fri Jul 26 13:24:17 JST 2019] The intermediate CA cert is in /root/.acme.sh/foo.staging.co.jp/ca.cer [Fri Jul 26 13:24:17 JST 2019] And the full chain certs is there: /root/.acme.sh/foo.staging.co.jp/fullchain.cer [Fri Jul 26 13:24:17 JST 2019] Installing key to:/etc/nginx/certs/letsencrypt/foo.staging.co.jp/foo.staging.co.jp.key [Fri Jul 26 13:24:17 JST 2019] Installing full chain to:/etc/nginx/certs/letsencrypt/fullchain.pem [Fri Jul 26 13:24:17 JST 2019] Installing full chain to:/etc/nginx/certs/letsencrypt/foo.staging.co.jp/fullchain.cer Reloading nginx: [ OK ] [Fri Jul 26 13:24:17 JST 2019] Reload success [Fri Jul 26 13:24:17 JST 2019] ===End cron===SSLサーバ証明書発行して、インストールして、nginx 再起動してる。
ブラウザからSSLサーバ証明書の有効期限を確認する。
有効期限が新しく発行したSSLサーバ証明書になっていれば、成功。ちなみに、Let's Encrypt の SSLサーバ証明書の有効期限は90日だけど、
acme.sh は cronで毎日更新処理を試行して、SSLサーバ証明書発行から60日経過している場合に、更新処理を実行する。補足
バージョン管理している場合は、"ルートディレクトリ/.well-known/acme-challenge/"の追加を忘れずに。
デプロイしたら"ルートディレクトリ/.well-known/acme-challenge/"ディレクトリが消えないように。