SlackのワークフローでAWS Chatbotを動かして、EC2を開始&停止する仕組みを作ってみた

Slackのワークフローで、AWS Chatbotのコマンドを実行します。AWS ChatbotでLambdaを動かし、EC2を制御します。
2021.09.27

AWS Chatbotを使ってLambdaを実行すれば、SlackからEC2の開始・停止を簡単にできます。 しかし、毎回コマンドを入力して実行するのはめんどくさいです。 そこでふと思いました。

「Slackのワークフローを使えば、ボタンぽちーで終わるんちゃう?」

基本的には、下記の記事を「AWS SAMで作ってみた」&「Slackワークフローで簡易化した」内容です。

おすすめの方

  • AWS ChatbotでEC2を開始・停止したい方
  • AWS ChatbotでLambdaを実行したい方
  • AWS ChatbotでRead系のAWSコマンドを実行したい方
  • AWS SAM(CloudFormation)でAWS ChatbotとLambdaを作りたい方
  • SlackのワークフローでAWS Chatbotのコマンドを実行したい方

前提

  • Amazon EC2インスタンスは作成済みとします

AWS Chatbotを準備する

Slackワークスペースの認証とワークスペースID取得

WebコンソールでAWS Chatbotにアクセスし、ワークスペースを追加します。下記のワークスペースIDはあとで必要なのでメモしておきます。

SlackワークスペースのIDを確認する

SlackチャンネルIDを取得

任意のチャンネルのリンクを取得します。

SlackチャンネルIDを確認する

このリンクの最後の文字列を使います。下記例だとABCD1234がチャンネルIDです。

https://classmethod.slack.com/archives/ABCD1234

Lambdaを作成する

SAM Init

sam init \
    --runtime python3.8 \
    --name Slack-EC2-Command \
    --app-template hello-world \
    --package-type Zip

SAMテンプレート

下記を作成しています。

  • AWS Chatbotのチャンネル設定
  • AWS Chatbot用のIAMロール
  • Lambda(開始・停止)
  • CloudWatch logs

AWS Chatbot用のIAMロールには、最低限の権限のみを付与しています。

template.yaml

AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: Slack-EC2-Command

Parameters:
  Env:
    Type: String
    Default: Env

  SlackWorkspaceId:
    Type: String

  SlackEc2ChannelId:
    Type: String

Resources:
  Ec2SlackChatbot:
    Type: AWS::Chatbot::SlackChannelConfiguration
    Properties:
      ConfigurationName: !Sub xxx-ec2-slack-chatbot-${Env}
      IamRoleArn: !GetAtt Ec2SlackChatbotIamRole.Arn
      LoggingLevel: INFO
      SlackWorkspaceId: !Ref SlackWorkspaceId
      SlackChannelId: !Ref SlackEc2ChannelId

  Ec2SlackChatbotIamRole:
    Type: AWS::IAM::Role
    Properties:
      RoleName: !Sub xxx-ec2-slack-chatbot-role-${Env}
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Principal:
              Service: chatbot.amazonaws.com
            Action: sts:AssumeRole
      Policies:
        - PolicyName: !Sub xxx-ec2-slack-chatbot-policy-${Env}
          PolicyDocument:
            Version: 2012-10-17
            Statement:
              - Effect: Allow
                Action:
                  - lambda:invokeAsync
                  - lambda:invokeFunction
                Resource:
                  - !GetAtt StartEc2Function.Arn
                  - !GetAtt StopEc2Function.Arn
              - Effect: Allow
                Action:
                  - ec2:DescribeInstanceStatus
                Resource:
                  - "*"

  StartEc2Function:
    Type: AWS::Serverless::Function
    Properties:
      FunctionName: !Sub xxx-start-ec2-${Env}
      CodeUri: start_ec2/
      Handler: app.lambda_handler
      Policies:
        - arn:aws:iam::aws:policy/AmazonEC2FullAccess
      Runtime: python3.8
      Timeout: 10

  StartEc2FunctionLogGroup:
    Type: AWS::Logs::LogGroup
    Properties:
      LogGroupName: !Sub /aws/lambda/${StartEc2Function}

  StopEc2Function:
    Type: AWS::Serverless::Function
    Properties:
      FunctionName: !Sub xxx-stop-ec2-${Env}
      CodeUri: stop_ec2/
      Handler: app.lambda_handler
      Policies:
        - arn:aws:iam::aws:policy/AmazonEC2FullAccess
      Runtime: python3.8
      Timeout: 10

  StopEc2FunctionLogGroup:
    Type: AWS::Logs::LogGroup
    Properties:
      LogGroupName: !Sub /aws/lambda/${StopEc2Function}

Labmdaコード

開始用のLambda

start_ec2/app.py

import boto3

ec2 = boto3.client('ec2')
instances_ids = ['i-xxxxx']

def lambda_handler(event, context):
    ec2.start_instances(InstanceIds=instances_ids)
    print(f'start instance: {instances_ids}')

停止用のLambda

stop_ec2/app.py

import boto3

ec2 = boto3.client('ec2')
instances_ids = ['i-xxxxx']

def lambda_handler(event, context):
    ec2.stop_instances(InstanceIds=instances_ids)
    print(f'stop instance: {instances_ids}')

デプロイ

--parameter-overrides部分は、適宜変更してください。

aws cloudformation package \
    --template-file template.yaml \
    --output-template-file packaged.yaml \
    --s3-bucket cm-fujii.genki-deploy

aws cloudformation deploy \
    --template-file packaged.yaml \
    --stack-name chatbot-ec2-command-stack \
    --capabilities CAPABILITY_NAMED_IAM \
    --parameter-overrides \
        Env=dev \
        SlackWorkspaceId=XYZXYZ \
        SlackEc2ChannelId=ABCD1234 \
    --no-fail-on-empty-changeset

SlackでAWSアプリを招待して、動作を確認する

AWSアプリを招待する

Slackの該当チャンネルで/invite @awsを実行し、AWSアプリを招待します。

AWSアプリを招待する

インスタンス状態を確認する(停止中?)

下記コマンドを実行します。初回のみ、リージョンを指定します。

@aws  ec2 describe-instance-status --instance-ids i-xxxx --include-all-instances true --region ap-northeast-1

AWS Chatbotの動作を確認する

EC2インスタンスは、ストップ状態でした。なお、AWSアカウント等の一部情報は黒塗りしています。

EC2の状態を表示する

EC2開始コマンドを実行する

下記で実行します。

@aws lambda invoke xxx-start-ec2-dev

EC2を起動する

実行すると、AWS Chatbotから「ええんか?」と聞かれるので、「Yes」を選択します。

Yesボタンを押す

無事に実行できました。

Lambdaが実行された

インスタンス状態を確認する(開始した?)

下記コマンドを実行します。

@aws  ec2 describe-instance-status --instance-ids i-xxxx --include-all-instances true

EC2インスタンスが開始しました。

EC2の状態を表示する

EC2停止コマンドを実行する

下記で実行します。

@aws lambda invoke xxx-stop-ec2-dev

EC2を停止する

実行すると、AWS Chatbotから「ええんか?」と聞かれるので、「Yes」を選択します。

Yesボタンを押してLambdaを実行する

インスタンス状態を確認する(停止した?)

下記コマンドを実行します。

@aws  ec2 describe-instance-status --instance-ids i-xxxx --include-all-instances true

EC2インスタンスが停止しました。

EC2の状態を表示する

SlackのワークフローでAWS Chatbotを実行する

ワークフローを作成する

EC2を開始するワークフロー

下記のワークフローを作成します。

Slackのワークフローを作成する(EC2開始)

Slackのワークフローを作成する(EC2開始)

Slackのワークフローを作成する(EC2開始)

@aws部分が認識されない場合は、再入力など試してください。 また、コマンド部分に「by Name」みたいな文字を付与すると、Lambda実行に失敗するので、コマンドのみを記載しています。

EC2を停止するワークフロー

下記のワークフローを作成します。

Slackのワークフローを作成する(EC2停止)

Slackのワークフローを作成する(EC2停止)

Slackのワークフローを作成する(EC2停止)

EC2の状態を確認するワークフロー

下記のワークフローを作成します。

Slackのワークフローを作成する(状態表示)

Slackのワークフローを作成する(状態表示)

Slackのワークフローを作成する(状態表示)

Slackショートカットの様子

作成したワークフローが表示されています。

作成したワークフローの様子

Slackワークフローを実行する

EC2を開始する様子

Slackのワークフローを実行した様子(EC2開始)

EC2の状態を確認する様子

Slackのワークフローを実行した様子(EC2状態表示)

EC2を停止する様子

Slackのワークフローを実行した様子(EC2停止)

おまけ: 開始と停止を分かりやすくする

ワークフローを下記のようにすれば、メッセージ投稿も可能です。

ワークフローを実行した人を表示する

ワークフローを実行した様子です。

ワークフローを実行した人を表示する

さいごに

便利、かつ、楽になりました。エンジニア以外でも使いやすくなったと思います。

参考