信頼はずっと、挑戦はもっと。

お問い合わせ
TEL:03-3496-3888

BLOG コアテックの社員ブログ (毎週月曜~金曜更新中)

LIST OF ARTICLES

記事一覧

  • 雑記

    これから求められるもの・生存戦略

    本日朝のjwaveにて(と言ってもこれを書いているのは6/25なので少し前なのですが)以下の本の著者が出演し、これから必要となる・変わっていくときに必要となる生存戦略について、古い・新しい価値観の概要について話していました。気になったのでこれから買おうかな、と考えています。という話です!----------ニュータイプの時代新時代を生き抜く24の思考・行動様式山口周 著https://www.diamond.co.jp/book/9784478108345.html----------技術や、こうやっていくのがどうもよさそうだな、という方法論についても、名前を与えられたり、体系立ってまとめられることによって力を得るということもよく経験しています。内容としてはもしかして「そうそう、そう思っていたんだよね。」というものも多いのかもしれません。ですが、それらに関連性や意味付けを行うことによって、もっと飲み込みやすく・吸収しやすくなる、ということもあるのではないでしょうか。----------この本の目次にも「リセット」ありますが、自身として振り返ってみると、関係していることが古くなってきたりすると、「すべてを捨ててやりなおしたい!」となることが多く、かつそういうこともよく行ってきました。(派手な断捨離みたいに捉えるといいでしょうか)ですが、それらも1箇所で、同じようなことを繰り返しているために起こることなのかもしれません。もっと柔軟に、楽しく行っていくことによって、持続可能な働き方というものが可能なのかもしれません。目次から見ると組織間を越境して起動する好奇心に駆動されて働くというところでしょうか。それらの働き方が、珍しいものではなく、普通になると、もっと持続可能な形で成長していけるのかもしれない、ということを考えました。----------本を買う前や、積ん読しているもののタイトル・目次などから「こういうことが書いてるのかな??ワクワクするな!!」と想像する、ってたのしいですよね。まずはこの本を買おうと思います!(この記事が投稿されるまでには買っていると思います!)
  • 画像:ブログサムネイル

    テクログ

    serverless frameworkで API GatewayのプライベートAPIを作成したい!

    プライベートAPI、便利ですね。内部でいろいろやるだけなのに外に出したくないですし。プライベートAPIをAPIGatewayで建てる場合、手動での作成や、既存で建ててあるAPIGatewayにリソースを追加することも可能ですが、serverless frameworkでlambdaのデプロイと同時にAPI GatewayのプライベートAPIを作成したいですよね。なのでやってみました。全体的にはhttps://www.serverless.com/framework/docs/providers/aws/events/apigateway/やhttps://github.com/serverless/serverless/pull/5080にあるのですが、いろいろ摘んで探していかないといけないので書いておきます。serverless.ymlが、このようになります!最低限くらいの内容です。service: internal-apigateway-test provider:   name: aws   endpointType: private   resourcePolicy:     - Effect: Allow       Principal: '*'       Action: execute-api:Invoke       Resource: arn:aws:execute-api:ap-northeast-1:<AWS account ID>:* #リソースにしぼってもいいです       Condition:         StringEquals:           'aws:sourceVpce': vpce-<あらかじめ作成してあるVPC Endpoint です>   runtime: python3.8   region: ap-northeast-1   role: ${opt:role_str, "arn:aws:iam::<AWS account ID>:role/aaaa"} functions:   main:     handler: handler.lambda_handler     name:  internal-apigateway-test     description: "(sample)内部APIGateway+簡単なjsonを返すだけlambdaの作成"     memorySize: 128     timeout: 5     events:       - http:           path: /           method: get ではよいslsライフを!
  • 画像:ブログサムネイル

    テクログ

    wafのサンプルログを定期的にとって、あったら自動でchatworkに通知してほしいというきもち

    どうも、相変わらずいろいろ検証をしています。RDS Proxy はやくGAになってほしいですね。さて、標題の気持ちになったのでLambdaを書きました。ファイル分け?大丈夫大丈夫このくらいなら。冗長だとしてもわかりやすさ優先なのはいつもどおりです。弊社ではcloud9でのserverless frameworkでのデプロイも普通になってきましたね。Lambdaがはかどりますね。さてソースです。こちら、参考URLです。https://dev.classmethod.jp/articles/get-aws-waf-sample-logs/こちらを色々変更し、指定したwaf 指定したルールを 指定した間隔で行うようにしています。環境変数に入るだけ何個でもいけますね。あ、これはCF版ですが、LB版は上のクライアントを変えるだけだと思います。(作って運用しています。増えすぎるのであえてCF版とLB版を分けました)実行はcloudwatch eventsで設定です。slsの設定で。環境変数はこんな感じCHATWORK_API_TOKEN XXあんごうかしたトークンだよXXCHECK_LISTS [{'Name':'ばいたいめいだよ','WebAclID':'aaaa-aaaaとかだよ','WAFName':'わかりやすくするためのwafの名前です','RuleID':'aaaa-bbbbとかのルールID','RuleName':'これも基本わかりやすくするためのルール名'},]INTERVAL 11(とか数字)ROOM_ID 11111111(とかのルームID)# -*- coding: utf-8 -*- #cfのwafのサンプルログを確認し、あれば通知する import os import urllib from datetime import datetime, timedelta import boto3 import sys from base64 import b64decode import ast REGION = "ap-northeast-1" #環境変数 #Chatwork API トークン ENCRYPTED_CHATWORK_API_TOKEN = os.environ['CHATWORK_API_TOKEN'] CHATWORK_API_TOKEN = boto3.client('kms').decrypt(CiphertextBlob=b64decode(ENCRYPTED_CHATWORK_API_TOKEN))['Plaintext'] INTERVAL = int(os.environ['INTERVAL']) ROOM_ID = os.environ['ROOM_ID'] CHECK_LISTS = ast.literal_eval(os.environ['CHECK_LISTS']) #client用意 CF版だよ waf = boto3.client('waf') #### # replace datetime to string #### def time2str(x):     x['Timestamp'] = x['Timestamp'].isoformat()     return x #### #chatworkに通知 #### def postChatwork(message, room_id):   END_POINT_BASE = "https://api.chatwork.com/v2"   END_POINT      = "/rooms/"   ACTION         = "/messages"      headers = { 'X-ChatWorkToken': CHATWORK_API_TOKEN }      data  = { 'body': message }   data = urllib.parse.urlencode(data)   data = data.encode('utf-8')      # リクエストの生成と送信   post_message_url = END_POINT_BASE + END_POINT + room_id + ACTION   request = urllib.request.Request(post_message_url, data=data, method="POST", headers=headers)   with urllib.request.urlopen(request) as response:     response_body = response.read().decode("utf-8")     print(response_body) #### #dictを文字にするだけ #### def makeText(marge_logs):   text = "[info][title]CF版 WAF 検知ログ 直近"+str(INTERVAL)+"分[/title]"      for log in marge_logs:     for key, value in log.items():       text += key + "    " + value + "\n"     text += "[hr]"        text += "[/info]"        return text ### #main ### def lambda_handler(event, context):   #LISTごとに繰り返し   for CHECK_LIST in CHECK_LISTS:     WebAclId = CHECK_LIST['WebAclID']     acl = waf.get_web_acl(WebACLId=WebAclId)          WebACLName = acl['WebACL']['Name']        marge_logs = []     for rule in acl['WebACL']['Rules']:       RuleId = rule['RuleId']              if RuleId == CHECK_LIST['RuleID']:         # get sample requests         r = waf.get_sampled_requests(           MaxItems=3,           WebAclId=WebAclId,           RuleId=RuleId,           TimeWindow={             'EndTime': datetime.utcnow(),             'StartTime': datetime.utcnow() - timedelta(minutes=INTERVAL)           }         )              # check sample count         if 'SampledRequests' not in r or len(r['SampledRequests']) == 0:           #ログのみ           print("WebAclId:" + WebAclId + " RuleId:" +RuleId + " サンプルカウントなし")         else:           # replace datetime to string           logs = list(map(time2str, r['SampledRequests']))           for l in logs:             headers_dict = l['Request']['Headers']                      Host = ''             From = ''             UserAgent = ''             UserAgent2 = ''             Referer = ''             Referer2 = ''             for hd in headers_dict:               if hd['Name'] == 'Host':                 Host = hd['Value']               elif hd['Name'] == 'From':                 From = hd['Value']               elif hd['Name'] == 'User-Agent':                 UserAgent = hd['Value']               elif hd['Name'] == 'user-agent':                 UserAgent2 = hd['Value']               elif hd['Name'] == 'Referer':                 Referer = hd['Value']               elif hd['Name'] == 'referer':                 Referer2 = hd['Value']                          simpledict = {               '媒体名':CHECK_LIST['Name'],               '時間':l['Timestamp'],               'IP':'https://ipee.at/'+l['Request']['ClientIP'],               '国':l['Request']['Country'],               'URI':l['Request']['URI'],               'Headers.Host':Host,               'Headers.From':From,               'Headers.User-Agent':UserAgent + UserAgent2,               'Headers.Referer':Referer + Referer2,               '対象WAF/ルール':CHECK_LIST['WAFName']+' / '+CHECK_LIST['RuleName'],               'Method':l['Request']['Method'],             }             marge_logs.append(simpledict)               # chatwork通知           if marge_logs != []:             try:               print(marge_logs)               cw_text = makeText(marge_logs)               postChatwork(cw_text, ROOM_ID)             except Exception as e:               print(e)           else:             postChatwork("ログないよ", ROOM_ID)#基本ここはないですね ではよいWAF生活を!
  • 画像:ブログサムネイル

    テクログ

    awscliのユーザーを、該当ディレクトリに移動しただけで自動で切り替えたい!

    ●イントロダクションいろいろなものの合間にサーバレス付近の検証を延々やってる昨今ですが、皆様におかれましてはいかがお過ごしでしょうか。サーバレス付近もうちょっとやったら組み合わせてのマイクロサービスとかにすすみたいんだよね〜。Goでペチペチとやってますよ。実行速い。さて、年末ですので、awscliが活躍する時期ですね。そう、隙間のホコリを掃除したりするのに役立ちますね。●やりたいことホコリを掃除するついでにcloud9でServerlessFrameworkを使ってLambdaのデプロイをしてたんですけど、デプロイするステージが正しいかどうかをユーザーを切り替えることによって実現したいなって気分になりました。デフォではdevだけの権限があるので、prodにやると「できないよ?」って言われる、みたいな。ガチガチに縛るとかじゃなくてうっかりを防ぐ安全装置的なやつですね。でも毎回prodの権限があるユーザに切り替えるとかしたくないですね。めんどくさいからね。●profileを切り替えればユーザーも変更できるけど……awscliについて、profileを指定すれば別ユーザーになれるのはご存知ですね。awscliの設定切り替えでもそんなprofile変更を手で毎回やりたくない。makeとかでdev prodを分けるにしたってそれを間違えるからそこではやりたくない。自動でやって…ほしい!!!!●くみあわせ技だよまず、環境変数でクレデンシャルファイルのパスが変えられるんです。ということはユーザーも変えられる。AWS CLIでクレデンシャルファイルパスを環境変数から設定できるようになりましたあとはどこかのディレクトリに移動したとき、自動で環境変数さえ変えられれば!あっ!ディレクトリごとに環境変数を定義 - direnv●おわかりいただけただろうかそういうことでございます。インフルエンザが流行る時期ですが、お気をつけを。よい年を迎えられますよう祈念しております。 画像は記事とは関係ありませんがイメージです
  • 画像:ブログサムネイル

    テクログ

    slackコマンドっぽいことをchatworkでしたい!

    そろそろ夏も終わりですね。はやく涼しくなってほしいですね。そういう気持ちからslackコマンドっぽいことをchatworkでしたい!ということになりました。-----------------------◆本当の経緯もとからslackでのchatops的なものは結構やっていたんですが、弊社slackだけではなくchatworkも使うんですね(ぼやかしで、chatworkもWebhookがあって、slackよりも機能や設定できることは少ないけど、なんとか似たことができそうだな、となったので作りました。-----------------------◆構成chatwork→APIGateway→Tokenやコマンドを検証し、振り分けるLambdaFunction→(SNS)→コマンドの実態LambdaFunction+chatworkへ結果返答わかりやすくするためTokenやコマンドを検証し、振り分けるLambdaFunction を [振り分けLambda]コマンドの実態Lambda を [実態Lambda]とします-----------------------◆設定を簡単に解説細かい設定は書きませんが、いろいろ試行錯誤するのも経験のうちですよね。(1)APIGatewayを作成chatworkのWebhookが叩く入り口です。URLがあればひとまずOKです。パス設定とかはおまかせします。(2)[振り分けLambda]の殻を作成APIGatewayの先のLambdaを作成します。(3)APIGatewayを設定(1)と(2)をつなぎまーす叩くとレスポンスが来るだけ確認しておくのもいいですね。(4)chatworkのWebhook設定chatworkにボットアカウントを作り、そのアカウントでWebhookの設定をします参考:https://help.chatwork.com/hc/ja/articles/115000169541-Webhook%E3%82%92%E8%A8%AD%E5%AE%9A%E3%81%99%E3%82%8BURLはAPIGatewayのURLで、イベントはルームイベントにしました。(なぜなら、目に見えないところではなく、その部屋だけで使ってほしいからです。)メッセージ作成のみ、にしました。(5)[振り分けLambda]を実装ソース!だよ!何もライブラリが要らないってのを重視。なんか貼ったら改行があれなのでまあそこはいいかんじにしてください。何かあってもこちらはサンプルですのでそこはいつものとおりご了承ください。見直すと入ってきた文字整形とか無理矢理感。chatworkはクライアントごとにメッセージの形式が微妙に違ったりしてね…必要な環境変数はCHATWORK_API_TOKEN (KMSで暗号化してある、postに使うchatworkのTokenWEBHOOK_TOKEN (渡ってきたchatworkのメッセージが正しいものかを判定するためのTokenです。# -*- coding: utf-8 -*- # chatwork commanderの入り口 import boto3 import json import logging import os import sys from datetime import datetime from botocore.exceptions import ClientError import copy import urllib.request, urllib.error from base64 import b64decode, b64encode import hmac import hashlib valid_command_list = ['こまんど1','こまんど2','こまんど3'] to_str = "[To:1111111111]" usage_str = "【コマンド一覧】\n" + \ "※それぞれのコマンドの使い方については[コマンド usage]を打って確認してください\n\n" + \ "こまんど1\n" + \ "こまんど2\n" + \ "こまんど3\n" SNS_ARN_PREFIX = "arn:aws:sns:ap-northeast-1:11111111111:chat_command_" #### #メイン #### def lambda_handler(event, context):   #先にイベントは取っておく(判定とかに使うから   eventjson = json.loads(json.dumps(event))   bodyjson = json.loads(eventjson['body'])   room_id    = str(bodyjson['webhook_event']['room_id'])   message_id = str(bodyjson['webhook_event']['message_id'])   body      = str(bodyjson['webhook_event']['body'])   account_id = str(bodyjson['webhook_event']['account_id'])   #まず   #[To:1111111111]   #がないなら無視(全メッセージ流れてくるから   if not to_str in body:     print('not me.END')     return {'statusCode': 200,'body': json.dumps('not me.END')}   #毎回kms使うのがやだからここでやってます   ENCRYPTED_WEBHOOK_TOKEN = os.environ['WEBHOOK_TOKEN']   WEBHOOK_TOKEN = boto3.client('kms').decrypt(CiphertextBlob=b64decode(ENCRYPTED_WEBHOOK_TOKEN))['Plaintext']   ENCRYPTED_CHATWORK_API_TOKEN = os.environ['CHATWORK_API_TOKEN']   CHATWORK_API_TOKEN = boto3.client('kms').decrypt(CiphertextBlob=b64decode(ENCRYPTED_CHATWORK_API_TOKEN))['Plaintext']   #Tokenの確認   if check_request(event, WEBHOOK_TOKEN) == True:     print("Token OK")     #body整形     command_text = body.replace('\n', '').replace('[To:1111111]', '').replace('aaaaa さん', '').replace('aaaaaさん', '').strip()     command_args = command_text.split(" ")     #コマンドの確認     command = command_args[0]     nextStatus = checkCommandStrAndMakeNextStatus(command, room_id, account_id, message_id, command_text, CHATWORK_API_TOKEN)     #nextStatusがTrue(続行)の場合、次のlambdaをSNSで呼ぶ     #続行ではない場合は特に何もせずreturnして終わり     if nextStatus == True:       message = {"room_id"   : room_id,             "command_args": command_args,             "account_id" : account_id,             "message_id" : message_id       }       #SNS_ARN_PREFIX+command がARNになるようになっている       sendSNS(message, SNS_ARN_PREFIX+command)     return {       'statusCode': 200,       'body': json.dumps('OK')     }   else:     print("Token NG")     return {       'statusCode': 403,       'body': json.dumps('NG')     } ##----------------------- def sendSNS(message, sns_TOPIC):   sns_client = boto3.client(     'sns'   )   #メッセージ整形   message=json.dumps(message)   message=json.dumps({'default': message, 'lambda': message})   response = sns_client.publish(     TopicArn=sns_TOPIC,     Subject='/lambda',     MessageStructure='json',     Message=message   )   print(response) #### #コマンドの内容を確認してchatwork通知 #また、今後の続行ステータスを返す #### def checkCommandStrAndMakeNextStatus(command, room_id, account_id, message_id, command_text, CHATWORK_API_TOKEN):   if command == 'usage':     postChatwork(usage_str,room_id, CHATWORK_API_TOKEN)     return False#終了   else:     if not command in valid_command_list:       postChatwork("対象コマンドがありません。\n"+usage_str,room_id, CHATWORK_API_TOKEN)       return False#終了     else:       #chatworkに受付状況を通知       postChatwork(         makeReplyMessage(account_id, room_id, message_id, command_text),         room_id,         CHATWORK_API_TOKEN       )       return True#続行 #### #メッセージをつけるだけ #### def makeReplyMessage(account_id, room_id, message_id, command_text):   return "コマンド:" + command_text + "\nを受け付けました。(コマンドの実態に渡しました)\nお待ち下さい。" #### #chatworkに通知 #### def postChatwork(message, room_id, CHATWORK_API_TOKEN):   print("in postChatwork")   END_POINT_BASE = "https://api.chatwork.com/v2"   END_POINT   = "/rooms/"   ACTION     = "/messages"   headers = { 'X-ChatWorkToken': CHATWORK_API_TOKEN }   data = { 'body': message }   data = urllib.parse.urlencode(data)   data = data.encode('utf-8')   # リクエストの生成と送信   post_message_url = END_POINT_BASE + END_POINT + room_id + ACTION   request = urllib.request.Request(post_message_url, data=data, method="POST", headers=headers)   with urllib.request.urlopen(request) as response:     response_body = response.read().decode("utf-8")     print(response_body) #参考 #https://qiita.com/ikedaosushi/items/b01183f207ea1db6a8d3 def check_request(event, WEBHOOK_TOKEN):   webhook_sig = event['headers']['X-ChatWorkWebhookSignature'].encode('utf-8')   sig = build_sig(event['body'], WEBHOOK_TOKEN)   is_valid = webhook_sig == sig   return is_valid def build_sig(body, WEBHOOK_TOKEN):   token_decode = b64decode(WEBHOOK_TOKEN)   sig = hmac.new(token_decode, body.encode('utf-8'), hashlib.sha256).digest()   sig_encoded = b64encode(sig)   return sig_encoded だいたいでいえば・メッセージはルームのものがすべて来るので、処理対象メッセージなのかを判定・tokenの確認・コマンドの確認・受け付けたことを返答・SNSで次のLambdaを呼ぶ(このSNSを一定の形式に統一することによって、後ろのコマンドを増やしやすくなってます。(6)実態Lambdaを呼ぶためのSNSを作るarn:aws:sns:ap-northeast-1:11111111111:chat_command_ ってなっているようにSNSをまず作りますたとえばmake_EC2みたいなコマンドだった場合、SNS名はchat_command_make_EC2になりますね。(7)[実態Lambda]を作るここは自分でつくってね!SNSを受け取って、分解して、処理をすればいいです。終わったらchatworkに通知したり、いろいろ内部でやればいいですね。夢が広がる。(8)SNSの先に[実態Lambda]を追加まあ追加するだけですあとはchatworkでボットにはなしかけたりしてテストをしてみよう!-----------------------コマンドを増やすときも、許可するコマンドを追加して、SNS作成コマンド実態Lambda作成だけでぽんぽんふえるよ!ルームを分けることによって、重要度ごとに使える人を分けられたりもします。以上夏休みの自由研究にどうぞ。もうおわってますか。-----------------------<以下はただの一覧用の画像でーす>
  • 画像:ブログサムネイル

    テクログ

    ブラウザテストフレームワークの5月でした

    ブラウザテストフレームワーク、使ってますか!単体テストもいいけど、やっぱりユーザが使って実際ちゃんと動作してるの?ってのが気になりますよね。最近はjsでいろいろやることも多いし、関連するところが動かなくなったり。(jsの単体テストやれって話もありますが)で、有償無償問わず、いろいろと見てみました。結構網羅したり、試したりするだけでもそれなりにかかったので、なんとなく一覧的に。・いわゆるツールでの自動テスト系teststudioRanorexAutifyTestCompleteUnified Functional TestingROBOWAREuipathkatalon studioimacros・いわゆるブラウザテストフレームワーク(E2Eテスト用)Seleniumを直使用CodeceptionCodeceptJSNightwatch.jsWebdriverIOScrapywatirAppiumSelenideGebおよびSpockCapybaraSplinterCasperJSSST (selenium-simple-test)重要視した点としては、パッとつくれて、パッと動かせる。なんだこれ、どうやるんだ、みたいなのはなし。……ということで、有償の自動テストツール系について、可能なものは体験版を入れてちょっと動かしたりしました。「ちょっと」なのはあえてちょっとだけやって、それでもできないのならば簡単じゃない!ということでした。もちろんデモや動画をみてると、「なんかすごいことやってるし、なんでもできそう…」となりますし、実際理解すればなんでもできるのかもしれません。でも少しだけいじっただけでは全く思ったとおりに動かないんですよね。というわけでツール系はなくなり、ブラウザテストフレームワークの検証となりました。テストコード書かないといけない、というのは確かに手軽とはいえないですが、サンプルがあればあとはその改良をつづけていけばなんとかなる、という思惑です。現状のサポート具合、活発さ、書きやすさ…などからCodeceptionCodeceptJSが残り、mac,PCでのブラウザテストはクリア。実機もやりたい、ということでAppium連携をしたり…ということをやっていましたよ。実機動作は結構コツが必要だったり、iPhoneだとやりたいことがどうしてもできない部分があったり…となりましたが、それ以外は結構思ったとおりのテストができましたので、毎回確認しないといけない動作がある、とか、そういった場合には役に立つのではないでしょうか。一個小ネタでいえば、テストをAWS Lambdaに連携させて、外への影響を確認したりする、ということもやってみました。純粋なE2Eテストの範疇からは外れるかとは思いますが、やはりどうしても確認したい内容もありますので、そういうものもいかがでしょう。ちなみに最終的に残ったのはCodeceptJS+Appiumでした!(以下イメージ画像