AWS Lambda Python3.8 から Slack へメッセージを送る設定を terraform で作成する

【個人備忘録】lambdaからslackへメッセージを送るシンプル設定

# 概要
* Slack API へのメッセージ送信に関して
 * [slackweb ライブラリ](https://pypi.org/project/slackweb) は使わない (ローカル環境にライブラリインストールしてあれやこれやがめんどくさい)。
 * Python標準ライブラリの urllib を使う。
 * Slack API へ渡す情報は、Lambdaの環境変数に設定する。

* Terraform での Lambda 作成に関して
 * aws provider の バージョンは 2.48.0 
 * Lambda関数コード（pythonソースコード）は、**terraform archive provider** の data ソース **archive_file** を使って zip にしてから、deployする。

* 送信イメージ
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/148868/7bca8ab8-442e-e155-e64f-517e591c20a3.png)


# Terraform 設定

* Terraform実行環境 ローカルディレクトリ構成 (MacOS)

<pre>
├── .terraform
│   ├── plugins
│   │   └── darwin_amd64
│   │       └── terraform-provider-aws_v2.48.0_x4
├── post-slack.tf
└── source_code
    └── post-slack
        └── main.py
</pre>

* Lambda関数を作成する tf ファイル

```terraform:post-slack.tf
data "archive_file" "post-slack" {
  type        = "zip"
  source_dir  = "./source_code/post-slack"
  output_path = "./source_code/post-slack.zip"
}
resource "aws_lambda_function" "post-slack" {
  filename         = "${data.archive_file.post-slack.output_path}"
  function_name    = "post-slack"
  role             = "arn:aws:iam::※※※※※※※※※※※※:role/service-role/lambda-basic-execution"
  handler          = "main.lambda_handler"
  source_code_hash = "${data.archive_file.post-slack.output_base64sha256}"
  runtime          = "python3.8"
  memory_size      = 128
  timeout          = 300
    environment {
    variables = {
      SLACK_CHANNEL = "#hogehoge"
      SLACK_TEXT = "Slack通知テスト"
      SLACK_USER_NAME = "名無し"
      SLACK_ICON_EMOJI = ":fearful:"
      SLACK_COLOR = "warning"
      SLACK_WEBHOOK_URL = "https://hooks.slack.com/services/※※※※※※※※※/※※※※※※※※※/※※※※※※※※※※※※※※※※※※※※※※※※"
    }
  }
}
```

* Lambda に割り当てる IAMロール

```terraform:lambda-basic-execution
data "aws_iam_policy_document" "lambda-assume-role-policy" {
  statement {
    actions = ["sts:AssumeRole"]
    principals {
      type        = "Service"
      identifiers = ["lambda.amazonaws.com"]
    }
  }
}
resource "aws_iam_role" "role_lambda-basic-execution" {
  name               = "lambda-basic-execution"
  assume_role_policy = data.aws_iam_policy_document.lambda-assume-role-policy.json
  path               = "/service-role/"
}
resource "aws_iam_role_policy_attachment" "AWSLambdaBasicExecutionRole" {
  role       = aws_iam_role.role_lambda-basic-execution.name
  policy_arn = "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"
}
```


* Slack API へメッセージを送信する python コード

```python:source_code/post-slack/main.py
import os
import json
from urllib.request import Request, urlopen

slackChannel = os.environ['SLACK_CHANNEL']
slackUserName = os.environ['SLACK_USER_NAME']
slackText = os.environ['SLACK_TEXT']
slackWebhookURL = os.environ['SLACK_WEBHOOK_URL']
slackIconEmoji = os.environ['SLACK_ICON_EMOJI']
slackColor = os.environ['SLACK_COLOR']

def lambda_handler(event, context):
    post_slack()

def post_slack():
    message = {
        'channel': slackChannel,
        'username': slackUserName,
        'text': slackText,
        'icon_emoji': slackIconEmoji,
        'attachments': [
            {
                "color": slackColor,
                "text": "なんて日だ・・"
            }
        ]
    }
    data = json.dumps(message).encode('utf-8')
    request = Request(slackWebhookURL, data)
    urlopen(request).read()
```

# terraform plan

**terraform plan 初回実行時に次のようなエラーが出た場合は、**

<pre>$ terraform plan</pre><pre>
Error: Could not satisfy plugin requirements


Plugin reinitialization required. Please run "terraform init".

Plugins are external binaries that Terraform uses to access and manipulate
resources. The configuration provided requires plugins which can't be located,
don't satisfy the version constraints, or are otherwise incompatible.

Terraform automatically discovers provider requirements from your
configuration, including providers used in child modules. To see the
requirements and constraints from each module, run "terraform providers".


Error: provider.archive: no suitable version installed
  version requirements: "(any version)"
  versions installed: none
</pre>

**terraform init を実行する**

<pre>
$ terraform init
</pre>

<pre>
Initializing the backend...

Initializing provider plugins...
- Checking for available provider plugins...
- Downloading plugin for provider "archive" (hashicorp/archive) 2.0.0...

The following providers do not have any version constraints in configuration,
so the latest version was installed.

To prevent automatic upgrades to new major versions that may contain breaking
changes, it is recommended to add version = "..." constraints to the
corresponding provider blocks in configuration, with the constraint strings
suggested below.

* provider.archive: version = "~> 2.0"

Terraform has been successfully initialized!

You may now begin working with Terraform. Try running "terraform plan" to see
any changes that are required for your infrastructure. All Terraform commands
should now work.

If you ever set or change modules or backend configuration for Terraform,
rerun this command to reinitialize your working directory. If you forget, other
commands will detect it and remind you to do so if necessary.
</pre>

**pluginsディレクトリに terraform-provider-aws_v2.48.0_x4 がダウンロードされた**
<pre>
├── .terraform
│   ├── plugins
│   │   └── darwin_amd64
│   │       ├── terraform-provider-archive_v2.0.0_x5
│   │       └── terraform-provider-aws_v2.48.0_x4
</pre>

# terraform apply

<pre>
$ terraform apply
</pre>

**実行後に source_code ディレクトリに post-slack.zip ができる**
<pre>
└── source_code
    ├── post-slack
    │   └── main.py
    └── post-slack.zip
</pre>

# AWSマネジメントコンソール で確認

**Lambda 関数「post-slack」の設定**

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/148868/df89a87e-9366-c440-0f56-042cdd0640b5.png)

**テスト実行**

* テストイベント作成
    ![20201113-01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/148868/075b3894-b47c-834d-394e-4cc815337cce.png)    
![20201113-02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/148868/997af27a-f2a3-e906-8710-2c4eb39b9386.png)

* テスト実行
    ![20201113-03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/148868/4fdb19c2-eed0-aade-4792-fdb2166c8f80.png)

* cloudwatch logs ロググループ
    ![20201113-04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/148868/10d076cf-ae88-45d3-db4b-951def52ea1c.png)
    ![20201113-05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/148868/95184a34-f0ac-0a28-c3e5-87a6d2ddc818.png)

* slack通知
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/148868/7bca8ab8-442e-e155-e64f-517e591c20a3.png)