CloudWatchで定期的にLambdaを実行して、Slackにメッセージを送信する

今回のお題

Lambdaのトリガーはいくつか設定できますが、今回は毎週月曜日のAM9時にSLackに通知するのが目的なんで、CloudWatchでLambdaに設定した関数を実行する方法を試して見ます。

LambdaにSlack送信するプログラムを作成する

LambdaからWebHookを使用してSlackにメッセージを送信してみる

別記事で書いたこちらを元に作成。
ちょっとだけ手を加えてあります。

slack.py
# coding: UTF-8
import requests
import json
import os
from datetime import datetime

def lambda_handler(event, context):
    now = datetime.now()
    msg = now.strftime("%Y/%m/%d %H:%M:%S")
    msg += u'\r\nCloudWatch実行\r\nlambdaからのPython使ってのSlack送信・・・何たる僥倖・・・!悪魔的発想・・・!'
    # 実行
    send_slack(u'カイジ', u':kaiji:', 'チャンネル名', msg)

# slack送信、仮メソッド
def send_slack(user_name, icon, channel, msg):
    requests.post('WebHookのURL', data = json.dumps({
        'text': msg, # 投稿するテキスト
        'username': user_name, # 投稿のユーザー名
        'link_names': 1, # メンションを有効にする
        'channel': channel, # チャンネル
        'icon_emoji': icon, # アイコン
    }))

分かりやすくするために、Postするメッセージに日付を入れて見ました。
あとはまぁ、よくある悪ふざけですw
テスト実行で、Slackにメッセージが送信されるのは確認済みです。

Lambdaにトリガーを設定する

トリガーを選択します、+ トリガーを追加を押下します。
スクリーンショット 2017-11-16 23.00.07.png

図の空白になっている、左側をクリックします。
スクリーンショット 2017-11-16 23.02.23.png

すると設定できるリストが表示されるので、今回使用する「CloudWatch Events」を選択します。
スクリーンショット 2017-11-16 23.03.07.png

ルールで「新規ルールの作成」を選択し、必要な項目を埋めていきます。
スケジュール式は、今回はテスト的な内容なんで5分ごとに実行する式を記載しました。
スクリーンショット 2017-11-16 23.05.37.png

トリガーの有効化のチェックがON担っているのを確認し、送信を押下する。
スクリーンショット 2017-11-16 23.07.07.png

トリガーの作成完了

スクリーンショット 2017-11-16 23.07.46.png

Slackを確認する

とりあえず問題なく定期的にSlackの送信ができました!!
スクリーンショット 2017-11-16 23.19.25.png

別枠で検証する事柄

時間がおかしいですね・・・?どこの時間ですかね?
とりあえず、日本時間での実行ができるように調べて見ます。

AWSのLambdaのタイムゾーンをUTCから東京に変更
こちらで、Lambdaでの時間についてはできました!

CloudWatchについては別途調査中です。

続きを読む

Amazon Linux + Apache でLet’s encrypt

Let’s encryptの設定

参考サイト

http://webfood.info/letsencrypt-renewal-failure/

Let’s encrypt とは?

「安全な接続を世界中に広めよう」という素晴らしい考えを持ったプロジェクト。
非営利団体の ISRG (Internet Security Research Group) によって運営されており、いろいろな大手企業がこの活動をサポートしている。利用料はもちろん無料。

なにがすごいんじゃ

Let’s encrypt では、「certbot」というクライアントソフトを使うことで、
自動的にSSL証明書の更新を行うことが出来るようになっている。
独自ドメインさえあればコマンド操作のみでSSL証明書がゲット出来るのである。

Amazon Linux に入れてみよう

Amazon Linuxはcertbotにまだ対応できていないため、単純にyumインストールができない(2017/11/16現在)
その為wgetでソースを落として直接インストールする必要がある。

$ wget https://dl.eff.org/certbot-auto
--2017-11-16 12:49:31--  https://dl.eff.org/certbot-auto
dl.eff.org (dl.eff.org) をDNSに問いあわせています... 151.101.32.201, 2a04:4e42:8::201
dl.eff.org (dl.eff.org)|151.101.32.201|:443 に接続しています... 接続しました。
HTTP による接続要求を送信しました、応答を待っています... 200 OK
長さ: 57312 (56K) [application/octet-stream]
`certbot-auto' に保存中

certbot-auto            100%[==============================>]  55.97K  --.-KB/s    in 0.02s   

2017-11-16 12:49:31 (2.39 MB/s) - `certbot-auto' へ保存完了 [57312/57312]

$ chmod a+x certbot-auto

ここまでは公式サイトに乗っている手順通り。
後1コマンド!・・・というところでこんな表示が出てしまう。

$ ./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.

要約すると、
「Amazon Linuxでのcertbotはまだ実験段階だよ。もし君がその実験のお手伝いをしたいならバックアップを必ず取ってさっきのコマンドに–debugオプションを付けて実行してね!」
と書いてある。優しい。

というわけでバックアップをとって自己責任で実行してみる。

$ ./certbot-auto --debug
Requesting to rerun ./certbot-auto with root privileges...
Bootstrapping dependencies for Amazon... (you can skip this with --no-bootstrap)
yum は /usr/bin/yum です
読み込んだプラグイン:priorities, update-motd, upgrade-helper
パッケージ 1:openssl-1.0.2k-8.105.amzn1.x86_64 はインストール済みか最新バージョンです
パッケージ ca-certificates-2015.2.6-65.0.1.16.amzn1.noarch はインストール済みか最新バージョンです
パッケージ python27-2.7.12-2.121.amzn1.x86_64 はインストール済みか最新バージョンです
パッケージ python27-devel-2.7.12-2.121.amzn1.x86_64 はインストール済みか最新バージョンです
パッケージ python27-virtualenv-15.1.0-1.14.amzn1.noarch はインストール済みか最新バージョンです
パッケージ python27-pip-9.0.1-1.24.amzn1.noarch はインストール済みか最新バージョンです
依存性の解決をしています
--> トランザクションの確認を実行しています。
---> パッケージ augeas-libs.x86_64 0:1.0.0-5.7.amzn1 を インストール

~省略~

依存性を解決しました

===============================================================================================
 Package                   アーキテクチャー
                                        バージョン                    リポジトリー        容量
===============================================================================================
インストール中:
 augeas-libs               x86_64       1.0.0-5.7.amzn1               amzn-main          345 k
 gcc                       noarch       4.8.5-1.22.amzn1              amzn-main          4.1 k

~省略~

トランザクションの要約
===============================================================================================
インストール  6 パッケージ (+17 個の依存関係のパッケージ)

総ダウンロード容量: 32 M
インストール容量: 61 M
Is this ok [y/d/N]: 

お、なんとかなりそう。
というわけで実行しましょう。ちゃんと完了しました!と表示されるはずです。

これでインストールが完了です。ここからが本番です。

証明書を取得する

以下のコマンドを入力し、証明書を入手します。

./certbot-auto certonly --webroot -w [ドキュメントルート] -d [ドメイン]

–webrootオプションをつけることで、Webサーバを停止することなく実行できます。

以下のメッセージが表示されていれば成功です。

IMPORTANT NOTES:
 - Congratulations! Your certificate and chain have been saved at:
   /etc/letsencrypt/live/[ドメイン名]/fullchain.pem
   Your key file has been saved at:
   /etc/letsencrypt/live/[ドメイン名]/privkey.pem
   Your cert will expire on 2018-02-14. To obtain a new or tweaked
   version of this certificate in the future, simply run certbot-auto
   again. To non-interactively renew *all* of your certificates, run
   "certbot-auto renew"
 - If you like Certbot, please consider supporting our work by:

   Donating to ISRG / Let's Encrypt:   https://letsencrypt.org/donate
   Donating to EFF:                    https://eff.org/donate-le

皆さん寄付をご検討ください。

このメッセージが表示されていれば、以下のパスに証明書ファイルが生成されています。
見に行きましょう。

$ cd /etc/letsencrypt/live/[ドメイン名]/
$ ls
cert.pem  chain.pem  fullchain.pem  privkey.pem  README

こいつらが生成されていればOK
Apacheにmod_SSLをインストールするのをお忘れなく

$ yum install -y mod24_ssl

ssl.confを修正

$ vi /etc/httpd/conf.d/ssl.conf 
以下を記述
SSLCertificateFile /etc/letsencrypt/live/[ドメイン名]/cert.pem
SSLCertificateKeyFile /etc/letsencrypt/live/[ドメイン名]/privkey.pem
SSLCertificateChainFile /etc/letsencrypt/live/[ドメイン名]/chain.pem

んでApaheを再起動すれば完了!

service httpd restart

問題なければここでおわり!
本当はhttpのアクセスをhttpsに流したりとかあるんだろうけど、それはまた別のお話。
お疲れ様でした。

…Apacheが起動しない人へ

最後に何故かApacheが起動しなくなりました・・エラーメッセージは以下

Starting httpd: (98)Address already in use: AH00072: make_sock: could not bind to address [::]:443

443ポートがすでに使われているとのこと。しかしポートが使われている形跡はない・・・
悩みに調べて30分後

「もしやhttpd自身が443ポートを2回バインドしようとしているのでは・・・?」
とおもいhttpd.confを見てみると、ありました

Listen 443

こいつ。ssl.confの中にも書いてあるんですね。
httpd.confの方をコメントアウトしてhttpd再起動!

上手く行った!!!
よかったよかった。

誰かの助けになればいいなと思います。

続きを読む

Lambdaの環境変数をKMSで暗号化して、Pythonで複合化する

今回のお題

IAMの暗号化キーを生成し、その暗号キーを用いてLambdaの環境変数を暗号化する。
暗号化したものをPythonで複合化して、表示してみる。

暗号化キーを作成する

IAM > 暗号化キーを選択する。
スクリーンショット 2017-11-15 23.46.16.png

リージョンを東京に変更する

スクリーンショット 2017-11-15 23.47.48.png

画面上部のキーの作成を押下する

スクリーンショット 2017-11-15 23.48.24.png

エイリアスを入力し、KMSを選択する。

今回はテストなので「test/key」としました。
入力・選択を終えたら、画面下部の「次のステップ」押下
スクリーンショット 2017-11-15 23.49.14.png

タグキーを入力

入力したら画面下部の「次のステップ」押下
スクリーンショット 2017-11-15 23.50.58.png

キー管理者を設定

本来は、ちゃんと設定するのでしょうが、今回はlambdaのデフォルトで用意されている「lambda_basic_execution」を設定しました。
あと、自分のAWSのログインIDも設定します(変更したりできるようにするため)
スクリーンショット 2017-11-15 23.51.55.png

キーの使用者の設定

こちらも同じく「lambda_basic_execution」とAWSの自分のIDを設定しておきます。
スクリーンショット 2017-11-15 23.53.13.png

完了

作成が終えると、キーの一覧に表示されます。
スクリーンショット 2017-11-15 23.55.03.png

Lambdaの環境変数を設定し、暗号化する

サービス > lambdaを選択し、ソースインラインの下にある環境変数に値を入れ、暗号化を設定していきます。

環境変数に値を入れる

スクリーンショット 2017-11-15 23.57.05.png

暗号化の設定を開く

「伝送中の暗号化のためのヘルパーの有効化」のチェックをONにすると、伝送中に暗号化するKMSキーが表示されます。
スクリーンショット 2017-11-15 23.59.28.png

前手順で作成したKMSキーを選ぶ

リスト式ですので、クリックすると設定されている一覧が表示されます。
先ほど作成したKMSキーを選択しましょう。
スクリーンショット 2017-11-16 0.00.37.png

環境変数の暗号化を押下する

KMSキーを設定すると、環境変数に暗号化ボタンが表示されますので、押下します。
スクリーンショット 2017-11-16 0.01.24.png

スクリーンショット 2017-11-16 0.04.45.png

Pythonで環境変数を読み込んでみる。

Lambdaで、下記のようなソースを記載します。

# coding: UTF-8

import os

def lambda_handler(event, context):
    print('~~~~~環境変数表示~~~~~')
    print(os.environ['test'])

保存して、実行します。
ログには、下記のように表示されました。
無事に暗号化できているようです。
スクリーンショット 2017-11-16 0.06.59.png

複合化してみる

複合化は、簡単でした。
下記のようなソースを記載し、実行して見ます。

# coding: UTF-8
from base64 import b64decode
import boto3
import os

def lambda_handler(event, context):
    kms = boto3.client('kms')
    decrypt_text = kms.decrypt(CiphertextBlob=b64decode(os.environ['test']))['Plaintext']

    print("~~~~~~~~~~~~~~複合化確認~~~~~~~~~~~~~~~~")
    print(os.environ['test'])
    print(decrypt_text)

実行結果

スクリーンショット 2017-11-16 0.09.48.png

まとめ。

環境変数に対する暗号化・複合化が非常に簡単にできました。
すごい便利ですねこれ。ロールをきちんと考えれば、セキュリティ的にも大丈夫な気がします。

続きを読む

AWS CloudFormation で RDS (SQLServer) インスタンスを作成してみる

0.はじめに

ずっと AWS CloudFormation 使いたいなと思っていたので、
使ってみました。

1.事前準備

  1. RDS のサブネットグループを作成しておく。

  2. セキュリティグループを作成しておく。

2.AWS CloudFormation で RDS(MSSQL) を作成

  1. AWS CloudFormation のマネジメントコンソールを開く。

  2. 「スタックの作成」ボタンを押下する。
    • 0001.jpg

  3. 「スタックの作成 – テンプレートの選択」画面が表示されるので、「テンプレートの選択」→「テンプレートを Amazon S3 にアップロードする」をチェック、以下の json ファイルをアップロードし、「次へ」ボタンを押下する。

    • 0002.jpg
    GS-RDS-MSSQL-from-bak.template
    {
    "AWSTemplateFormatVersion": "2010-09-09",
    "Parameters": {
        "ProjectName": {
            "Type": "String",
            "Default": "[プロジェクト名]"
        },
        "DbSubnetGroupName": {
            "Type": "String",
            "Default": "[作成しておいたサブネットグループ名]"
        },
        "VpcSecurityGroup": {
            "Type": "AWS::EC2::SecurityGroup::Id",
            "Default": "[作成しておいたセキュリティグループのID]"
        }
    },
    "Resources": {
        "DbInstance": {
            "Type": "AWS::RDS::DBInstance",
            "Properties": {
                "Engine": "sqlserver-ex",
                "DBInstanceClass": "db.t2.micro",
                "AllocatedStorage": "20",
                "StorageType": "gp2",
                "DBInstanceIdentifier": "[DBインスタンス名]",
                "MasterUsername": "[ユーザーID]",
                "MasterUserPassword": "[パスワード]",
                "DBSubnetGroupName": {
                    "Ref": "DbSubnetGroupName"
                },
                "PubliclyAccessible": true,
                "AvailabilityZone": "ap-northeast-1a",
                "VPCSecurityGroups": [
                    {
                        "Ref": "VpcSecurityGroup"
                    }
                ],
                "CopyTagsToSnapshot": true,
                "BackupRetentionPeriod": 7,
                "Tags": [
                    {
                        "Key": "[タグの名前]",
                        "Value": "[タグの値]"
                    }
                ]
            },
            "DeletionPolicy": "Snapshot"
        }
    }
    }
    
  4. 「スタックの作成 – 詳細の指定」画面が表示されるので、以下の項目を入力し、「次へ」ボタンを押下する。

    • スタック名称 : ※任意

    • 0003.jpg

  5. 「スタックの作成 – オプション」画面が表示されるので、「次へ」ボタンを押下する。

    • 0004.jpg

  6. 「スタックの作成 – 確認」画面が表示されるので、「作成」ボタンを押下する。

    • 0005.jpg

  7. スタックの一覧が表示されるので、作成したスタックの状況を確認します。また RDS のマネジメントコンソールも開き、作成する RDS インスタンスの状況を確認します。

    • 0006-1.jpg

    • 0006-2.jpg

  8. しばらくすると、作成が完了します。

    • 0007-1.jpg

    • 0007-2.jpg

99.ハマりポイント

XX.まとめ

とりあえず使ってみたかったので、
ちゃんと作成されてよかったです。

AWS のリソースのみだけではなく、
それ以外のリソースや OS 内部の設定など、
そういった設定も必要な場合での CloudFormation の使い方ってどうなるんでしょうかね?

その辺も今後試せればと思います。

続きを読む

Fitbit Logger with AWS Lambda/CloudWatch

I bought a fitbit device more than 2 years ago. Since then, using the wearable device and its app, almost everything in my ordinary life have been being logged such as workouts, steps, heart rate, sleeps, weights and calories. One of my habit is measur… 続きを読む

Ubuntu✕Terraform✕ItamaeでKinesis-firehoseを使う

What the Kinesis-firehose?

  • Streams,Analyticsなど、KinesisStreamingDataPlatformの一部
    スクリーンショット 2017-11-08 15.26.52.png
  • kinesis-agentをサーバで起動させ、configに処理を定義します
    • Javaで動き、任意のログをS3などのデータレイクへ任意のタイミングでPushします

Kinesis-agent

Prerequisites

  • UbuntuというかDebianは入ってないです…
  • Writing to Amazon Kinesis Streams Using Kinesis Agent

    • Prerequisites

      Your operating system must be either Amazon Linux AMI with version 2015.09 or later, or Red Hat
      Enterprise Linux version 7 or later.
      

Method

  • 公式ドキュメントには書いてないけど、ReadMeにBuildすれば使えるって書いてありました

    Building from Source
    The installation done by the setup script is only tested on the following OS Disributions:
    Red Hat Enterprise Linux version 7 or later
    Amazon Linux AMI version 2015.09 or later
    Ubuntu Linux version 12.04 or later
    Debian Linux version 8.6 or later
    

Enviroment

  • ubuntu15.04(サポート終了してるしLTSでさえないことは諸事情により触れないでください…)
  • Terraform v0.10.7
  • itamae (1.9.11)

Apply

Firehose delivery streams

terraform

  • 構成は端的に書くと以下

    • 他サービスと同じリージョンに作成するなら、構造は分離しなくてもOK
.
├── kinesis_firehose_delivery_stream.tf
├── main.tf
└── terraform_remote_state.tf
main.tf
// config
provider "aws" {
  region  = "ap-northeast-1"
  profile = "xxxxxx"
}
// backend
terraform {
  backend "s3" {
    bucket  = "xxxxxx"
    key     = "xxxxxx"
    region  = "ap-northeast-1"
    profile = "xxxxxx"
  }
}
terraform_remote_state.tf
data "terraform_remote_state" "xxxxxx" {
  backend = "s3"
  config {
    bucket  = "xxxxxx"
    key     = "xxxxxx"
    region  = "ap-northeast-1"
    profile = "xxxxxx"
  }
}
kinesis_firehose_delivery_stream.tf
// syslog
resource "aws_kinesis_firehose_delivery_stream" "xxxxxx-syslog" {
  name        = "xxxxxx-syslog"
  destination = "s3"
  s3_configuration {
    role_arn        = "${aws_iam_role.xxxxxx.arn}"
    buffer_interval = "300"
    buffer_size     = "5"
    bucket_arn      = "arn:aws:s3::: xxxxxx"
    prefix          = "kinesis-firehose/rsyslog/syslog/"
  }
}

itamae

  • 構成は以下
.
├── provisioner
│   └── cookbooks
│       ├── aws-kinesis
│       │   ├── default.rb
│       │   └── file
│       │       └── etc
│       │           └── aws-kinesis
│       │               └── agent.json
default.rb
#kinesis-agent depend-packages install
execute "updte repository" do
  command "sudo apt-get update"
end

package 'openjdk-8-jdk' do
  action :install
end

#kinesis-agent install
execute "git clone" do
  command "git clone https://github.com/awslabs/amazon-kinesis-agent.git"
  not_if 'test -e /home/ubuntu/amazon-kinesis-agent'
end

execute "build" do
  command "cd /home/ubuntu/amazon-kinesis-agent;./setup --build"
end

execute "install" do
  command "cd /home/ubuntu/amazon-kinesis-agent;./setup --install"
end

#change to the agent.json
remote_file "/etc/aws-kinesis/agent.json" do
  source "file/etc/aws-kinesis/agent.json"
  mode "644"
  owner "root"
  group "root"
end

directory "/var/log/nginx" do
  mode "755"
end

service 'aws-kinesis-agent' do
  action [:enable, :start]
end
agent.json
{
  "cloudwatch.emitMetrics": true,
  "cloudwatch.endpoint": "https://monitoring.ap-northeast-1.amazonaws.com",
  "firehose.endpoint": "https://firehose.ap-northeast-1.amazonaws.com",
  "flows": [
    {
      "filePattern": "/var/log/syslog*",
      "deliveryStream": "xxxxxx-syslog",
      "initialPosition": "END_OF_FILE",
      "maxBufferAgeMillis": "60000",
      "maxBufferSizeBytes": "1048576",
      "maxBufferSizeRecords": "100",
      "minTimeBetweenFilePollsMillis": "100",
      "partitionKeyOption": "RANDOM",
      "skipHeaderLines": "0",
      "truncatedRecordTerminator": "'n'"
    }
//以下、必要な分を記述
  ]
}

Check

  • プロセスは正常に起動しているか確認

    • ヒープ全体はデフォルトで512MBなので、要チューニング
    PID USER      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND
    12037 999       20   0 4053620 244480  19052 S   1.1  1.5   3:47.96 /usr/bin/java -server -Xms32m -Xmx512m -XX:OnOutOfMemoryError="/bin/kill -9 %p" -cp /usr/share/aws-kinesis-agent/lib:/usr/share/aws-kinesis-+
    9 root      20   0       0      0      0 S   0.3  0.0   1:00.50 [rcuos/0]
    18 root      20   0       0      0      0 S   0.3  0.0   0:15.21 [rcuos/1]
    1 root      20   0   35896   6024   3688 S   0.0  0.0   0:02.82 /sbin/init
    
  • /var/log/aws-kinesis-agent/aws-kinesis-agent.logにError,WARNが出てないか確認

  • 指定したバケットにログが格納されているか確認

Monitor

  • kinesis-agentが正常に動作してるかCloudWatchで監視
.
├── kinesis_firehose_delivery_stream.tf
├── cloudwatch_metric_alarm.tf
├── main.tf
└── terraform_remote_state.tf
  • treat_missing_dataを使用することで不連続なデータの扱いを定義できます
treat_missing_data - (Optional) Sets how this alarm is to handle missing data points. The following values are supported: missing, ignore, breaching and notBreaching. Defaults to missing.
cloudwatch_metric_alarm.tf
resource "aws_cloudwatch_metric_alarm" "xxxxxx-syslog-ServiceErrors" {
  alarm_name          = "[KINESIS-AGENT] xxxxxx-syslog-ServiceErrors"
  alarm_description   = "Number of calls to PutRecords that have become service errors (except throttling errors) within the specified time period"
  comparison_operator = "GreaterThanOrEqualToThreshold"
  evaluation_periods  = "1"
  treat_missing_data  = "notBreaching"
  metric_name         = "ServiceErrors"
  namespace           = "AWSKinesisAgent"
  period              = "300"
  statistic           = "Sum"
  threshold           = "2"
  alarm_actions       = ["arn:aws:sns:ap-northeast-1:012345678910:xxxxxx"]
  ok_actions          = ["arn:aws:sns:ap-northeast-1:012345678910:xxxxxx"]
  dimensions {
    Destination = "DeliveryStream:xxxxxx-syslog"
  }
}

Caution

  • agentには取得対象のログがローテートされた時copytruncateが定義されているとエージェントが停止するバグがあるので、createを使用します

続きを読む