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

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

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

LIST OF ARTICLES

記事一覧

  • テクログ

    Lambdaを試してみました

    お久しぶりです。在宅勤務になり、時間に余裕ができたのでAWSを色々試していました。今回はLambdaについて紹介したいと思います。処理の内容はS3のimagesにjpgの画像をアップすると、別のバケットにリサイズされた画像がアップされ、画像のアップロードパスと登録日時がdynamoDBに登録されます。まず、Lambda上でPillowを使えるようにするために、EC2で下記を実行しました。sudo yum -y install gcc openssl-devel bzip2-devel libffi-devel wget https://www.python.org/ftp/python/3.8.1/Python-3.8.1.tgz tar xzf Python-3.8.1.tgz cd Python-3.8.1 sudo ./configure --enable-optimizations sudo make altinstall pip3.8 install pillow -t . 上記で作成されたPILとPillow.libsとPillow-7.1.2.dist-infoとlambda_function.pyをzipで固めてアップロードします。次にLambdaのトリガーの設定ですが、S3を選択し、下記内容を入力し、追加をクリックします。バケット sample イベントタイプ すべてのオブジェクト作成イベント プレフィックス-オプション images/ サフィックス-オプション .jpg トリガーの有効化 チェック 次にdynamoDBで画像管理テーブルとautoincrementがないためidを管理するテーブルを作成します。テーブルを作成後、idsテーブルにtable_nameがs3_images、idが0を登録します。・s3_images id 主キー   数値型 upload_path 文字列型 created_at  文字列型 ・ids table_name 主キー 文字列型 id                数値型 次にS3で下記の二つのバケットを作成します。sample sample-resize 最後にlambda_function.pyは下記の内容です。import boto3 import os import sys import uuid from urllib.parse import unquote_plus from PIL import Image import PIL.Image import datetime s3_client = boto3.client('s3') dynamodb = boto3.resource('dynamodb') def resize_image(image_path, resized_path):   with Image.open(image_path) as image:     image.thumbnail(tuple(x / 2 for x in image.size))     image.save(resized_path) def get_id(table_name):   table = dynamodb.Table('ids')   data = table.update_item(     Key = {       'table_name': table_name     },     UpdateExpression = 'ADD id :id_val',     ExpressionAttributeValues = {       ':id_val': 1     },     ReturnValues = "UPDATED_NEW"   )       res = table.get_item(     Key = {       'table_name': table_name     }   )   return res['Item']['id'] def insert_dynamodb(id, upload_path):   table= dynamodb.Table('s3_images')   now = datetime.datetime.now()   table.put_item(     Item = {       'id': id,       'upload_path': upload_path,       'created_at': now.strftime("%Y-%m-%d %H:%M:%S")     }   ) def lambda_handler(event, context):   for record in event['Records']:     bucket = record['s3']['bucket']['name']     key = unquote_plus(record['s3']['object']['key'])     tmpkey = key.replace('/', '')     download_path = '/tmp/{}{}'.format(uuid.uuid4(), tmpkey)     upload_path = '/tmp/resized-{}'.format(tmpkey)     s3_client.download_file(bucket, key, download_path)     resize_image(download_path, upload_path)     s3_client.upload_file(upload_path, '{}-resized'.format(bucket), key)           id = get_id('s3_images')     insert_dynamodb(id, upload_path) これでS3のsampleバケットのimagesにjpgの画像をアップすると、sample-resizeバケットにリサイズされた画像がアップされます。Lambdaの設定は一部割愛しましたが、以上となります。
  • テクログ

    git clone 時に出た 「the remote end hung up unexpectedly」に辛勝した話

    どうも!エンジニア歴2年目に突入したわいです。連投になって申し訳ないんですけど、先日ハマった沼から抜け出すために苦悩したことを備忘録として書き留めます。ウダウダ書いていますが、結果だけ知りたい方はまとめまで読み飛ばしてください。何が起きたか開発環境を CodeCommit から git clone したときに、下記のエラーに阻まれた。(いろいろあって開発環境を消してしまった…)FATAL ERROR: Remote side unexpectedly closed network connection fatal: the remote end hung up unexpectedly fatal: early EOF fatal: index-pack failed 1行目のエラーメッセージはなぜかコロコロ変わったりした。開発環境がないので、このままだと仕事ができないとかなり焦り、先輩に相談。>どうやら、リポジトリの容量がでかすぎるらしい試しに、先輩にもcloneし直してもらうと、、成功したあわよくばと思ったが、自力で解決するしかなくなった、、正直、Git Extensions のぬるま湯に1年間浸かりつづけていたので、Git が全くわかっていない。とりあえず、ガンガン試していく作戦に出た。何を試したかこれらの記事を参考にさせていただきました。ありがとうございます。https://stackoverflow.com/questions/6842687/the-remote-end-hung-up-unexpectedly-while-git-cloninghttps://cithukyaw.wordpress.com/2014/09/08/fix-for-the-fatal-error-early-eof-on-git-clone/https://qiita.com/cacahuatl/items/4d763e98f3934e3569ca① 「http.postBuffer」の設定を変更するgit config --global http.postBuffer 524288000 >結果は変わらなかったさらに2倍にしてみるgit config --global http.postBuffer 1048576000 >結果は変わらなかった② 「core.compression」を設定するhttps://git-scm.com/docs/git-configgit config --global core.compression 0 >結果は変わらなかった>設定値を -1, 9 と変えてみたが、結果は変わらなかった③  ssh接続のタイムアウトを設定する「Remote side unexpectedly closed network connection」で検索すると、sshのタイムアウトっぽいことが出てきたので試してみた~/.ssh/configServerAliveInterval 60 ServerAliveCountMax 3 >結果は変わらなかった④  一度にcloneする量を減らす(shallow clone)git clone --depth 1 <my_repo_URI> >結果は変わらなかったいくら調べても他の解決法が出てこないので、この時点でかなり詰んだと思った⑤  有線接続に変える在宅になってから、家の Wi-Fi で仕事をしていたことに先輩の一言で気づいたclone中の「MiB/s」が2倍近く増えたが、、>結果は変わらなかった>①~④のどれも結果は変わらなかった絶望の淵に立たされていたときに、一筋の光が差し込んだ⑥  masterブランチよりも軽いブランチをcloneするgit clone -b <smaller_branch> <my_repo_URI> >結果は変わらなかった一度にcloneする量を減らす(shallow clone)git clone -b <smaller_branch> --depth 1 <my_repo_URI> >clone成功!!現在、<smaller_branch>の最新のコミットだけ取得している状態なので、<smaller_branch>の全履歴を取得git fetch --unshallow >またもや、同様のエラーコミット数を制限して少しずつ履歴を取得git fetch --depth 8 # コミット数:8は任意 >fetch成功!!残りの履歴を取得git fetch --unshallow >fetch成功!!⑦  masterブランチを含め、他のブランチ情報を取得する.git/config の<smaller_branch>を * に変更する[remote "origin"]     url = <my_repo_URI>     fetch = +refs/heads/*:refs/remotes/origin/* git fetch >fetch成功!!これですべての履歴が取得できた>やっとの思いで、開発環境が復活!!まとめ結局、必要だったコマンド。git config --global http.postBuffer 524288000 git clone -b <smaller_branch> --depth 1 <my_repo_URI> git fetch --depth 8 git fetch --unshallow .git/config[remote "origin"]     url = <my_repo_URI>     fetch = +refs/heads/*:refs/remotes/origin/* git fetch 有線接続では以上のコマンドでcloneできた。Wi-Fi の場合、最後の git fetch だけがうまくいかなかった。>いきなり、* で fetch するのではなくて、別のブランチを一度 fetch して、再度 * で fetch したらいけたうーん、Gitムズイ、、そもそも、alpineでDocker環境を作ってたら、こんなことには、、他にいい方法があれば教えてください!以上、わいでした。健闘を祈る!!
  • 画像:ブログサムネイル

    テクログ

    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生活を!
  • テクログ

    【AWS】ELBのログをS3に保存して、Athenaで検索しよう!

    こんにちは皆さんAWS使ってますか?LB、使ってます??AWSのLBもいくつか種類がありますねhttps://docs.aws.amazon.com/elasticloadbalancing/index.html弊社も大変お世話になっていますそんなこんなでLBのアクセスログをS3に保存するととてもいいことがあります。https://tech.basicinc.jp/articles/46詳しいやり方はこちらのサイト様を参考にして頂いて・・・S3に保存するとAthenaでSQLを使って検索が出来るようになるので非常に便利です。よく使うクエリはこんな感じです。○該当IPがアクセスしているURLを検索するselect  request_ip, url from  ELBログの保存先 where  elb_name = ‘たくさんあると絞ってあげたほうがわかりやすいです’   AND  (regexp_like(request_ip, ‘111.111.111.111’)) limit 1000; こんな感じで○該当URLにアクセスしているIPを割り出す○該当URLにアクセスしているIPのカウント数○該当日時にアクセスしてきたIPやURLを割り出すなどが検索可能です。更に応用としてはUAでGoogleBotがクローリングしているURLを割り出したり(もちろんUAは偽装できてしまうので正確とは言えないですが・・・参考までに)日毎のGoogleBotの件数を見てみたり(↓)SELECT substr(request_timestamp,      1,     10) AS ymd,      count(*) AS cnt FROM ELBログの保存先 WHERE elb_name = ‘たくさんあると絞ってあげたほうがわかりやすいです’     AND user_agent LIKE '%Googlebot%' GROUP BY substr(request_timestamp, 1,10) ORDER BY ymd; あとはprocessing_time(何種類かあります)でorder by descすれば処理が重いページもわかったりします。便利ですね!!皆さんもELBのログをS3に保存して素晴らしいAthenaライフをお送りください!!
  • テクログ

    AWS CLI等でEC2に紐づいているパブリックIPアドレスがEIPか否かを見分ける

    नमस्ते! आप कैसे(कैसी) हैं?ナマステー!こんにちは。インフラ担当のまつやです。前日までに新たに起動したEC2があり、それが監視が必要なものであるならば自動でZabbixに登録するスクリプトを毎日動かしています。aws cli等でインスタンスの情報を取得して以下の情報を抜き出します。Reservations[].Instances[].NetworkInterfaces[].Association[].PublicIp これでパブリックIPの付与されたインスタンスをピックアップし、別条件でZabbixのホストに登録するか否かを判定し、Zabbixに登録がなければ登録しています。しかし最近、自動でZabbixにホスト登録されたはずのEC2が見つからないという事象が発生しました。上記で抜き出したパブリックIPが見つからない・・・どのEC2にも紐づいていないし、EIPを検索しても見つかりません。色々調べた結果、どうやらAuto ScalingグループのEC2インスタンスがスケールアウトしてローンチする際、予約しておいたEIPに紐づけされる前に、動的に割り当てられるパブリックIPアドレスを検知してZabbixのホストとして登録してしまっていることが分かりました。その後予約してあったEIPが紐づけられたために、一時的に割り当てられていたパブリックIPは解放されたのでどこを探しても見つからないわけです。ということは、動的に割り当てられるパブリックIPと、EIPを区別することができればZabbixに登録するか否かを判定することができそうです。aws ec2 describe-instancesでインスタンスリストを取得して探していると、それらしいものがありました。Reservations[].Instances[].NetworkInterfaces[].Association[].IpOwnerId {   "Reservations": [     {       "Groups": [],       "Instances": [         {    中略               "NetworkInterfaces": [                          {                                 "Association": {                                        "IpOwnerId": "XXXXXXXXXXXX",                                        "PublicDnsName": "ec2-XXX-XXX-XX-XXXX.ap-northeast-1.compute.amazonaws.com",                                        "PublicIp": "XXX.XXX.XXX.XXX"                                 }, IPの所有者のIDですね。この値がAWSアカウントのIDになっていればEIP,amazonになっていれば動的に割り当てられるパブリックIPということになります。これによって、IpOwnerIdがamazonである場合はZabbixホストに登録しないという処理をスクリプトに入れることができました。それではまた!फिर मिलेंगे!