slackのslash commandの処理をaws lambdaで実装してみました

12
Slack Slash command の処理をAWS Lambda で実装してみました 株式会社サイタスマネジメント 米田 真治 1 2016/4/22 JAWS-UG アーキテクチャ専門支部 クラウドネイティブ 分科会 CDP議論会 #8

Upload: komeda-shinji

Post on 15-Apr-2017

644 views

Category:

Software


0 download

TRANSCRIPT

Page 1: SlackのSlash commandの処理をAWS Lambdaで実装してみました

SlackのSlash commandの処理をAWS Lambdaで実装してみました株式会社サイタスマネジメント

米田真治

1

2016

/4/2

2JA

WS-

UG

アーキテクチャ専門支部クラウドネイティブ

分科会

CDP議論会

#8

Page 2: SlackのSlash commandの処理をAWS Lambdaで実装してみました

自己紹介•米田真治 (こめだ しんじ)

� 株式会社サイタスマネジメント CTO� 運用エンジニア

• 経歴� 学生時代にUNIXに出会う� Internetにつながる環境がきた� いろんなプログラムをビルドしているうちに、開発・構築の楽しさに目覚める

� 学科のシステム管理を経験

� システム運用のおもしろさを覚える

� 就職してISPのサーバ構築・運用に携わる� 2000年6月サイタスマネジメント創業

2016

/04/

20OSS運用管理勉強会

2

Page 3: SlackのSlash commandの処理をAWS Lambdaで実装してみました

全体像

3

2016

/4/2

2JA

WS-

UG

アーキテクチャ専門支部クラウドネイティブ

分科会

CDP議論会

#8

Page 4: SlackのSlash commandの処理をAWS Lambdaで実装してみました

利用したblueprint• slack-­echo-­command-­python

Slack 側は Custom Integrations の Slash Commands を使用します。

• cloudwatch-­alarm-­to-­slack-­pythonevent['Records'][0]['Sns']['Message']からメッセージを取り出します。Incoming Webhooksでなく response_url を使って応答を返すように修正しました。

4

2016

/4/2

2JA

WS-

UG

アーキテクチャ専門支部クラウドネイティブ

分科会

CDP議論会

#8

Page 5: SlackのSlash commandの処理をAWS Lambdaで実装してみました

シナリオSlack → API Gateway → Lambda

Slack 側では Slash Commands を使用します。Lambda 関数の処理では 3 秒以内にSlack 側へ応答を返す必要があります。時間がかかる処理を行うために、Lambda で受信したコマンドは、SNS を経由して別の Lambda 関数をイベント起動します。

5

2016

/4/2

2JA

WS-

UG

アーキテクチャ専門支部クラウドネイティブ

分科会

CDP議論会

#8

Page 6: SlackのSlash commandの処理をAWS Lambdaで実装してみました

シナリオLambda → SNS → Lambda → SlackSNS イベントから起動される Lambda 関数では STS を利用して、Slash Command を発行したユーザのロールを引き受けてAPI コマンドを実行します。

{"user_name":  "komeda",  "command":  "/lambda",  "channel":  "genral",  "command_text":  "ec2  start  i-­‐xxxxxxxx",  "response_url":  "https://...."

}

6

2016

/4/2

2JA

WS-

UG

アーキテクチャ専門支部クラウドネイティブ

分科会

CDP議論会

#8

Page 7: SlackのSlash commandの処理をAWS Lambdaで実装してみました

API Gatewayの設定

7

2016

/4/2

2JA

WS-

UG

アーキテクチャ専門支部クラウドネイティブ

分科会

CDP議論会

#8

Page 8: SlackのSlash commandの処理をAWS Lambdaで実装してみました

lambda-bot関数概要def lambda_handler(event,  context):

req_body =  event['body']params =  parse_qs(req_body)トークンチェック引数取りだしarg =  command_text.split('  ')

if  arg[0]  in  ['ec2',  's3']:sns =  boto3.client('sns')topic_arn =  sns.create_topic(Name='sns-­‐lambda')['TopicArn']message={"user_name":  user,  "command":  command,  "channel":  channel,  "command_text":  com

mand_text,  "response_url":  response_url}message=json.dumps(message)message=json.dumps({'default':  message,  'lambda':  message})response  =  sns.publish(

TopicArn=topic_arn,Subject='/lambda',MessageStructure='json',Message=message

)return  {  "text":  "%s  %s¥nroger"  %  (command,  command_text)  }

elif arg[0]  ==  'help':return  {  "text":  "ec2  [console|start|stop instance-­‐id]¥ns3  [usage  bucket]"  }

else:return  {  "text":  "%s  invoked  %s  in  %s  with  the  following  text:  %s"  %  (user,  command,  ch

annel,  command_text)  }

8

2016

/4/2

2JA

WS-

UG

アーキテクチャ専門支部クラウドネイティブ

分科会

CDP議論会

#8

Page 9: SlackのSlash commandの処理をAWS Lambdaで実装してみました

notify-to-slack関数概要def lambda_handler(event,  context):

message  =  event['Records'][0]['Sns']['Message']logger.info("Event:  "  +  str(message))if  True:

message  =  json.loads(message)引数取りだしarg =  command_text.split('  ')slack_message =  {

'channel':  '@%s'  %  user_name, 'response_type':  'ephemeral', #  or  'in_channel''isDelayedResponse':  'true','text':  "%s  %s"  %  (command,  command_text)

}if  arg[0]  ==  'ec2':

slack_message['text']  =  ec2_command(arg,  user_name,  response_url)send_response(response_url,  slack_message)

elif arg[0]  ==  's3':slack_message['text']  =  s3_command(arg,  user_name,  response_url)send_response(response_url,  slack_message)

else:slack_message =  {  'text':  "command  failed"  }send_response(response_url,  slack_message)

9

2016

/4/2

2JA

WS-

UG

アーキテクチャ専門支部クラウドネイティブ

分科会

CDP議論会

#8

Page 10: SlackのSlash commandの処理をAWS Lambdaで実装してみました

STSでの権限の引き受けポリシー名とロール名をハードコードしています。ほかに良い方法があれば…

iam =  boto3.client('iam')response  =  iam.get_user(UserName=user_name)if  response.has_key('User'):

uid =  response['User']['Arn'].split(':')[4]if  uid and  boto3.resource('iam').UserPolicy(user_name,  'ec2-­‐full-­‐access'):

response  =  iam.get_role(RoleName='virginia-­‐ec2-­‐delegate')if  response.has_key('Role'):

sts =  boto3.client('sts')assumedRoleObject =  sts.assume_role(RoleArn="arn:aws:iam::%s:role/%s"  %  

(uid,  'virginia-­‐ec2-­‐delegate'),  RoleSessionName='session')credentials  =  assumedRoleObject['Credentials']ec2  =  boto3.resource(

'ec2',aws_access_key_id=credentials['AccessKeyId'],aws_secret_access_key=credentials['SecretAccessKey'],aws_session_token =  credentials['SessionToken'],)

10

2016

/4/2

2JA

WS-

UG

アーキテクチャ専門支部クラウドネイティブ

分科会

CDP議論会

#8

Page 11: SlackのSlash commandの処理をAWS Lambdaで実装してみました

response_urlに応答を返すdef send_response(response_url,  message):

req =  Request(response_url)req.add_header('Content-­‐Type',  'application/json')try:

response  =  urlopen(req,  json.dumps(message))response.read()

except  HTTPError as  e:logger.error("Request  failed:  %d  %s",  e.code,  e.reason)

except  URLError as  e:logger.error("Server  connection  failed:  %s",  e.reason)

11

2016

/4/2

2JA

WS-

UG

アーキテクチャ専門支部クラウドネイティブ

分科会

CDP議論会

#8

Page 12: SlackのSlash commandの処理をAWS Lambdaで実装してみました

課題• 認証

� いまのところ、Slackのユーザ名をAWSのユーザ名に対応づけて扱っています。

� コマンド実行のときは、できればユーザ認証をしたい。

� MFAできればよいけれど… …� Cognitoの新機能「User Pools」を使えばMFAできるの?

• STS� ポリシー名とロール名をハードコードしているところ、ユーザが持っている権限をチェックできた方がよい。

� 実用上はハードコードでもかまわない?

12

2016

/4/2

2JA

WS-

UG

アーキテクチャ専門支部クラウドネイティブ

分科会

CDP議論会

#8