2018年10月8日月曜日

slack + errbot(python)でAWSリソースを表示してみる


Slackとpython製の errbot を使用して、以下の動作を試してみた。

 1) Slack に "!subnet search" と入力する
 2) ボットがAWSを検索してサブネット一覧を取得する
 3) サブネット一覧をSlackに表示する

errbot は VirtualBox(CentOS7)のDockerコンテナで動かします。


1.errbot のDockerイメージ作成



Dockerfileは以下のようにしました。
FROM python:3.5.2-alpine

# apk update
RUN apk update

# for errbot
RUN apk add gcc g++ libffi-dev openssl-dev

# for develop
RUN apk add vim bash

# errbot, boto3
RUN pip install errbot slackclient boto3

# aws accesskey
ADD .aws /root/.aws

# errbot external plugins
ADD errbot-root /errbot-root

# entrypoint
ENV OPT ""
Entrypoint cd /errbot-root && errbot $OPT

ディレクトリ構成は以下のとおり。
errbot-root は空です。.aws には config と credentials があります。
[root@centos702 errbot]# ls -al
合計 4
drwxr-xr-x 5 root root  74 10月  8 11:18 .
drwxr-xr-x 4 root root  37 10月  6 21:45 ..
drwxr-xr-x 2 root root  56 10月  8 00:45 .aws
-rw-r--r-- 1 root root 365 10月  8 11:17 Dockerfile
drwxr-xr-x 2 root root   6 10月  8 11:19 errbot-root

Dockerイメージをビルドします。
[root@centos702 errbot]# docker build . -t bot

2.errbot の初期化と動作確認


errbot を初期化します。
[root@centos702 slackbot]# docker run --rm -v `pwd`/errbot-root:/errbot-root --env "OPT=--init" -it bot
Your Errbot directory has been correctly initialized !
Just do "errbot" and it should start in text/development mode.

空だったerrbot-root ディレクトリに、設定ファイルと 拡張プラグインのひな形が作成されます。
[root@centos702 errbot]# ls -l errbot-root
合計 4
-rw-r--r-- 1 root root 680 10月  8 11:42 config.py
drwxr-xr-x 2 root root   6 10月  8 11:42 data
drwxr-xr-x 3 root root  24 10月  8 11:42 plugins

errbot を起動します。
[root@centos702 errbot]# docker run --rm -v `pwd`/errbot-root:/errbot-root --env "OPT=--text" -it bot
02:45:47 INFO     errbot.specific_plugin_ma storage search paths {'/usr/local/lib/python3.5/site-packages/errbot/storage'}
02:45:47 INFO     errbot.specific_plugin_ma Found those plugings available:
02:45:47 INFO     errbot.specific_plugin_ma         Memory  (/usr/local/lib/python3.5/site-packages/errbot/storage/memory.py)
02:45:47 INFO     errbot.specific_plugin_ma          Shelf  (/usr/local/lib/python3.5/site-packages/errbot/storage/shelf.py)
02:45:47 INFO     errbot.bootstrap          Found Storage plugin: 'Shelf'
Description: This is the storage plugin for the traditional shelf store for errbot.
02:45:47 DEBUG    errbot.specific_plugin_ma Refilter the plugins...
02:45:47 DEBUG    errbot.specific_plugin_ma Load the one remaining...
02:45:47 DEBUG    errbot.specific_plugin_ma Class to load ShelfStoragePlugin
02:45:47 DEBUG    errbot.storage            Opening storage 'repomgr'
02:45:47 DEBUG    errbot.storage.shelf      Open shelf storage /errbot-root/data/repomgr.db
02:45:47 DEBUG    errbot.storage            Opening storage 'core'
02:45:47 DEBUG    errbot.storage.shelf      Open shelf storage /errbot-root/data/core.db
02:45:47 INFO     errbot.specific_plugin_ma backends search paths {'/usr/local/lib/python3.5/site-packages/errbot/backends'}
02:45:47 INFO     errbot.specific_plugin_ma Found those plugings available:
02:45:47 INFO     errbot.specific_plugin_ma        Graphic  (/usr/local/lib/python3.5/site-packages/errbot/backends/graphic.py)
02:45:47 INFO     errbot.specific_plugin_ma        Hipchat  (/usr/local/lib/python3.5/site-packages/errbot/backends/hipchat.py)
02:45:47 INFO     errbot.specific_plugin_ma            IRC  (/usr/local/lib/python3.5/site-packages/errbot/backends/irc.py)
02:45:47 INFO     errbot.specific_plugin_ma           Null  (/usr/local/lib/python3.5/site-packages/errbot/backends/null.py)
02:45:47 INFO     errbot.specific_plugin_ma          Slack  (/usr/local/lib/python3.5/site-packages/errbot/backends/slack.py)
02:45:47 INFO     errbot.specific_plugin_ma       Telegram  (/usr/local/lib/python3.5/site-packages/errbot/backends/telegram_messenger.py)
02:45:47 INFO     errbot.specific_plugin_ma           Test  (/usr/local/lib/python3.5/site-packages/errbot/backends/test.py)
02:45:47 INFO     errbot.specific_plugin_ma           Text  (/usr/local/lib/python3.5/site-packages/errbot/backends/text.py)
02:45:47 INFO     errbot.specific_plugin_ma           XMPP  (/usr/local/lib/python3.5/site-packages/errbot/backends/xmpp.py)
02:45:47 INFO     errbot.bootstrap          Found Backend plugin: 'Text'
                                                Description: This is the text backend for Err.
02:45:47 DEBUG    errbot.specific_plugin_ma Refilter the plugins...
02:45:47 DEBUG    errbot.specific_plugin_ma Load the one remaining...
02:45:47 DEBUG    errbot.specific_plugin_ma Class to load TextBackend
02:45:47 DEBUG    errbot.core               ErrBot init.
02:45:47 DEBUG    errbot.backends.base      Backend init.
02:45:47 DEBUG    errbot.core               created a thread pool of size 10.
02:45:47 DEBUG    errbot.backends.text      Text Backend Init.
02:45:47 DEBUG    errbot.backends.text      Bot username set at @errbot.
02:45:47 DEBUG    MARKDOWN                  Successfully loaded extension "markdown.extensions.fenced_code.FencedCodeExtension".
02:45:47 DEBUG    MARKDOWN                  Successfully loaded extension "markdown.extensions.footnotes.FootnoteExtension".
02:45:47 DEBUG    MARKDOWN                  Successfully loaded extension "markdown.extensions.attr_list.AttrListExtension".
02:45:47 DEBUG    MARKDOWN                  Successfully loaded extension "markdown.extensions.def_list.DefListExtension".
02:45:47 DEBUG    MARKDOWN                  Successfully loaded extension "markdown.extensions.tables.TableExtension".
02:45:47 DEBUG    MARKDOWN                  Successfully loaded extension "markdown.extensions.abbr.AbbrExtension".
02:45:47 DEBUG    MARKDOWN                  Successfully loaded extension "markdown.extensions.extra.ExtraExtension".
02:45:47 DEBUG    MARKDOWN                  Successfully loaded extension "errbot.rendering.ansiext.AnsiExtension".
02:45:47 DEBUG    errbot.core               Initializing backend storage
02:45:47 DEBUG    errbot.storage            Opening storage 'text_backend'
02:45:47 DEBUG    errbot.storage.shelf      Open shelf storage /errbot-root/data/text_backend.db
02:45:47 DEBUG    errbot.plugin_manager     All plugin roots:
02:45:47 DEBUG    errbot.plugin_manager     -> /usr/local/lib/python3.5/site-packages/errbot/core_plugins
02:45:47 DEBUG    errbot.plugin_manager     Add /usr/local/lib/python3.5/site-packages/errbot/core_plugins to sys.path
02:45:47 DEBUG    errbot.plugin_manager     -> /errbot-root/plugins/err-example
02:45:47 DEBUG    errbot.plugin_manager     Add /errbot-root/plugins/err-example to sys.path
02:45:47 DEBUG    errbot.plugin_manager     /usr/local/lib/python3.5/site-packages/errbot/core_plugins has no requirements.txt file
02:45:47 DEBUG    errbot.plugin_manager     /errbot-root/plugins/err-example has no requirements.txt file
02:45:47 DEBUG    errbot.plugins.ACLs       Logger for plugin initialized...
02:45:47 DEBUG    errbot.plugins.Backup     Logger for plugin initialized...
02:45:47 DEBUG    errbot.plugins.ChatRoom   Logger for plugin initialized...
02:45:47 DEBUG    errbot.plugins.CommandNot Logger for plugin initialized...
02:45:47 DEBUG    errbot.plugins.Flows      Logger for plugin initialized...
02:45:47 DEBUG    errbot.plugins.Health     Logger for plugin initialized...
02:45:47 DEBUG    errbot.plugins.Help       Logger for plugin initialized...
02:45:47 DEBUG    errbot.plugins.Plugins    Logger for plugin initialized...
02:45:47 DEBUG    errbot.plugins.TextCmds   Logger for plugin initialized...
02:45:47 DEBUG    errbot.plugins.Utils      Logger for plugin initialized...
02:45:48 DEBUG    errbot.plugins.VersionChe Logger for plugin initialized...
02:45:48 INFO     errbot                    webhooks:  Flag to bind /echo to                           echo
02:45:48 DEBUG    errbot.plugins.Webserver  Logger for plugin initialized...
02:45:48 DEBUG    errbot.plugins.Example    Logger for plugin initialized...
02:45:48 DEBUG    errbot.bootstrap          Start serving commands from the text backend
────────────────────────────────────────────────────────────────────────────────
 You start as a bot admin in a one-on-one conversation with the bot.

    Context of the chat

• Use !inroom to switch to a room conversation.
• Use !inperson to switch back to a one-on-one conversation.
• Use !asuser to talk as a normal user.
• Use !asadmin to switch back as a bot admin.

    Preferences

• Use !ml to flip on/off the multiline mode (Enter twice at the end to send).
────────────────────────────────────────────────────────────────────────────────

[@CHANGE_ME ➡ @errbot] >>> 

!tryme と入力してENTERし、It works ! と表示されたらOKです。
Ctrl+Dで終了します。
[@CHANGE_ME ➡ @errbot] >>> !tryme
It works !

[@CHANGE_ME ➡ @errbot] >>> [root@centos702 errbot]#


3.SlackでBotの作成


チャット画面の左メニューのApp の横にある[+] をクリックします。

[Appディレクトリ表示]をクリックします。

[ビルド]をクリックします。

[Start Building]をクリックします。

[AppName], [Development Slack Workspace]を入力して、[CreateApp]をクリックします。

[Bot Users]をクリックします。

[Add a Bot User]をクリックします。

[Add Bot User] をクリックします。

[Install App]をクリックします。

[Install App to Workspace] をクリックします。

[許可する]をクリックします。

[Bot User OAuth Access Token] を、errbot の設定で使用します。

あとで、Appの設定変更/確認したい場合は、[YourApp]をクリックします。
下図のようにAppの一覧が表示されるので、見たいAppをクリックします。

チャット画面にAppが追加されます。

4.errbot のSlack対応


errbot の config.py を修正します。修正ポイントは次のとおり。
・BACKENDは Slack に変更
・BOT_IDENTITY を追加。tokenには、上記3で作成したAppの Bot User OAuth Access Token を設定
・BOT_LOG_LEVELを logging.INFO に変更
[root@centos702 errbot]# cat errbot-root/config.py
import logging

# This is a minimal configuration to get you started with the Text mode.
# If you want to connect Errbot to chat services, checkout
# the options in the more complete config-template.py from here:
# https://raw.githubusercontent.com/errbotio/errbot/master/errbot/config-templat                                                           e.py

BACKEND = 'Slack'  # Errbot will start in text mode (console only mode) and will                                                            answer commands from there.

BOT_DATA_DIR = r'/errbot-root/data'
BOT_EXTRA_PLUGIN_DIR = r'/errbot-root/plugins'

BOT_LOG_FILE = r'/errbot-root/errbot.log'
BOT_LOG_LEVEL = logging.INFO

BOT_ADMINS = ('@blue21', )  # !! Don't leave that to "@CHANGE_ME" if you connect                                                            your errbot to a chat system !!

BOT_IDENTITY = {
    'token': 'xoxb-*******************************************'
}


5.errbot の拡張プラグイン作成


プラグインを格納するディレクトリを作成します。
[root@centos702 errbot]# mkdir errbot-root/plugins/aws

aws.plug を作成します。
[root@centos702 errbot]# cat errbot-root/plugins/aws/aws.plug
[Core]
Name = Aws
Module = aws

[Documentation]
Description = example aws.

[Python]
Version = 2+

aws.py を作成します。
[root@centos702 errbot]# cat errbot-root/plugins/aws/aws.py
import boto3
from errbot import BotPlugin, botcmd, arg_botcmd

class Aws(BotPlugin):

    @arg_botcmd('--key', dest='key', type=str, default='*')
    def subnet_search(self, msg, key=None):

        yield "検索中です ..."

        client = boto3.client('ec2')
        response = client.describe_subnets(
            Filters=[
                {
                    'Name': 'tag:Name',
                    'Values': [
                        key,
                    ]
                },
            ]
        )

        t=()
        for s in response['Subnets']:
            nm = [x['Value'] for x in s['Tags'] if x['Key'] == 'Name'][0]
            cidr = s['CidrBlock']
            t+=((nm,cidr),)

        self.send_card(title='** AWS Subnet List **',
                       body='検索キーワード=> ' + key,
                       color='green',
                       fields=t,
                       in_reply_to=msg)


6.動作確認


errbot を起動します。
[root@centos702 errbot]# docker run --rm -v `pwd`/errbot-root:/errbot-root -it bot
08:51:58 INFO     errbot.specific_plugin_ma storage search paths {'/usr/local/lib/python3.5/site-packages/errbot/storage'}
08:51:58 INFO     errbot.specific_plugin_ma Found those plugings available:
08:51:58 INFO     errbot.specific_plugin_ma         Memory  (/usr/local/lib/python3.5/site-packages/errbot/storage/memory.py)
08:51:58 INFO     errbot.specific_plugin_ma          Shelf  (/usr/local/lib/python3.5/site-packages/errbot/storage/shelf.py)
08:51:58 INFO     errbot.bootstrap          Found Storage plugin: 'Shelf'
Description: This is the storage plugin for the traditional shelf store for errbot.
08:51:58 INFO     errbot.specific_plugin_ma backends search paths {'/usr/local/lib/python3.5/site-packages/errbot/backends'}
08:51:58 INFO     errbot.specific_plugin_ma Found those plugings available:
08:51:58 INFO     errbot.specific_plugin_ma        Graphic  (/usr/local/lib/python3.5/site-packages/errbot/backends/graphic.py)
08:51:58 INFO     errbot.specific_plugin_ma        Hipchat  (/usr/local/lib/python3.5/site-packages/errbot/backends/hipchat.py)
08:51:58 INFO     errbot.specific_plugin_ma            IRC  (/usr/local/lib/python3.5/site-packages/errbot/backends/irc.py)
08:51:58 INFO     errbot.specific_plugin_ma           Null  (/usr/local/lib/python3.5/site-packages/errbot/backends/null.py)
08:51:58 INFO     errbot.specific_plugin_ma          Slack  (/usr/local/lib/python3.5/site-packages/errbot/backends/slack.py)
08:51:58 INFO     errbot.specific_plugin_ma       Telegram  (/usr/local/lib/python3.5/site-packages/errbot/backends/telegram_messenger.py)
08:51:58 INFO     errbot.specific_plugin_ma           Test  (/usr/local/lib/python3.5/site-packages/errbot/backends/test.py)
08:51:58 INFO     errbot.specific_plugin_ma           Text  (/usr/local/lib/python3.5/site-packages/errbot/backends/text.py)
08:51:58 INFO     errbot.specific_plugin_ma           XMPP  (/usr/local/lib/python3.5/site-packages/errbot/backends/xmpp.py)
08:51:58 INFO     errbot.bootstrap          Found Backend plugin: 'Slack'
                                                Description: This is the slack backend for Err.
08:52:01 INFO     errbot                    webhooks:  Flag to bind /echo to                           echo
08:52:01 INFO     errbot.backends.slack     Verifying authentication token
08:52:02 INFO     errbot.backends.slack     Connecting to Slack real-time-messaging API
08:52:03 INFO     errbot.backends.slack     Connected
08:52:03 INFO     errbot.core               Activate internal commands
08:52:03 INFO     errbot.plugin_manager     Activate bot plugins...
08:52:03 INFO     errbot.plugin_manager     Activate plugin: Aws
08:52:03 INFO     errbot.plugin_manager     Activating Aws with min_err_version = 5.2.0 and max_version = 5.2.0
08:52:03 INFO     errbot.core_plugins.wsvie Checking Aws for webhooks
08:52:03 INFO     errbot.plugin_manager     Activate plugin: Example
08:52:03 INFO     errbot.plugin_manager     Activating Example with min_err_version = 5.2.0 and max_version = 5.2.0
08:52:03 INFO     errbot.core_plugins.wsvie Checking Example for webhooks
08:52:03 INFO     errbot.plugin_manager     Activate plugin: ACLs
08:52:03 INFO     errbot.plugin_manager     Activating ACLs with min_err_version = 5.2.0 and max_version = 5.2.0
08:52:03 INFO     errbot.core_plugins.wsvie Checking ACLS for webhooks
08:52:03 INFO     errbot.plugin_manager     Activate plugin: Backup
08:52:03 INFO     errbot.plugin_manager     Activating Backup with min_err_version = 5.2.0 and max_version = 5.2.0
08:52:03 INFO     errbot.core_plugins.wsvie Checking Backup for webhooks
08:52:03 INFO     errbot.plugin_manager     Activate plugin: ChatRoom
08:52:03 INFO     errbot.plugin_manager     Activating ChatRoom with min_err_version = 5.2.0 and max_version = 5.2.0
08:52:03 INFO     errbot.core_plugins.wsvie Checking ChatRoom for webhooks
08:52:03 INFO     errbot.plugin_manager     Activate plugin: CommandNotFoundFilter
08:52:03 INFO     errbot.plugin_manager     Activating CommandNotFoundFilter with min_err_version = 5.2.0 and max_version = 5.2.0
08:52:03 INFO     errbot.core_plugins.wsvie Checking CommandNotFoundFilter for webhooks
08:52:03 INFO     errbot.plugin_manager     Activate plugin: Flows
08:52:03 INFO     errbot.plugin_manager     Activating Flows with min_err_version = 5.2.0 and max_version = 5.2.0
08:52:03 INFO     errbot.core_plugins.wsvie Checking Flows for webhooks
08:52:03 INFO     errbot.plugin_manager     Activate plugin: Health
08:52:03 INFO     errbot.plugin_manager     Activating Health with min_err_version = 5.2.0 and max_version = 5.2.0
08:52:03 INFO     errbot.core_plugins.wsvie Checking Health for webhooks
08:52:03 INFO     errbot.plugin_manager     Activate plugin: Help
08:52:03 INFO     errbot.plugin_manager     Activating Help with min_err_version = 5.2.0 and max_version = 5.2.0
08:52:03 INFO     errbot.core_plugins.wsvie Checking Help for webhooks
08:52:03 INFO     errbot.plugin_manager     Activate plugin: Plugins
08:52:03 INFO     errbot.plugin_manager     Activating Plugins with min_err_version = 5.2.0 and max_version = 5.2.0
08:52:03 INFO     errbot.core_plugins.wsvie Checking Plugins for webhooks
08:52:03 INFO     errbot.plugin_manager     Activate plugin: TextCmds
08:52:03 INFO     errbot.plugin_manager     Plugin TextCmds has no section [Python]. Assuming this plugin is running only under python 3.
08:52:03 INFO     errbot.plugin_manager     Activating TextCmds with min_err_version = 5.2.0 and max_version = 5.2.0
08:52:03 INFO     errbot.core_plugins.wsvie Checking TextModeCmds for webhooks
08:52:03 INFO     errbot.plugin_manager     Activate plugin: Utils
08:52:03 INFO     errbot.plugin_manager     Activating Utils with min_err_version = 5.2.0 and max_version = 5.2.0
08:52:03 INFO     errbot.core_plugins.wsvie Checking Utils for webhooks
08:52:03 INFO     errbot.plugin_manager     Activate plugin: VersionChecker
08:52:03 INFO     errbot.plugin_manager     Activating VersionChecker with min_err_version = 5.2.0 and max_version = 5.2.0
08:52:03 INFO     errbot.core_plugins.wsvie Checking VersionChecker for webhooks
08:52:03 INFO     errbot.plugin_manager     Activate plugin: Webserver
08:52:03 INFO     errbot.plugin_manager     Activating Webserver with min_err_version = 5.2.0 and max_version = 5.2.0
08:52:03 INFO     errbot.plugins.Webserver  Webserver is not configured. Forbid activation
08:52:03 INFO     errbot.core_plugins.wsvie Checking Webserver for webhooks
08:52:03 INFO     errbot.core_plugins.wsvie Webhook routing echo
08:52:03 INFO     errbot.core
08:52:03 INFO     errbot.core               Notifying connection to all the plugins...
08:52:03 INFO     errbot.plugins.ChatRoom   Callback_connect
08:52:03 INFO     errbot.core               Plugin activation done.

Slack で !tryme や !subnet search を入力すると、下図のように errbot が返信してくれます。




2018年8月23日木曜日

ハイブリッド環境にCloudWatchAgentをインストール


下記URLを参考にVirtualBoxのVM(CentOS7)に CloudWatchAgent をインストールしてみます。
https://docs.aws.amazon.com/ja_jp/AmazonCloudWatch/latest/monitoring/install-CloudWatch-Agent-on-first-onprem.html


1.IAMユーザ作成


グループを作成します。
[root@centos701]# aws iam create-group --group-name WatchGroup
{
    "Group": {
        "Path": "/",
        "CreateDate": "2018-08-22T23:12:11Z",
        "GroupId": "AGPAJ4JOAVM6OWOBHN6NS",
        "Arn": "arn:aws:iam::0123456789:group/WatchGroup",
        "GroupName": "WatchGroup"
    }
}

ユーザを作成します。
[root@centos701]# aws iam create-user --user-name WatchUser
{
    "User": {
        "UserName": "WatchUser",
        "Path": "/",
        "CreateDate": "2018-08-22T23:12:13Z",
        "UserId": "AIDAJ3RIMXJMFJLANLUHG",
        "Arn": "arn:aws:iam::0123456789:user/WatchUser"
    }
}

ユーザをグループに追加します。
[root@centos701]# aws iam add-user-to-group --user-name WatchUser --group-name WatchGroup

グループを確認します。
[root@centos701]# aws iam get-group --group-name WatchGroup
{
    "Group": {
        "Path": "/",
        "CreateDate": "2018-08-22T23:12:11Z",
        "GroupId": "AGPAJ4JOAVM6OWOBHN6NS",
        "Arn": "arn:aws:iam::0123456789:group/WatchGroup",
        "GroupName": "WatchGroup"
    },
    "Users": [
        {
            "UserName": "WatchUser",
            "Path": "/",
            "CreateDate": "2018-08-22T23:12:13Z",
            "UserId": "AIDAJ3RIMXJMFJLANLUHG",
            "Arn": "arn:aws:iam::0123456789:user/WatchUser"
        }
    ]
}

グループにポリシーを設定します。
CloudWatchAgentの設定ファイルをSSMのパラメータストアに保存したいので、AmazonSSMFullAccess を設定しています。
[root@centos701]# aws iam attach-group-policy --policy-arn arn:aws:iam::aws:policy/CloudWatchAgentAdminPolicy --group-name WatchGroup
[root@centos701]# aws iam attach-group-policy --policy-arn arn:aws:iam::aws:policy/AmazonSSMFullAccess --group-name WatchGroup

グループに設定したポリシーを確認します。
[root@centos701]# aws iam list-attached-group-policies --group-name WatchGroup
{
    "AttachedPolicies": [
        {
            "PolicyName": "CloudWatchAgentAdminPolicy",
            "PolicyArn": "arn:aws:iam::aws:policy/CloudWatchAgentAdminPolicy"
        },
        {
            "PolicyName": "AmazonSSMFullAccess",
            "PolicyArn": "arn:aws:iam::aws:policy/AmazonSSMFullAccess"
        }
    ]
}

ユーザのアクセスキーを作成します。
[root@centos701]# aws iam create-access-key --user-name WatchUser
{
    "AccessKey": {
        "UserName": "WatchUser",
        "Status": "Active",
        "CreateDate": "2018-08-22T23:12:33Z",
        "SecretAccessKey": "xxxxxxxxxxxxxxxxxxxxx",
        "AccessKeyId": "AKIXXXXXXXXXXXXX"
    }
}

2.CloudWatchAgentのインストール


作業用のディレクトリを作成してCloudWatchAgentのパッケージをダウンロードします。
[root@centos701]# mkdir cw
[root@centos701]# cd cw
[root@centos701 cw]# curl -OL https://s3.amazonaws.com/amazoncloudwatch-agent/linux/amd64/latest/AmazonCloudWatchAgent.zip

アーカイブを解凍します。
[root@centos701 cw]# unzip AmazonCloudWatchAgent.zip

インストールスクリプトを実行します。
[root@centos701 cw]# ./install.sh
Created symlink from /etc/systemd/system/multi-user.target.wants/amazon-cloudwatch-agent.service to /etc/systemd/system/amazon-cloudwatch-agent.service.
Redirecting to /bin/systemctl restart amazon-cloudwatch-agent.service

3.aws-cli の設定


aws-cli のプロファイル(AmazonCloudWatchAgent)を作成します。
"aws configure --profile AmazonCloudWatchAgent" を実行するか、直接設定ファイルを修正します。

~/.aws/credentials に以下を追加します。上記1で作成したユーザのアクセスキーを設定します。
[AmazonCloudWatchAgent]
aws_access_key_id=AKIXXXXXXXXXXXXX
aws_secret_access_key=xxxxxxxxxxxxxxxxxxxxx

~/.aws/config に以下を追加します。
[profile AmazonCloudWatchAgent]
region = us-east-1

4.CludWatchAgentの設定ファイル作成


CloudWatchAgentの設定ファイルを作成します。
今回は、設定ファイルをサーバには保存しないで、SSMのパラメータストアに保存します。
また、収集するメトリックスは 「BASIC」、ログは、「/var/log/messages」とします。
[root@centos701]# /opt/aws/amazon-cloudwatch-agent/bin/amazon-cloudwatch-agent-config-wizard
=============================================================
= Welcome to the AWS CloudWatch Agent Configuration Manager =
=============================================================
On which OS are you planning to use the agent?
1. linux
2. windows
default choice: [1]:

Trying to fetch the default region based on ec2 metadata...
Are you using EC2 or On-Premises hosts?
1. EC2
2. On-Premises
default choice: [2]:

Please make sure the credentials and region set correctly on your hosts.
Refer to http://docs.aws.amazon.com/cli/latest/userguide/cli-chap-getting-started.html
Do you want to monitor any host metrics? e.g. CPU, memory, etc.
1. yes
2. no
default choice: [1]:

Do you want to monitor cpu metrics per core? Additional CloudWatch charges may apply.
1. yes
2. no
default choice: [1]:

Would you like to collect your metrics at high resolution (sub-minute resolution)? This enables sub-minute resolution for all metrics, but you can customize for specific metrics in the output json file.
1. 1s
2. 10s
3. 30s
4. 60s
default choice: [4]:

Which default metrics config do you want?
1. Basic
2. Standard
3. Advanced
4. None
default choice: [1]:

Current config as follows:
{
        "metrics": {
                "metrics_collected": {
                        "cpu": {
                                "measurement": [
                                        "cpu_usage_idle"
                                ],
                                "metrics_collection_interval": 60,
                                "resources": [
                                        "*"
                                ],
                                "totalcpu": true
                        },
                        "disk": {
                                "measurement": [
                                        "used_percent"
                                ],
                                "metrics_collection_interval": 60,
                                "resources": [
                                        "*"
                                ]
                        },
                        "diskio": {
                                "measurement": [
                                        "write_bytes",
                                        "read_bytes",
                                        "writes",
                                        "reads"
                                ],
                                "metrics_collection_interval": 60,
                                "resources": [
                                        "*"
                                ]
                        },
                        "mem": {
                                "measurement": [
                                        "mem_used_percent"
                                ],
                                "metrics_collection_interval": 60
                        },
                        "net": {
                                "measurement": [
                                        "bytes_sent",
                                        "bytes_recv",
                                        "packets_sent",
                                        "packets_recv"
                                ],
                                "metrics_collection_interval": 60,
                                "resources": [
                                        "*"
                                ]
                        },
                        "swap": {
                                "measurement": [
                                        "swap_used_percent"
                                ],
                                "metrics_collection_interval": 60
                        }
                }
        }
}
Are you satisfied with the above config? Note: it can be manually customized after the wizard completes to add additional items.
1. yes
2. no
default choice: [1]:

Do you have any existing CloudWatch Log Agent (http://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/AgentReference.html) configuration file to import for migration?
1. yes
2. no
default choice: [2]:

Do you want to monitor any log files?
1. yes
2. no
default choice: [1]:

Log file path:
/var/log/messages
Log group name:
default choice: [messages]

Do you want to specify any additional log files to monitor?
1. yes
2. no
default choice: [1]:
2
Saved config file to /opt/aws/amazon-cloudwatch-agent/bin/config.json successfully.
Current config as follows:
{
        "logs": {
                "logs_collected": {
                        "files": {
                                "collect_list": [
                                        {
                                                "file_path": "/var/log/messages",
                                                "log_group_name": "messages"
                                        }
                                ]
                        }
                }
        },
        "metrics": {
                "metrics_collected": {
                        "cpu": {
                                "measurement": [
                                        "cpu_usage_idle"
                                ],
                                "metrics_collection_interval": 60,
                                "resources": [
                                        "*"
                                ],
                                "totalcpu": true
                        },
                        "disk": {
                                "measurement": [
                                        "used_percent"
                                ],
                                "metrics_collection_interval": 60,
                                "resources": [
                                        "*"
                                ]
                        },
                        "diskio": {
                                "measurement": [
                                        "write_bytes",
                                        "read_bytes",
                                        "writes",
                                        "reads"
                                ],
                                "metrics_collection_interval": 60,
                                "resources": [
                                        "*"
                                ]
                        },
                        "mem": {
                                "measurement": [
                                        "mem_used_percent"
                                ],
                                "metrics_collection_interval": 60
                        },
                        "net": {
                                "measurement": [
                                        "bytes_sent",
                                        "bytes_recv",
                                        "packets_sent",
                                        "packets_recv"
                                ],
                                "metrics_collection_interval": 60,
                                "resources": [
                                        "*"
                                ]
                        },
                        "swap": {
                                "measurement": [
                                        "swap_used_percent"
                                ],
                                "metrics_collection_interval": 60
                        }
                }
        }
}
Please check the above content of the config.
The config file is also located at /opt/aws/amazon-cloudwatch-agent/bin/config.json.
Edit it manually if needed.
Do you want to store the config in the SSM parameter store?
1. yes
2. no
default choice: [1]:

What parameter store name do you want to use to store your config? (Use 'AmazonCloudWatch-' prefix if you use our managed AWS policy)
default choice: [AmazonCloudWatch-linux]

Which region do you want to store the config in the parameter store?
default choice: [us-east-1]

Which AWS credential should be used to send json config to parameter store?
1. AKIAIUPXXXXXXXX(From SDK)
2. AKIAJROXXXXXXXX(From Profile: AmazonCloudWatchAgent)
3. Other
default choice: [1]:
2
Successfully put config to parameter store AmazonCloudWatch-linux.
Program exits now.


パラメータストアに保存された内容を確認します。
[root@centos701 ~]# aws ssm get-parameter --name AmazonCloudWatch-linux
{
    "Parameter": {
        "Version": 1,
        "Type": "String",
        "Name": "AmazonCloudWatch-linux",
        "Value": "{\n\t\"logs\": {\n\t\t\"logs_collected\": {\n\t\t\t\"files\": {\n\t\t\t\t\"collect_list\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"file_path\": \"/var/log/messages\",\n\t\t\t\t\t\t\"log_group_name\": \"messages\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t}\n\t},\n\t\"metrics\": {\n\t\t\"metrics_collected\": {\n\t\t\t\"cpu\": {\n\t\t\t\t\"measurement\": [\n\t\t\t\t\t\"cpu_usage_idle\"\n\t\t\t\t],\n\t\t\t\t\"metrics_collection_interval\": 60,\n\t\t\t\t\"resources\": [\n\t\t\t\t\t\"*\"\n\t\t\t\t],\n\t\t\t\t\"totalcpu\": true\n\t\t\t},\n\t\t\t\"disk\": {\n\t\t\t\t\"measurement\": [\n\t\t\t\t\t\"used_percent\"\n\t\t\t\t],\n\t\t\t\t\"metrics_collection_interval\": 60,\n\t\t\t\t\"resources\": [\n\t\t\t\t\t\"*\"\n\t\t\t\t]\n\t\t\t},\n\t\t\t\"diskio\": {\n\t\t\t\t\"measurement\": [\n\t\t\t\t\t\"write_bytes\",\n\t\t\t\t\t\"read_bytes\",\n\t\t\t\t\t\"writes\",\n\t\t\t\t\t\"reads\"\n\t\t\t\t],\n\t\t\t\t\"metrics_collection_interval\": 60,\n\t\t\t\t\"resources\": [\n\t\t\t\t\t\"*\"\n\t\t\t\t]\n\t\t\t},\n\t\t\t\"mem\": {\n\t\t\t\t\"measurement\": [\n\t\t\t\t\t\"mem_used_percent\"\n\t\t\t\t],\n\t\t\t\t\"metrics_collection_interval\": 60\n\t\t\t},\n\t\t\t\"net\": {\n\t\t\t\t\"measurement\": [\n\t\t\t\t\t\"bytes_sent\",\n\t\t\t\t\t\"bytes_recv\",\n\t\t\t\t\t\"packets_sent\",\n\t\t\t\t\t\"packets_recv\"\n\t\t\t\t],\n\t\t\t\t\"metrics_collection_interval\": 60,\n\t\t\t\t\"resources\": [\n\t\t\t\t\t\"*\"\n\t\t\t\t]\n\t\t\t},\n\t\t\t\"swap\": {\n\t\t\t\t\"measurement\": [\n\t\t\t\t\t\"swap_used_percent\"\n\t\t\t\t],\n\t\t\t\t\"metrics_collection_interval\": 60\n\t\t\t}\n\t\t}\n\t}\n}"
    }
}

5.CloudWatchAgent を開始する


上記4でパラメータストアに保存した設定を変数で指定し、CloudWatchAgentを開始します。
[root@centos701]# /opt/aws/amazon-cloudwatch-agent/bin/amazon-cloudwatch-agent-ctl -a fetch-config -m onPremise -c ssm:AmazonCloudWatch-linux -s
/opt/aws/amazon-cloudwatch-agent/bin/config-downloader --output-file /opt/aws/amazon-cloudwatch-agent/etc/amazon-cloudwatch-agent.json --download-source ssm:AmazonCloudWatch-linux --mode onPrem --config /opt/aws/amazon-cloudwatch-agent/etc/common-config.toml
Got Home directory: /root
Set home dir Linux: /root
Start configuration validation...
/opt/aws/amazon-cloudwatch-agent/bin/config-translator --input /opt/aws/amazon-cloudwatch-agent/etc/amazon-cloudwatch-agent.json --output /opt/aws/amazon-cloudwatch-agent/etc/amazon-cloudwatch-agent.toml --mode onPrem --config /opt/aws/amazon-cloudwatch-agent/etc/common-config.toml
Valid Json input schema.
Got Home directory: /root
Got Home directory: /root
Set home dir Linux: /root
2018/08/23 08:28:07 E! ec2metadata is not available
2018/08/23 08:28:07 E! ec2metadata is not available
Under path : /logs/ | Info : Using centos701 as log_stream_name
Configuration validation first phase succeeded
/opt/aws/amazon-cloudwatch-agent/bin/amazon-cloudwatch-agent -schematest -config /opt/aws/amazon-cloudwatch-agent/etc/amazon-cloudwatch-agent.toml
Configuration validation second phase succeeded
Configuration validation succeeded
Redirecting to /bin/systemctl stop amazon-cloudwatch-agent.service
Redirecting to /bin/systemctl restart amazon-cloudwatch-agent.service

CloudWatchAgent が起動したことを確認します。
[root@centos701 cw]# systemctl status amazon-cloudwatch-agent
● amazon-cloudwatch-agent.service - Amazon CloudWatch Agent
   Loaded: loaded (/etc/systemd/system/amazon-cloudwatch-agent.service; enabled; vendor preset: disabled)
   Active: active (running) since 木 2018-08-23 08:28:07 JST; 4min 5s ago
 Main PID: 2361 (amazon-cloudwat)
   Memory: 12.1M
   CGroup: /system.slice/amazon-cloudwatch-agent.service
           └─2361 /opt/aws/amazon-cloudwatch-agent/bin/amazon-cloudwatch-agent -pidfile /opt/aws/amazon-cloudwa                               ..

 8月 23 08:28:10 centos701 start-amazon-cloudwatch-agent[2361]: Valid Json input schema.
 8月 23 08:28:10 centos701 start-amazon-cloudwatch-agent[2361]: Got Home directory: /root
 8月 23 08:28:10 centos701 start-amazon-cloudwatch-agent[2361]: Set home dir Linux: /root
 8月 23 08:28:10 centos701 start-amazon-cloudwatch-agent[2361]: Got Home directory: /root
 8月 23 08:28:11 centos701 start-amazon-cloudwatch-agent[2361]: 2018/08/23 08:28:11 E! ec2metadata is not availab
 8月 23 08:28:12 centos701 start-amazon-cloudwatch-agent[2361]: 2018/08/23 08:28:12 E! ec2metadata is not availab
 8月 23 08:28:12 centos701 start-amazon-cloudwatch-agent[2361]: Under path : /logs/ | Info : Using centos701 as l
 8月 23 08:28:12 centos701 start-amazon-cloudwatch-agent[2361]: Configuration validation first phase succeeded
 8月 23 08:28:12 centos701 start-amazon-cloudwatch-agent[2361]: 2018/08/23 08:28:12 I! AmazonCloudWatchAgent Vers
 8月 23 08:28:12 centos701 start-amazon-cloudwatch-agent[2361]: 2018/08/23 08:28:12 Seeked /var/log/messages - &{
Hint: Some lines were ellipsized, use -l to show in full.

CloudWatch に収集されているかメトリックスを確認します。
CloudWatchAgentで収集したメトリックスは、namespace が "CWAgent" になるようです。
[root@centos701 cw]# aws cloudwatch list-metrics --namespace CWAgent --output text | head
METRICS diskio_reads    CWAgent
DIMENSIONS      host    centos701
DIMENSIONS      name    sda
METRICS diskio_writes   CWAgent
DIMENSIONS      host    centos701
DIMENSIONS      name    sda
METRICS diskio_writes   CWAgent
DIMENSIONS      host    centos701
DIMENSIONS      name    sda2
METRICS diskio_reads    CWAgent

CloudWatchLogs に収集されているか確認します。
[root@centos701 cw]# aws logs describe-log-streams --log-group-name messages
{
    "logStreams": [
        {
            "firstEventTimestamp": 1534935120318,
            "lastEventTimestamp": 1534935680678,
            "creationTime": 1534935128402,
            "uploadSequenceToken": "49585417476964286413865313731794451232034865543907549378",
            "logStreamName": "centos701",
            "lastIngestionTime": 1534980791209,
            "arn": "arn:aws:logs:us-east-1:0123456789:log-group:messages:log-stream:centos701",
            "storedBytes": 0
        }
    ]
}

ログの内容を確認します。
[root@centos701 cw]# aws logs get-log-events --log-group-name messages --log-stream-name centos701 | head
{
    "nextForwardToken": "f/34231215160138873141677890916998199662103777254773620736",
    "events": [
        {
            "ingestionTime": 1534935129103,
            "timestamp": 1534935120318,
            "message": "Aug 22 16:21:42 [localhost] systemd: Time has been changed"
        },
        {
            "ingestionTime": 1534935129103,



2018年8月22日水曜日

ハイブリッド環境に SSMエージェントをインストール


下記URLを参考にVirtualBoxのCentOS7に SSMエージェントをインストールしてみます。
https://docs.aws.amazon.com/ja_jp/systems-manager/latest/userguide/systems-manager-managedinstances.html


1.IAMロールの作成


SSMService-Trust.json のファイル名で下記内容を保存します。
{
  "Version": "2012-10-17",
  "Statement": {
    "Effect": "Allow",
    "Principal": {"Service": "ssm.amazonaws.com"},
    "Action": "sts:AssumeRole"
  }
}

IAMロール(SSMServiceRole)を作成します。
[root@centos701 ~]# aws iam create-role --role-name SSMServiceRole --assume-role-policy-document file://SSMService-Trust.json

ポリシーを設定します。
[root@centos701 ~]# aws iam attach-role-policy --role-name SSMServiceRole --policy-arn arn:aws:iam::aws:policy/AmazonSSMFullAccess

2.SSMエージェントインストール


SSMエージェントをダウンロードします。
[root@centos701 ~]# curl -OL https://s3.region.amazonaws.com/amazon-ssm-region/latest/linux_amd64/amazon-ssm-agent.rpm

rpm をインストールします。
[root@centos701 ~]# rpm -ivh amazon-ssm-agent.rpm

3.アクティベーション


アクティベーションを作成します。
[root@centos701 ~]# aws ssm create-activation --default-instance-name vm701 --iam-role SSMServiceRole --registration-limit 1 --expiration-date 2018-08-31
{
    "ActivationCode": "nTlEimuyjNkjt8vw8axz",
    "ActivationId": "c9675763-7207-4a9a-811a-f507bb01b38f"
}

SSMエージェントを停止します。
[root@centos701 ~]# systemctl stop amazon-ssm-agent

ActivationCode, ActivationID を指定して、VMをマネージドインスタンスとして登録します。
下記例では、登録情報を上書きするか質問されていますが、初めて登録する場合は、質問されません。
今回は2回目の登録なので、上書きするか質問されています。
[root@centos701 ~]# amazon-ssm-agent -register -code "nTlEimuyjNkjt8vw8axz" -id "c9675763-7207-4a9a-811a-f507bb01b38f" -region "us-east-1"
Error occurred fetching the seelog config file path:  open /etc/amazon/ssm/seelog.xml: no such file or directory
Initializing new seelog logger
New Seelog Logger Creation Complete

Instance already registered. Would you like to override existing with new registration information? [Yes/No]: Yes
2018-08-22 21:12:26 INFO Successfully registered the instance with AWS SSM using Managed instance-id: mi-0e5589860c747f3ea

SSMエージェントを起動します。
[root@centos701 ~]# systemctl start amazon-ssm-agent

以下のように、VMがSSM管理のインスタンスとして登録されます。
[root@centos701 ~]# aws ssm describe-instance-information
{
    "InstanceInformationList": [
        {
            "IsLatestVersion": true,
            "IamRole": "SSMServiceRole",
            "ComputerName": "centos701",
            "PingStatus": "Online",
            "Name": "vm701",
            "InstanceId": "mi-0e5589860c747f3ea",
            "IPAddress": "10.0.2.15",
            "ResourceType": "ManagedInstance",
            "ActivationId": "c9675763-7207-4a9a-811a-f507bb01b38f",
            "AgentVersion": "2.3.13.0",
            "PlatformVersion": "7",
            "RegistrationDate": 1534939946.19,
            "PlatformName": "CentOS Linux",
            "PlatformType": "Linux",
            "LastPingDateTime": 1534940279.653
        }
    ]
}



2018年8月8日水曜日

任意の1文字を指定した文字数だけ繰り返して変数に格納する


値は適当でいいけど、文字数が100文字の値を作りたいとき

bashでは、以下のようにして, 'x' が100文字の値をつくって変数に格納する。

[root@centos701 ~]# value=`printf x"%.s" {1..100}|echo $(cat)`

$value を表示すると下記のとおり。

[root@centos701 ~]# echo $value
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

$value の文字数をカウントすると以下のとおり。
[root@centos701 ~]# echo -n $value | wc -c
100


2018年7月25日水曜日

AWS Data Pipeline をジョブスケジューラとして使える(S3のシェルを実行)


AWS Data Pipeline でS3に置いたシェルを実行できるらしい。

ジョブの依存関係も設定可能。

スケジュール起動も可能。

ジョブの異常は、SNSでメール通知。

ジョブのログはS3に格納できる。

[AWS Data Pipeline]S3上の任意のシェルを実行しジョブを連携させる

2018年7月18日水曜日

aws-cli でリトライさせる設定


~/.aws/models/_retry.json を用意すると aws-cli でエラーの再試行ができるらしい。

boto3でリトライの設定を変更する



2018年7月14日土曜日

シェルで urlencode したいとき


最近は、どのOSにも python が入っているので、python を使用します。

function urlencode
{
    echo "$1" \
        | python -c 'import sys,urllib; sys.stdout.write(urllib.quote_plus(raw_input()))'
}

urlencode "xxxxx"

AWSコンソールの貸し出しURL作成


フェデレーションユーザーに対して AWS マネジメントコンソール へのアクセスを許可する URL の作成(カスタムフェデレーションブローカー)」を参考にして、貸し出し用のAWSコンソールURLを作ってみます。

貸し出し用のURLでは、以下ができるようにします。
・認証不要。ただし、1時間(変更可能)しか使用できない。
・特定のロール(ReadOnlyなど)を割り当て、操作を制限する。

なお、URL作成時には、aws-cli を使用し、MFA必須とします。


1. URL作成用のIAMユーザを作成


「貸し出し用URL」を作成するIAMユーザを用意します。
今回作成するIAMユーザの名称は、"ops" とします。

[アクセス権限]タブで、[インラインポリシーの追加]をクリックし、インラインポリシーを作成します。
貸し出しURL作成に必要な権限だけ付与しています。


[認証情報]タブで、[MFAデバイスの割り当て]を実施します。
また、[アクセスキーの作成]ボタンでアクセスキーを作成します。


アクセスキーは、「貸し出しURL」を作成するマシンに設定します。
今回は、以下のようにしています。
[root@centos701 ~]# cat ~/.aws/credentials
[default]
aws_access_key_id = <アクセスキー>
aws_secret_access_key = <シークレットアクセスキー>

[ops]
aws_access_key_id = <上記で作成したアクセスキー>
aws_secret_access_key = <上記で作成したシークレットアクセスキー>

[root@centos701 ~]# cat ~/.aws/config
[default]
output = text
region = us-east-1

[profile ops]
output = text
region = us-east-1


2.AWSコンソールに割り当てるロールを作成


今回は、EC2の参照権限しかないロールを作成します。
今回作成するロールの名称は、"EC2ReadOnly" とします。
[アクセス権限]タブで AmazonEC2ReadOnlyAccess ポリシーを割り当てます。


[信頼関係]タブで、[信頼されたエンティティ]に上記1で作成した opsユーザを指定し、MFA必須にします。
[信頼関係の編集]ボタンをクリックして、以下のように設定します。
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::12345678:user/ops"
      },
      "Action": "sts:AssumeRole",
      "Condition": {
        "Null": {
          "aws:MultiFactorAuthAge": "false"
        }
      }
    }
  ]
}


ちなみに、[最大 CLI/API セッション期間]に表示されてる時間が、AWSコンソールを操作できる最大時間になります。この時間を過ぎると自動的にログアウトします。


3.URL作成用のスクリプトを作成


今回作成したスクリプトは以下のとおり。
ファイル名は awsurl.sh とします。

#!/bin/bash

PROF=ops
SERIAL_NUMBER=arn:aws:iam::12345678:mfa/${PROF}
AWS_FED_URL=https://signin.aws.amazon.com/federation
AWS_CONSOLE_URL=https://console.aws.amazon.com/
DURATION=3600 #sec

function urlencode
{
    echo "$1" \
        | python -c 'import sys,urllib; sys.stdout.write(urllib.quote_plus(raw_input()))'
}

if [ $# -ne 2 ]; then
    echo "usage: $(basename $0) <role name> <code>"
    exit 1
fi

role=$1
code=$2

arn=$(aws iam list-roles \
    --query "Roles[?RoleName == '${role}'].Arn" \
    --profile ${PROF} \
    --output text)

if [ "${arn}" == "" ]; then
    echo "${role} is not found."
    exit 1
fi

key=$(aws sts assume-role \
    --role-arn "${arn}" \
    --role-session-name OneTimeSession \
    --query "Credentials.[AccessKeyId,SecretAccessKey,SessionToken]" \
    --profile ${PROF} \
    --serial-number ${SERIAL_NUMBER} \
    --token-code ${code} \
    --output text)

access_key=$(echo "${key}" | awk -F"\t" '{printf("%s",$1)}')
secret_access_key=$(echo "${key}" | awk -F"\t" '{printf("%s",$2)}')
session_token=$(echo "${key}" | awk -F"\t" '{printf("%s",$3)}')

if [ "${access_key}" == "" ]; then
    echo "assume-role failed."
    exit 1
fi

json="{\"sessionId\":\"${access_key}\",\"sessionKey\":\"${secret_access_key}\",\"sessionToken\":\"${session_token}\"}"

token=$(curl -s "${AWS_FED_URL}?Action=getSigninToken&SessionDuration=${DURATION}&Session=$(urlencode ${json})" \
    | jq -r .SigninToken)

if [ "${token}" == "" ]; then
    echo "get signin token failed."
    exit 1
fi

url="${AWS_FED_URL}?Action=login&Issuer=&Destination=$(urlencode ${AWS_CONSOLE_URL})&SigninToken=$(urlencode ${token})"

echo ${url}

exit 0

4.動作確認


EC2の参照しかできないAWSコンソールのURLを作ってみます。
上記3で作成したスクリプトの引数に、「ロール名」、「opsユーザ用MFAのパスコード」を指定して実行すると、URLが表示されます。
[root@centos701 awscli]# ./awsurl.sh EC2ReadOnly 160335
https://signin.aws.amazon.com/federation?Action=login&Issuer=&Destination=https%3A%2F%2Fconsole.aws.amazon.com%2F&SigninToken=RHe2_m5aLBqK0Ci7_XXmp05OSMj0wGiFp1el48SI-qqR8WZV3qqTvYvBZQw7UrEHUUa5BOaH9IderXxzwtkicg9LGEJO0239ih8psYfidXoC_QHTeW_7DKBTIHGoU1NlU-xYXhcmDbidSE8LKZS4ZqjI0uxbzLuTnCU6iVHUdPAt4iqsLXpKa4oPTfUAexY52MnBZhZElNxXK4DVOyNEkCYWTUNisR9ufxAyf3GoC1f-7UbE4Dt_vdYkKOlED4k7FAaoUMo5OazE0mr-IJiYS7rnwYVUMcVnd7y-01CarUU4OdFt8rIiPfs6UprHBbpCOCqJdFf4jXFUy4olKdLtnorh6waDfO8wSmyQlPHu2P0QJDTzsvPekux06dDPzyRgEk3Uw9bHOxX6DpRO4Sqgev9t09t7VH5fkNshUZbF8SB2m4J7vNcWG7v0YDGGmdNd2QWKI47yZ1luN_C9MQS84IePpGfGicK9Uoda-mjXWvBAVBxA-4uA3qSzUsb0bLpXNAEx_lo14XY2p-I9RgLM_i3DDvx2WP6_kg9L0JZrTVU4zmTF19bORYPde6w854gTlpUXWKVWVMwqg7Tid-T2l7AYapkduA7KYLcBd2m0-wIqBVcc6liZYUEv7bs6gmobwH3vaLlCgTHF7x98JXlF5B0AT845_FP-Ng-BJwiKmpcyIg50_8f4W-V3vl7zRq0n9VKED53jJBYmABRuDc_QRoLUrW7Qa3qBQzMJ6Gq7-A0_CkhL3vBM8ax0I_WHcxkICCIUegh9hoIbsg41O9RJZkwsXCM3BsmTasKta_vosHdPYWzNw5_Dy2otHEUzM88s

このURLをブラウザにペーストして、AWSコンソールを開きます。
認証なしで下図にように画面が表示されます。
表示されるログイン名は、[EC2ReadOnly/OneTimeSession] です。
ロール名と、スクリプトの assume-role(awscli) で指定したセッション名が表示されています。


EC2は、下図のように参照できます。


S3を参照しようとすると、権限がないので、エラーになります。






2018年7月7日土曜日

sshd_config の AuthorizedKeysCommand を設定して IAMユーザのSSH公開キーでログインする


下記の記事を見て、ssh の AuthorizedKeysCommand を知りました。
AuthorizedKeysCommand にコマンドを指定すると、コマンドの実行結果として公開鍵を渡すことができるらしい。
OpenSSH 6.2を使って公開鍵認証もLDAPで行いたい。

そこで、AWSのIAMユーザにSSH公開鍵を登録して、その鍵で、SSHログインできるか試してみました。

1.IAMユーザにssh公開鍵を登録


まず、キーペアを作成します
[root@centos701 ~]# ssh-keygen
Generating public/private rsa key pair.
Enter file in which to save the key (/root/.ssh/id_rsa):
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /root/.ssh/id_rsa.
Your public key has been saved in /root/.ssh/id_rsa.pub.
The key fingerprint is:
SHA256:yU9NjtIMq8a9LJhNboxtZ2gxcEcLQTFNROj3ETvlMBU root@centos701
The key's randomart image is:
+---[RSA 2048]----+
|     .=O+  .E.   |
|      o.o + .    |
|     . o.. B.    |
|    . o.+*+=.    |
|     o oS.=oo    |
|     .+o +.      |
|     X++. .      |
|    +.@.o.       |
|     + +o        |
+----[SHA256]-----+

~/.ssh に公開鍵(id_rsa.pub)と秘密鍵(id_rsa)ができます。
[root@centos701 ~]# ls ~/.ssh/id*
/root/.ssh/id_rsa  /root/.ssh/id_rsa.pub

AWSコンソールでIAMユーザに上記で作成した公開鍵を登録します。
今回使用するIAMユーザは user01 です。
IAMユーザの[認証情報]タブで、[SSH公開キーのアップロード]ボタンをクリックします。
下図のように、作成した公開鍵をコピー&ペーストして、[SSH公開キーのアップロード]ボタンをクリックします。


下図のようにSSH公開鍵が登録されます。


2.SSH公開鍵取得スクリプトの用意


IAMユーザのSSH公開鍵を取得するスクリプトを用意します。
AuthorizedKeysCommand に設定して、sshd から実行されると、引数にユーザが渡されます。
スクリプト名は、/usr/local/sbin/aws_ssh_key.sh とし、内容は以下のようにしました。
テスト環境が、VirtualBoxなのでアクセスキーを設定していますが、
EC2インスタンスにロールを設定すれば、アクセスキーの設定は不要です。

[root@centos701 ~]# cat /usr/local/sbin/aws_ssh_key.sh
#!/bin/bash

export AWS_ACCESS_KEY_ID=<アクセスキー>
export AWS_SECRET_ACCESS_KEY=<シークレットアクセスキー>
export AWS_DEFAULT_REGION=ap-northeast-1

LOG=/tmp/debug.log
exec > >(tee ${LOG}) 2>&1

user=$1

id=`aws iam list-ssh-public-keys \
    --user-name "${user}" \
    --query "SSHPublicKeys[?Status=='Active'].[SSHPublicKeyId]" \
    --output text`

aws iam get-ssh-public-key \
    --user-name ${user} \
    --ssh-public-key-id "${id}" \
    --encoding SSH \
    --query "SSHPublicKey.SSHPublicKeyBody" \
    --output text


実行権限をつけます。
[root@centos701 ~]# chmod +x /usr/local/sbin/aws_ssh_key.sh

試しに動かしてみます。
以下のように、引数に user01 を指定して、上記1で登録した公開鍵が表示されたらOKです。
[root@centos701 ~]# /usr/local/sbin/aws_ssh_key.sh user01
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDFcuCzHvzR3epwYjydZ+ge0mpXLfjV69fG9JbS2xAdfh5LGKOXnUKyFPFzZHIS31yg0wQBgzISaR4r3uPJ6WePh2Kx3LgX/cJoUCeKfVWPngoxyvu7f4wOlgehP8RCQ4Fs3OoCIlaT56zJYLR+r6hirdGoAdi3gq5Tp42628V5aMSyWCFn2k3LGZJOsUfEfjHWWeOQsujKjv/XlXoBFIf5p4kwClzV31KOtMex5CeuM0QPmJM2syjONmJ1WqARVRZgLuuXMkdD0cYlBSQd2gMf4ujf/CIuXirYNuyG3BY4tJFbFRHCKsXqzc1FvvVaU2+fJBwxsq/jtBGEXdFeCcp9

3. sshd_config の設定


/etc/sshd/sshd_config を下記のように修正します。
CentOS7の場合は、コメントアウトされていたので、# を削除して設定します。
AuthorizedKeysCommand /usr/local/sbin/aws_ssh_key.sh
AuthorizedKeysCommandUser nobody

sshd を reload します。
[root@centos701 ~]# systemctl reload sshd


4. ssgログインの動作確認 


サーバには、IAMユーザと同じ名称でユーザを用意します。
user01の公開鍵は、サーバには設定していません。
[root@centos701 home]# id user01
uid=1000(user01) gid=1000(user01) groups=1000(user01)
[root@centos701 home]# ls -al /home/user01
合計 20
drwx------  2 user01 user01  92  2月 25 00:18 .
drwxr-xr-x. 5 root   root    47  2月 25 00:20 ..
-rw-------  1 user01 user01  15  2月 25 00:18 .bash_history
-rw-r--r--  1 user01 user01  18  9月  7  2017 .bash_logout
-rw-r--r--  1 user01 user01 193  9月  7  2017 .bash_profile
-rw-r--r--  1 user01 user01 231  9月  7  2017 .bashrc
-rw-r--r--  1 user01 user01 334  9月 20  2017 .emacs

上記1で作成した、秘密鍵でログインします。
[root@centos701 ~]# ssh -i .ssh/id_rsa -l user01 localhost
Last login: Sat Jul  7 20:27:09 2018 from localhost

AWSに公開鍵を取りに行くので、ログインに、少し、時間がかかります。

下記の記事と、組み合わせると、いいかもしれない。
AuthorizedKeysCommandを使うと、記事の authorized_keysの作成は不要になります。
IAMで踏み台ホストのユーザーとSSH公開鍵を一元管理する





2018年4月30日月曜日

terraform + ECSを試す


terraform と ECS の学習のため、
下図のAWS環境を terraform で構築してみました。



ECSで試したかったことは以下のとおり。
  • EC2インスタンス1台でマイクロサービスのコンテナを4つ(backend,user,auth,worker)動かす。
  • スケールアウトできるように1サービス:1コンテナ(1タスク)にし、コンテナには、ALB経由でアクセスする。
  • workerコンテナは、awsvpc にして、プライベートサブネットに入れる。
  • SSMでEC2インスタンスの docker コマンドを実行する。
  • コンテナのログをCloudWatchLogsで収集する。
  • Route53にALBをDNS(インターナル)登録する。

実施した構築作業と動作確認の流れを、備忘録として、以下に記述します。

Dockerイメージの準備


まず、テスト用のマイクロサービスとして、下記のDockerイメージを2つ用意しました。
  • blue21/micro.backend
    backendコンテナで使用し、user,auth,workerにアクセスしてレスポンスを表示します。
  • blue21/micro.workers
    user, auth, worker コンテナで使用し、コンテナのIPアドレスを返します。
Dockerイメージは、ローカル環境(VirtualBoxのCentOS7)の docker-compose でビルドと動作確認を行いました。
今回作成した docker-compose のソースは、以下の Bitbucketからダウンロードできます。

上記ソースを使用したDockerイメージ準備作業の流れは、以下のとおり。
最終的に、DockerHUBにイメージを登録します。
イメージのサイズがECRの無料使用枠に収まらないと思ったので、DockerHUBに登録しました。

1. マイクロサービスの Docker イメージをビルドする。


docker-compose でイメージを2つ作成します。
# docker-compose build
# docker images
REPOSITORY               TAG                 IMAGE ID            CREATED             SIZE
blue21/micro.workers     latest              88fa4a7edec0        2 days ago          261MB
blue21/micro.backend     latest              cc75da278726        2 days ago          297MB

2. ローカル環境でDockerイメージの動作確認


docker-composeで コンテナを4つ起動して、動作確認します。
# docker-compose up -d
# docker-compose ps
 Name        Command       State           Ports
---------------------------------------------------------
auth      python3 app.py   Up      80/tcp
backend   python3 app.py   Up      0.0.0.0:5000->5000/tcp
user      python3 app.py   Up      80/tcp
worker    python3 app.py   Up      80/tcp
# curl http://localhost:5000
<!DOCTYPE html>
<html>
<head>
  <title>[demo] マイクロサービス</title>
</head>
<body>
  <h1>[demo] マイクロサービス</h1>

  <ul>

    <li><h2>worker</h2><strong>Service Response:</strong> こんにちは、worker です. Host は、worker.dev.blue21.local(172.18.0.4) です.
    </li>

    <li><h2>user</h2><strong>Service Response:</strong> こんにちは、user です. Host は、user.dev.blue21.local(172.18.0.2) です.
    </li>

    <li><h2>auth</h2><strong>Service Response:</strong> こんにちは、auth です. Host は、auth.dev.blue21.local(172.18.0.3) です.
    </li>

  </ul>

</body>

3. DockerイメージをDockerHUB に登録


Dockerイメージを DockerHUB の自分のアカウントに登録します。
# docker login
# docker push blue21/micro.backend:latest
# docker push blue21/micro.workers:latest

今回は、無償のパブリックなレポジトリとして登録したので、下記で参照できます。
https://hub.docker.com/u/blue21/

AWS環境構築


terraform でAWS環境を構築します。
terraform コマンドは、dockerコンテナを使用しました。(前回の記事を参照)

今回作成したソースは、以下の Bitbucket で参照できます。
https://bitbucket.org/blue21/aws-sample-ecs/src/master/

上記ソースでは、terraform の workspace を利用して 開発環境と本番環境を構築できるように考慮していますが、本番環境構築の動作確認はしていません。
また、terra.sh というシェルを用意して、dockerコンテナの terraform コマンドを実行しています。

上記ソースを使用した構築の流れは以下のとおり。
今回は、開発環境(workspace=dev)を構築します。ちなみに。本番環境の場合は workspace = prod になります。

1. envfile の準備


envfile にアクセスキー、シークレットアクセスキーを定義します。
今回は、Adminstrator 権限を持ったキーを使用しました。
AWS_ACCESS_KEY_ID=<アクセスキー>
AWS_SECRET_ACCESS_KEY=<シークレットアクセスキー>
envfile は terra.sh で使用し、/root/conf/envfile に配置します。

2. common.tfvars の準備


使用するリージョンを定義します。
今回は us-east-1 を使用するので、ECSで使用する EC2インスタンス用のAMIは、us-east-1 用です。
myip は、セキュリティグループの定義で使用します。myip に定義したIPアドレスのみEC2インスタンスへのSSH接続を許可します。
/*
 * COMMON VARIABLES
 *
 */

common = {
    # default
    default.region     = "us-east-1"         # リージョン
    default.project    = "demo"              # プロジェクト名
    default.myip       = "110.165.221.254"   # 管理者IP
    default.zone_name  = "blue21.local"      # DNS
}

3. terraform で AWSに network環境を作成


下記のコマンドでネットワーク環境を構築します。
VPC、サブネット、IGW、ルートテーブル、セキュリティグループを作成します。
# ./terra.sh 10.network init
# ./terra.sh 10.network workspace new dev
# ./terra.sh 10.network plan
# ./terra.sh 10.network apply

terraformで作成したリソースを、AWSコンソールで確認すると下図のようになります。

[VPC]

[サブネット]

[ルートテーブル]

[IGW]

[セキュリティグループ]

4. terraform で AWSに IAMロールを作成


下記のコマンドでIAMロールを作成します。
# ./terra.sh 20.iam init
# ./terra.sh 20.iam workspace new dev
# ./terra.sh 20.iam plan
# ./terra.sh 20.iam apply

terraformで作成したリソースを、AWSコンソールで確認すると下図のようになります。

[ロール]

4. terraform で AWSに ALBを作成


下記のコマンドでALBを作成します。
# ./terra.sh 30.ec2 init
# ./terra.sh 30.ec2 workspace new dev
# ./terra.sh 30.ec2 plan
# ./terra.sh 30.ec2 apply

terraformで作成したリソースを、AWSコンソールで確認すると下図のようになります。

[ターゲット]

[ロードバランサ]

7. terraform で AWSに ECSを作成


下記のコマンドでECSを作成します。
ここで作成するEC2インスタンスのキーペアは、"virginia_key" という名前にしています。
また、EC2インスタンスには、userdata を使用して、SSMエージェントをインストールしています。
# ./terra.sh 40.ecs init
# ./terra.sh 40.ecs workspace new dev
# ./terra.sh 40.ecs plan
# ./terra.sh 40.ecs apply

terraformで作成したリソースを、AWSコンソールで確認すると下図のようになります。

[EC2インスタンス]
ENIが2つ作成され、プライベートIPが2つ割当てられます。1つは、ネットワークタイプを "awsvpc" にした worker コンテナ用です。

[ECS: タスク定義]

[ECS: クラスタ]

[ECS: サービス]

[ECS: タスク]

[ECS: ECSインスタンス]

8. terraform で AWSに Route53 を作成


下記のコマンドでRoute53を作成します。
VPC内部で使用可能なインターナルなゾーンを作成します。
# ./terra.sh 50.r53 init
# ./terra.sh 50.r53 workspace new dev
# ./terra.sh 50.r53 plan
# ./terra.sh 50.r53 apply

terraformで作成したリソースを、AWSコンソールで確認すると下図のようになります。

[ゾーン]

[レコードセット]

動作確認


上記でAWS環境ができたので、いろいろ試します。

マイクロサービス


AWSの外側からALBにアクセスしてみます。
成功すると、以下のように各コンテナのIPアドレスが表示されます。
[root@centos701 ~]# curl http://demo-dev-alb-1527439969.us-east-1.elb.amazonaws.com
<!DOCTYPE html>
<html>
<head>
  <title>[demo] マイクロサービス</title>
</head>
<body>
  <h1>[demo] マイクロサービス</h1>

  <ul>

    <li><h2>worker</h2><strong>Service Response:</strong> こんにちは、worker です. Host は、worker.dev.blue21.local(10.0.10.104) です.
    </li>

    <li><h2>user</h2><strong>Service Response:</strong> こんにちは、user です. Host は、user.dev.blue21.local(172.17.0.3) です.
    </li>

    <li><h2>auth</h2><strong>Service Response:</strong> こんにちは、auth です. Host は、auth.dev.blue21.local(172.17.0.2) です.
    </li>

  </ul>

</body>
</html>[root@centos701 ~]#

こんどは、HTTPヘッダでホスト名を worker に変更して、 ALBにアクセスしてみます。
成功すると以下のように workerコンテナのIPアドレスが表示されます。
[root@centos701 ~]# curl -H "Host: worker.dev.blue21.local" http://demo-dev-alb-1527439969.us-east-1.elb.amazonaws.com
こんにちは、worker です. Host は、worker.dev.blue21.local(10.0.10.104) です.[root@centos701 ~]#

CloudWatchLogs


AWSコンソールで CLoudWatchLogs を参照すると、下図のとおり。
コンテナのログを参照できます。

[コンテナのログ一覧]

[backend のログ(アクセスログ)]

SSMでのコマンド実行


AWSコンソールの[EC2]>[SYSTEM MANAGER SERVICES]でコマンドを実行してみます。
ECS用のEC2インスタンス上で"docker ps"コマンドを実行すると下図のように表示されました。


Route53


VPC内部で、blue21.local のDNS名でマイクロサービスにアクセスしてみます。
ECS用のEC2インスタンスにSSHログインして、以下のように curl コマンドで backend に アクセスしてみました。
成功すると以下のように表示されます。
[ec2-user@ip-10-0-0-4 ~]$ curl http://backend.dev.blue21.local
<!DOCTYPE html>
<html>
<head>
  <title>[demo] マイクロサービス</title>
</head>
<body>
  <h1>[demo] マイクロサービス</h1>

  <ul>

    <li><h2>worker</h2><strong>Service Response:</strong> こんにちは、worker です. Host は、worker.dev.blue21.local(10.0.10.104) です.
    </li>

    <li><h2>user</h2><strong>Service Response:</strong> こんにちは、user です. Host は、user.dev.blue21.local(172.17.0.3) です.
    </li>

    <li><h2>auth</h2><strong>Service Response:</strong> こんにちは、auth です. Host は、auth.dev.blue21.local(172.17.0.2) です.
    </li>

  </ul>

</body>
</html>[ec2-user@ip-10-0-0-4 ~]$

user,auth,workerコンテナにアクセスすると、成功すれば、以下のよう表示されます。
[ec2-user@ip-10-0-0-4 ~]$ curl http://user.dev.blue21.local
こんにちは、user です. Host は、user.dev.blue21.local(172.17.0.3) です.[ec2-user@ip-10-0-0-4 ~]$
[ec2-user@ip-10-0-0-4 ~]$ curl http://auth.dev.blue21.local
こんにちは、auth です. Host は、auth.dev.blue21.local(172.17.0.2) です.[ec2-user@ip-10-0-0-4 ~]$
[ec2-user@ip-10-0-0-4 ~]$ curl http://worker.dev.blue21.local
こんにちは、worker です. Host は、worker.dev.blue21.local(10.0.10.104) です.[ec2-user@ip-10-0-0-4 ~]$
[ec2-user@ip-10-0-0-4 ~]$

コンテナのスケールアウト


user コンテナを手動でスケールアウトしてみます。
modules/ecs/main.tf の 下記 "desired_count" を 2 に修正して、user コンテナを2つ起動するようにソースを変更します。
resource "aws_ecs_service" "user" {
  name                  = "${local.name_prefix}-user"
  cluster               = "${aws_ecs_cluster.default.id}"
  task_definition       = "${aws_ecs_task_definition.user.arn}"
  desired_count         = 2
  health_check_grace_period_seconds = 30
  iam_role              = "${var.m-role-ecs.["ecs-service-role-arn"]}"

  load_balancer {
    target_group_arn    = "${var.m-alb.["target-user-id"]}"
    container_name      = "user"
    container_port      = 80
  }
}

terraform で上記の変更を反映します。
# ./terra.sh 40.ecs apply

AWSコンソールで変更結果を確認すると下図のとおり。

[userサービスのコンテナが2つある]

[ALBの user用ターゲットに、コンテナが追加されている]

[CloudwatchLogs が追加されている]

マイクロサービスにアクセスすると、以下のように user のIPアドレスが変わります。
# curl http://demo-dev-alb-1527439969.us-east-1.elb.amazonaws.com
<!DOCTYPE html>
<html>
<head>
  <title>[demo] マイクロサービス</title>
</head>
<body>
  <h1>[demo] マイクロサービス</h1>

  <ul>

    <li><h2>worker</h2><strong>Service Response:</strong> こんにちは、worker です. Host は、worker.dev.blue21.local(10.0.10.104) です.
    </li>

    <li><h2>user</h2><strong>Service Response:</strong> こんにちは、user です. Host は、user.dev.blue21.local(172.17.0.3) です.
    </li>

    <li><h2>auth</h2><strong>Service Response:</strong> こんにちは、auth です. Host は、auth.dev.blue21.local(172.17.0.2) です.
    </li>

  </ul>

</body>
</html>
下記は、user コンテナのIPアドレスが上記と異なっているので、ALBで振り分けできてることがわかります。
# curl http://demo-dev-alb-1527439969.us-east-1.elb.amazonaws.com
<!DOCTYPE html>
<html>
<head>
  <title>[demo] マイクロサービス</title>
</head>
<body>
  <h1>[demo] マイクロサービス</h1>

  <ul>

    <li><h2>worker</h2><strong>Service Response:</strong> こんにちは、worker です. Host は、worker.dev.blue21.local(10.0.10.104) です.
    </li>

    <li><h2>user</h2><strong>Service Response:</strong> こんにちは、user です. Host は、user.dev.blue21.local(172.17.0.5) です.
    </li>

    <li><h2>auth</h2><strong>Service Response:</strong> こんにちは、auth です. Host は、auth.dev.blue21.local(172.17.0.2) です.
    </li>

  </ul>

</body>
</html>

あとかたずけ


遊び終わったら、上記で作成したAWS環境を、以下の順番で削除します。お金がもったいないので。
# ./terra.sh 50.r53 destroy
# ./terra.sh 40.ecs destroy
# ./terra.sh 30.ec2 destroy
# ./terra.sh 20.iam destroy
# ./terra.sh 10.network destroy

ちなみに、夜などAWSをさわらないときは、
お金のかからない network, iam だけ残して、ec2, ecs, r53 は削除し、検証時に毎回、ec2, ecs, r53 を作成してました。