Amazon Linux 2用 AWS Systems ManagerでOSの簡易設定ドキュメントを作ってみた | Developers.IO

おはようございます、加藤です。AWS Systems Manager(以降、SSM)でAmazon Linux2を簡易設定するドキュメントを作ったので公開します。 できること. 簡易設定という言葉だけでは何ができるかわからないので説明します。今回作成したドキュメントをAmazon Linux2に対して以下の処理を実行できます。 ホスト名変更; YUM … 続きを読む

InspectorでAmazon Linux 2の脆弱性診断に対応したのでやってみた

今回は Amazon Linux 2 LTS Candidate AMI 2017.12.0 (HVM), SSD Volume Type のAMIからインスタンスを作成します。なお、自動的にパッケージを更新されないようにユーザデータに repo_upgrade: none を設定します。SSMを利用するため、ロールに AmazonEC2RoleforSSM のAWSマネージドポリシーをあてます。 続きを読む

ほう

IO. 【アップデート】Systems Managerがインフラテストツール「InSpec」に対応しました! | Developers.IO. 森永です。 Systems Manager(SSM)使ってますか。いいですよねSSM。 今回SSMにアップデートがあり、インフラストラクチャのテストツール「InSpec」に対応しました!! AWS Systems Man […] Developers.IO. 続きを読む

カテゴリー 未分類 | タグ

CloudWatch Events と Systems Manager で EC2の起動/停止をスケジュール化する

はじめに

開発環境等のインスタンスは休日や夜間は停止しておくことが多いと思います。
CloudWatch Events と Lambda で実装する例も多くみかけますが、
Systems Managerと組み合わせてノンプログラミングで実装する方法もあります。

Systems Manager 単体でも Maintenance Windows を使用して設定することができますが、
これは別の記事でご紹介できればと考えています。

設定する

IAM ロールの設定と CloudWatch Events のルール作成が必要です。

IAMロールを作成する

EC2 の起動停止は SSM Automation の機能を利用します。
そのため CloudWatch Events が SSM を呼び出すための IAM ロールを作成します。

image.png

ここでは AWS 管理ポリシーの AmazonSSMAutomationRole をアタッチします。
EC2 起動停止するために必要な権限以外も含まれますので、必要に応じてカスタムポリシーを作成してください。
作成後、信頼関係から信頼されたエンティティに events.amazonaws.com を追加します。

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Service": [
          "events.amazonaws.com"
        ]
      },
      "Action": "sts:AssumeRole"
    }
  ]
}

image.png

CloudWatch Events を設定する

起動用ルールの作成

イベントソースの設定でスケジュールを選択し、Cron式でイベントスケジュールを設定します。
例えば平日の午前9時に指定したEC2を起動したい場合は、以下のように設定します。

0 0 ? * 2-6 *

※UTC で設定しますので、日本標準時との時差9時間を考慮する必要があります。

image.png

ルールのスケジュール式ついては以下ドキュメントにも詳細が記載されています。
https://docs.aws.amazon.com/ja_jp/AmazonCloudWatch/latest/events/ScheduledEvents.html

次にターゲットの追加から SSM Automation 選択し、以下のように設定します。

  • Doclument: AWS-StartEC2Instance
  • Configure automation parameter(s)
    • InstanceId: 起動したいインスタンスのインスタンスID
  • 既存のロールの使用: 作成した IAM ロールを指定

ロールの作成手順で信頼されたエンティティに events.amazonaws.com を追加していないと、
既存のロールの選択肢に出てきませんので注意してください。

image.png

設定の詳細ボタンからステップ 2:に進み、

  • ルール名称(必須)
  • 説明(任意)

を入力し、ルールを作成すれば完了です。

停止用ルールの作成

起動用ルールと同じ流れですので、画面コピーは割愛します。

ここでは平日の18時に停止を行うと想定し、UTC で以下のように設定します。

0 9 ? * 2-6 *

ターゲットの追加から SSM Automation 選択し、以下のように設定します。

  • Doclument: AWS-StopEC2Instance
  • Configure automation parameter(s)
    • InstanceId: 停止したいインスタンスのインスタンスID
  • 既存のロールの使用: 作成した IAM ロールを指定

設定の詳細ボタンからステップ 2:に進み、

  • ルール名称(必須)
  • 説明(任意)

を入力し、ルールを作成します。

動作確認

設定した時刻に指定したインスタンスが起動および停止することを確認します。
Automation の実行結果については、コンソールでの確認方法は現時点で2通りあり、
EC2コンソールの 自動化 または AWS Systems ManagerコンソールのAutomation から確認することができます。

image.png

CloudWatch Events で結果を監視する

せっかくなので Automation の実行結果についても CloudWatch Events で設定してみます。
新規にルールを作成し、スケジュールではなく、イベントパターンを選択します。
ここでは Automation の失敗またはタイムアウトを監視するため、以下のように詳細を設定します。

  • サービス名: EC2 Simple Systems Manager (SSM)
  • イベントタイプ: Automation
  • Specific detail type(S)

    • EC2 Automation Execution Status-change Notification
  • 特定のステータス

    • Failed, TimedOut

image.png

コンソールで設定できるのは上記項目のみであるため、このままの設定だと今回設定した EC2 起動停止用の
Automation だけでなく、SSM で実行される全ての Automation が監視対象となってしまいます。
条件を更に絞りたい場合は、イベントパターンのプレビューから直接 JSON の編集を行うことができます。

ここでは EC2 の起動停止を行う Automation のみを監視するため、
“detail.Definition” フィールドに Automation ドキュメント名を設定しました。
“resources” フィールドに対象ドキュメントの ARN を指定した場合も同様の結果になります。

{
  "source": [
    "aws.ssm"
  ],
  "detail-type": [
    "EC2 Automation Execution Status-change Notification"
  ],
  "detail": {
    "Definition": [
      "AWS-StartEC2Instance",
      "AWS-StopEC2Instance"
    ],
    "Status": [
      "Failed",
      "TimedOut"
    ]
  }
}

その他にどのような項目を指定できるかについては、以下のドキュメントの
Automation 実行ステータス変更の通知例をご参照ください。

サポートされている各サービスからの CloudWatch イベント イベントの例
AWS Systems Manager イベント
https://docs.aws.amazon.com/ja_jp/AmazonCloudWatch/latest/events/EventTypes.html#ssm_event_types

ターゲットの設定では検知した内容の通知方法を設定します。
ここでは SNS の Topic に登録した Email アドレスに通知するよう設定しました。
必要に応じて入力の設定で通知内容を定義します。

image.png

設定の詳細ボタンからステップ 2:に進み、

  • ルール名称(必須)
  • 説明(任意)

を入力し、ルールを作成すれば完了です。
参考になれば幸いです。

参考: イベントパターンにおける実行ロールの指定

前述のとおり、ドキュメントに記載されているイベント例に記載されている内容であれば
イベントパターンの手動編集で条件を絞り込むことができます。

Automation 実行ステータス変更の通知例をドキュメントから抜粋すると以下のとおりです。

{
  "version": "0",
  "id": "d290ece9-1088-4383-9df6-cd5b4ac42b99",
  "detail-type": "EC2 Automation Execution Status-change Notification",
  "source": "aws.ssm",
  "account": "123456789012",
  "time": "2016-11-29T19:43:35Z",
  "region": "us-east-1",
  "resources": ["arn:aws:ssm:us-east-1:123456789012:automation-execution/333ba70b-2333-48db-b17e-a5e69c6f4d1c", 
    "arn:aws:ssm:us-east-1:123456789012:automation-definition/runcommand1:1"],
  "detail": {
    "ExecutionId": "333ba70b-2333-48db-b17e-a5e69c6f4d1c",
    "Definition": "runcommand1",
    "DefinitionVersion": 1.0,
    "Status": "Success",
    "StartTime": "Nov 29, 2016 7:43:20 PM",
    "EndTime": "Nov 29, 2016 7:43:26 PM",
    "Time": 5753.0,
    "ExecutedBy": "arn:aws:iam::123456789012:user/userName"
  }
}

最後の “detail.ExecutedBy” フィールドは実行されたユーザの ARN になっています。
今回のEC2起動停止では、”スケジュール実行で SSM Automation を実行するルール”を定義しているため、
この箇所はイベントルールに設定した実行ロールの assumed-role ARN が含まれる形になります。
これを指定すれば実行元のロールも監視条件に含めることができます。
ただし、実際の assumed-role ARN は以下の形式になります。

"arn:aws:sts::[account-id]:assumed-role/[role-name]/[role-session-name]"

ロールセッション名については、イベントルールの実行ロール設定時に AWS側で設定されるようです。
ロールセッション名がルールの実行毎に変わってしまうと、正常に監視できないことになりますが、
現状の挙動を観察する限りでは、実行ロールの変更を行わない限りは(時間によらず)変化しないようです。

ただしドキュメント等に記載されている仕様ではないため、今後予告なく挙動が変わる可能性が大いにあります。
プロダクション環境等での設定はおすすめできませんので参考情報として最後に記載させていただきました。

続きを読む

Amazon Linux と Amazon Linux 2 の技術面の違い

Amazon Linux 向けに書いた Ansible Playbook を Amazon Linux 2 に対応させるときに気づいた点をまとめておきます。

個人ブログに書いた「Ansible で Amazon Linux と Amazon Linux 2 を見分ける」も参考にしてください。

TL;DR

Amazon Linux はもともと CentOS とよく似た構成なので、概ね CentOS 6 から 7 への変更点と同じです。

大きな変更点

init デーモン

init デーモンが Upstart から systemd に変更されています。 pstree コマンドで見ると PID 1 のデーモンが init から systemd に変わっていることがわかります。

Amazon_Linux_2
$ pstree -p --ascii
systemd(1)-+-agetty(3177)
           |-agetty(3178)
           |-amazon-ssm-agen(3204)-+-{amazon-ssm-agen}(3208)
           |                       |-{amazon-ssm-agen}(3209)
           |                       |-{amazon-ssm-agen}(3210)
           |                       |-{amazon-ssm-agen}(3211)
           |                       |-{amazon-ssm-agen}(3212)
           |                       |-{amazon-ssm-agen}(3213)
           |                       `-{amazon-ssm-agen}(3215)
           |-atd(3162)
           |-auditd(2567)---{auditd}(2568)
           |-chronyd(2630)
           |-crond(3164)
(snip)
Amazon_Linux
$ pstree -p --ascii
init(1)-+-acpid(2415)
        |-agetty(2605)
        |-amazon-ssm-agen(2250)-+-{amazon-ssm-agen}(2262)
        |                       |-{amazon-ssm-agen}(2263)
        |                       |-{amazon-ssm-agen}(2264)
        |                       |-{amazon-ssm-agen}(2265)
        |                       |-{amazon-ssm-agen}(2266)
        |                       |-{amazon-ssm-agen}(2271)
        |                       |-{amazon-ssm-agen}(2281)
        |                       |-{amazon-ssm-agen}(2282)
        |                       `-{amazon-ssm-agen}(2638)
        |-atd(2580)
        |-auditd(2258)---{auditd}(2259)
        |-crond(2566)
(snip)

ファイルシステム

ファイルシステムが ext4 から xfs に変更されています。

Amazon_Linux_2
$ df -T /dev/xvda1
Filesystem     Type 1K-blocks    Used Available Use% Mounted on
/dev/xvda1     xfs    8376300 1055844   7320456  13% /
Amazon_Linux
$ df -T /dev/xvda1
Filesystem     Type 1K-blocks    Used Available Use% Mounted on
/dev/xvda1     ext4   8123812 1072296   6951268  14% /

軽微な変更点

ユーザー

ec2-user の uid と gid が 500 から 1000 に変更されています。

Amazon_Linux_2
$ id
uid=1000(ec2-user) gid=1000(ec2-user) groups=1000(ec2-user),4(adm),10(wheel),190(systemd-journal)
Amazon_Linux
$ id
uid=500(ec2-user) gid=500(ec2-user) groups=500(ec2-user),10(wheel)

パッケージ管理

Yum リポジトリがひとつに集約されました。 /etc/yum.repos.d/ 以下を見ると、epel リポジトリが削除されたことがわかります。

Amazon_Linux_2
$ yum repolist
Loaded plugins: langpacks, update-motd
repo id                            repo name                              status
!amzn2-core/2017.12/x86_64         Amazon Linux 2 core repository         7,102
repolist: 7,102

$ ls -l /etc/yum.repos.d/
total 4
-rw-r--r-- 1 root root 1003 Dec 12 20:52 amzn2-core.repo
Amazon_Linux
$ yum repolist
Loaded plugins: priorities, update-motd, upgrade-helper
repo id                               repo name                           status
!amzn-main/latest                     amzn-main-Base                      5,883
!amzn-updates/latest                  amzn-updates-Base                     738
repolist: 6,621

$ ls -l /etc/yum.repos.d/
total 24
-rw-r--r-- 1 root root 1014 Nov  1 19:45 amzn-main.repo
-rw-r--r-- 1 root root  327 Nov  1 19:45 amzn-nosrc.repo
-rw-r--r-- 1 root root 1041 Nov  1 19:45 amzn-preview.repo
-rw-r--r-- 1 root root 1041 Nov  1 19:45 amzn-updates.repo
-rw-r--r-- 1 root root  957 Mar  1  2013 epel.repo
-rw-r--r-- 1 root root 1056 Mar  1  2013 epel-testing.repo

NTP クライアント

NTP クライアントが ntpd から chronyd に変更されています。

Amazon_Linux_2
$ ps aux | grep -e ntpd -e chronyd
chrony    2633  0.0  0.8 120480  4356 ?        S    22:53   0:00 /usr/sbin/chronyd
Amazon_Linux
$ ps aux | grep -e ntpd -e chronyd
ntp       2506  0.0  0.8  29772  4280 ?        Ss   22:53   0:00 ntpd -u ntp:ntp -p /var/run/ntpd.pid -g

MTA

MTA が Sendmail から Postfix に変更されています。

Amazon_Linux_2
$ alternatives --display mta
mta - status is auto.
 link currently points to /usr/sbin/sendmail.postfix
/usr/sbin/sendmail.postfix - priority 30
 slave mta-mailq: /usr/bin/mailq.postfix
 slave mta-newaliases: /usr/bin/newaliases.postfix
 slave mta-pam: /etc/pam.d/smtp.postfix
 slave mta-rmail: /usr/bin/rmail.postfix
 slave mta-sendmail: /usr/lib/sendmail.postfix
 slave mta-mailqman: /usr/share/man/man1/mailq.postfix.1.gz
 slave mta-newaliasesman: /usr/share/man/man1/newaliases.postfix.1.gz
 slave mta-sendmailman: /usr/share/man/man1/sendmail.postfix.1.gz
 slave mta-aliasesman: /usr/share/man/man5/aliases.postfix.5.gz
Current `best' version is /usr/sbin/sendmail.postfix.
Amazon_Linux
$ alternatives --display mta
mta - status is auto.
 link currently points to /usr/sbin/sendmail.sendmail
/usr/sbin/sendmail.sendmail - priority 90
 slave mta-mailq: /usr/bin/mailq.sendmail
 slave mta-newaliases: /usr/bin/newaliases.sendmail
 slave mta-rmail: /usr/bin/rmail.sendmail
 slave mta-sendmail: /usr/lib/sendmail.sendmail
 slave mta-pam: /etc/pam.d/smtp.sendmail
 slave mta-sendmailman: /usr/share/man/man8/sendmail.sendmail.8.gz
 slave mta-mailqman: /usr/share/man/man1/mailq.sendmail.1.gz
 slave mta-newaliasesman: /usr/share/man/man1/newaliases.sendmail.1.gz
 slave mta-aliasesman: /usr/share/man/man5/aliases.sendmail.5.gz
Current `best' version is /usr/sbin/sendmail.sendmail.

まとめ

ひとつの Playbook の中で Amazon Linux と Amazon Linux 2 に対応するのはなかなか大変なので、fork して別の Playbook を書いたほうが楽かもしれませんね。

続きを読む

SSL証明書の有効期限監視をLambda+CloudWatchで実装する

SSL証明書の有効期限をLambdaで取得し、CloudWatchにカスタムメトリクスを送り、CloudWatch Alarmで通知する

AWS上のEC2インスタンスや各種サービスの監視を行う際、CloudWatch Alarmを活用しているケースは多いと思います。
このような場面を想定し、Lambdaで毎日SSL証明書の有効期限チェックを行い、CloudWatchに各ドメインの残日数を送り、その日数をターゲットとしたCloudWatch Alarmを設定することができるようにしたいと思います。

環境

ランタイム:node.js 6.10
開発環境:AWS Cloud9

監視対象の管理

監視対象のドメインは適宜増減することが想定されます。
これらを簡単に管理するために、今回はAWS Systems Manager のパラメータストアにて管理を行います。

パラメータストアに、下記のようなパラメータを登録します。

項目 内容
キー名 /monitor/certificate/domains
タイプ 文字列
[ “hogehoge.com”, “example.com” ]

上記のようにチェックを行うドメインをJSON配列形式で設置します。

Lambdaコード

下記ので実装できます。
※child-process-promise を使用していますが、モジュールのインストールを別途行わなくてもよい
 child_processを使っても良いと思います。(全てをPromiseで統一したかったのであえてchild-process-promiseを使っています)

index.js
const AWS = require('aws-sdk');
var SSM;
var CW;

exports.handler = (event, context, callback) => {
  if(SSM===undefined){
    SSM = new AWS.SSM({region: 'ap-northeast-1'});
  }
  if(CW===undefined){
    CW = new AWS.CloudWatch({region: 'ap-northeast-1'});
  }

  Promise.resolve()
  .then(()=>{
    return new Promise((resolve)=>{
      let ssm_params = {
        Name: "/monitor/certificate/domains"
      };
      let ssm_parameter = SSM.getParameter(ssm_params).promise();
      ssm_parameter.then((data)=>{
        resolve(JSON.parse(data.Parameter.Value));
      });
    });
  })
  .then((domains)=>{
    return new Promise((resolve)=>{
      let check_expire_list = [];
      domains.forEach((domain)=>{
        check_expire_list.push(checkExpire(domain));
      });
      Promise.all(check_expire_list)
      .then((result_valid)=>{
        resolve(result_valid);
      });
    });
  })
  .then((valid_list)=>{
    return new Promise((resolve)=>{
      let metric_list = [];
      valid_list.forEach((result)=>{
        var params = {
          MetricData: [
            {
              MetricName: 'valid_days',
              Dimensions: [
                {
                  Name: 'domain',
                  Value: result.domain
                }
              ],
              Unit: 'None',
              Value: result.valid_days
            }
          ],
          Namespace: 'SSLCertificate'
        };
        metric_list.push(CW.putMetricData(params).promise());
      });
      Promise.all(metric_list)
      .then((data)=>{
        resolve();
      });
    });
  })
  .then(()=>{
    callback();
  });
};

var checkExpire = (domain)=>{
  return new Promise((resolve)=>{
    let exec = require('child-process-promise').exec;
    let cmd = "openssl s_client -connect " + domain + ":443 -servername " + domain + " < /dev/null 2> /dev/null | openssl x509 -text | grep Not | sed -e 's/^  *//g' | sed -e 's/Not.*: //g'";
    let now = new Date();
    exec(cmd)
    .then((result)=>{
      let not = result.stdout.split("n");
      let expire_date = new Date(not[1]);
      let valid_days = Math.floor((expire_date - now) / 1000 / 3600 / 24);
      console.log(domain+" の残り日数は "+valid_days + " です");
      resolve({'domain': domain,'valid_days': valid_days});
    });
  });
};

SAM Template(CloudFormation)

上記のコードをデプロイするためのSAMテンプレートとして、下記のテンプレートでデプロイすることで、CloudWatchEventsにて毎日実行する設定を同時に行われます。

template.yaml
AWSTemplateFormatVersion: '2010-09-09'
Transform: 'AWS::Serverless-2016-10-31'
Description: SSL certificate monitoring function.
Resources:
  monitorCertExpire:
    Type: 'AWS::Serverless::Function'
    Properties:
      Handler: monitorCertExpire/index.handler
      Runtime: nodejs6.10
      Description: ''
      MemorySize: 256
      Timeout: 300
      Events:
        CheckExpire:
          Type: Schedule
          Properties:
            Schedule: rate(1 day)
            Input: "{}"

CloudWatch

上記をデプロイすることで、CloudWatchメトリクスに 名前空間:SSLCertificate メトリック:valid_days で有効期限切れまでの残り日数が毎日送信されます。

このメトリックデータを使用し、間隔:1日 統計:最小 期間:1中1のデータポイント にて、アラートさせたい日数をしきい値としてアラームを設定することでこれまで通り他の監視と同様に扱うことができます。

参考にさせていただきました

https://qiita.com/zwirky/items/25b1a66dac534f67ca03
https://blog.manabusakai.com/2016/07/lambda-cert-expire/

続きを読む

Go – AWS SSM Parameter Storeのデータを復号化とmockテストの書き方

SSMとは? SSM ParameterStoreとは? 実際にやってみよう 1. ParameterStoreの登録 2. aws-cliで試してみる 3. Goで動かす 4. テストを書く SSMとは? インフラ運用を便利にするサービス SSM ParameterStoreとは? パスワードなど値を管理 KMSを使… 続きを読む

カテゴリー 未分類 | タグ