slack スラッシュコマンドでaws cliを実行させる方法

外部からawsのインスタンスの状態確認などを行うのに、インスタンスへ接続してコマンドをたたくのがめんどくさい場合に、簡単かつ安全にaws cliを操作したい場合のために、slackのslash commandを利用できるようにしました。

lambda用資材の準備

pipのインストール

sudo yum install epel-release
sudo yum install python-pip --enablerepo=epel
sudo pip install --upgrade pip

アップロード用モジュールの作成

mkdir aws_cli
cd aws_cli
pip install awscli -t ./
pip install colorama -t ./
pip install pyasn1 -t ./
pip install simplejson -t ./
pip install argparse -t ./
pip install pyyaml -t ./

awsコマンド実行ソース

ソースファイル名:aws

#!/usr/bin/python

import sys
import os

if os.environ.get('LC_CTYPE', '') == 'UTF-8':
    os.environ['LC_CTYPE'] = 'en_US.UTF-8'
import awscli.clidriver


def main():
    return awscli.clidriver.main()


if __name__ == '__main__':
    sys.exit(main())

lambda用関数のソース

ソースファイル名:lambda_function.py

import commands
import json
import os
from cStringIO import StringIO
import re
import logging
from base64 import b64decode
from urllib2 import Request, urlopen, URLError, HTTPError
from time import sleep

logger = logging.getLogger()
logger.setLevel(logging.INFO)

print('Loading function')

def _(cmd):
    return commands.getoutput(cmd)

def lambda_handler(event, context):
    logger.info("Event: " + str(event))
    if event['token'] != 'slack slash commandで設定された値':
        return("error")
    etext = event['text']
    ans = _("./aws " + etext)
    response_url = event['response_url']
    slack_message = {
        'channel': '@%s' % event['user_name'],
        'response_type': 'ephemeral',
        'isDelayedResponse': 'true',
        'text': ans
    }
    logger.info("Send message to %s %s", response_url, slack_message)
    req = Request(response_url)
    req.add_header('Content-Type', 'application/json')
    response = urlopen(req, json.dumps(slack_message))
    response.read()
    logger.info("Message posted to %s", slack_message['channel'])
    return("ok")

slack slash commandで設定された値を設定するため、1回作った後に再度変更する必要があります。

資材をzipに固める

chmod 755 -R *
zip -r ../aws_cli.zip *

lambdaの設定

先ほど作ったzipファイルをアップロードします。

aws cliの実行に時間がかかるため、タイムアウトを5分に設定します。

lambdaのロールに自分が制御したいサービスの権限を付加します。

この例では、EC2とS3のアクセス権を追加しています。

api gatewayの設定

GETメソッドを追加します

GETメソッドリクエストのURLクエリ文字列パラメータにslackから渡されるパラメータを追加します。

channel_name
user_id
command
text
team_id
token
channel_id
team_domain
response_url
user_name

GET統合リクエストを編集します。

マッピングテンプレートにlambda関数へ引き渡すパラメータをセットします。

{
  "channel_name" : "$input.params('channel_name')",
  "user_id"      : "$input.params('user_id')",
  "command"      : "$input.params('command')",
  "text"         : "$input.params('text')",
  "team_id"      : "$input.params('team_id')",
  "token"        : "$input.params('token')",
  "channel_id"   : "$input.params('channel_id')",
  "team_domain"  : "$input.params('team_domain')",
  "response_url" : "$input.params('response_url')",
  "user_name"    : "$input.params('user_name')",
  "apiId"        : "$context.apiId"
}

ステージングを行います。

URLの呼び出しを控えておきます。slackの設定で使用します。

slack slash commandの設定

slackにログインした後、下のURLへアクセスしてください。

https://my.slack.com/services/new/slash-commands

コマンドを入力して、追加してください。

API Gatewayで取得したURLを設定してください。

トークンを、lambda_function.pyに設定して、zipに固めなおし、lambdaへ再アップロードしてください。

使用例

ec2のインスタンスの状態を取得

/aws ec2 describe-instances --query 'Reservations[*].Instances[*].[Placement.AvailabilityZone, State.Name, InstanceId]' --output text

結果

ap-northeast-1a    stopped    i-04
ap-northeast-1a    running    i-0a

S3バケットを表示

/aws s3 ls

結果

2019-03-27 05:39:00 aws-athe
2019-02-07 04:02:40 aws-logs