技術雑記帳兼日記帳

AWS、Python、Terraformの使い方をコッソリ

AWS Certified Solutions Architect - Professional その2

今回はエンドポイントについて。 2種類のエンドポイントの違いなどがはっきりとわかるようにならないと サービス設計や利用で提供でつまづきそうなので、まとめみました。

ゲートウェイVPCエンドポイント

  • S3とDynamo DBで使える。
  • 料金が発生しない。
  • ルートテーブルの設定が必要
  • PryoxyサーバのようなEC2が必要(オンプレなどから直接アクセスできない)
  • 高可用性は設計側で検討する必要がある。

    インターフェイス VPC エンドポイント (AWS PrivateLink)

  • 様々なAWSサービスで使える。
  • 料金が発生する。
  • AZは設定時に追加できるので高可用性は担保してもらえる。
  • サブネットにENIが配置される。
  • Proxy不要
  • Lambda+VPCを使う場合はインタフェイスエンドポイントがあるとセキュアにサービスが使える

    まだまだ書くべきことはあるが、掻い摘んで理解した内容です。
    特に最後のPrivate LinkでLambdaを使うケースは実践でやって、重要性と必要性は理解できました。
    また、お金は大事です。

    まとめ

    さらっと始めたが、傾向とし、Professionalレベルになると、単独アカウントや単独のサービスの提供で行うことより組織としてAWSサービスを提供・利用するための管理について重点が置かれているように感じる。
    Professionalなので当然といえば当然かなぁとは思いますが。
    サービス間連携が理解できないと設計も難しいですしね。

下記に公式のURLを貼り付けておきます。

docs.aws.amazon.com

docs.aws.amazon.com

AWS Certified Solutions Architect - Professional その1

今回は勉強のためにAssumeRoleを試してみました。

AWSアカウント(A)からのアカウント(B)に対して操作』を許可するケースを簡単にまとめてみました。

B側操作

・ロール作成で、AWSアカウントを選択し、許可したいAWSアカウントID(A)を指定する。
・アカウントIDを指定したら、許可したい操作をポリシー単位で選択する。

A側操作(今回はコンソール)

・下記のコマンドを実行する

aws sts assume-role \
--role-arn "arn:aws:iam::<B側のアカウントID>:role/<ロール名>" 
--role-session-name <sessionName>

こうすると、AccessKeyId、SecretAccessKey、SessionTokenが取得できるのでexportする。

export AWS_ACCESS_KEY_ID =  <assume-roleで取得したAccessKeyId>
export AWS_SECRET_ACCESS_KEY = <assume-roleで取得したSecretAccessKey>
export AWS_SESSION_TOKEN = <assume-roleで取得したSessionToken>

これでB側のアカウントの操作が可能になる。

まとめ

最小特権の原則(PoLP)に沿わないと簡単に他アカウントのAWSリソースをぶち壊す可能性を秘めている。

Amazon S3 and boto3

忘れそうなのでメモついでにAWS CLIPythonでS3の使い方をまとめる。

docs.aws.amazon.com

S3の設定

aws s3 mb s3://バケット名
aws s3 sync images s3://バケット名/images/
aws s3 rm  s3://バケット名/ --include 'img*.jpg' --recursive --dryrun
でためして
aws s3 rm  s3://バケット名/ --include 'img*.jpg' --recursive
aws s3 ls s3://バケット名/images/

バケットを作るときに以下のNGが出た場合はAWS内で重複しているのでバケット名を替える必要がある

make_bucket failed: s3://imagebucket An error occurred (BucketAlreadyExists) when calling the CreateBucket operation: The requested bucket name is not available. The bucket namespace is shared by all users of the system. Please select a different name and try again.

「/」のつけ忘れでフォルダ、ファイルが混同するので注意が必要

最後にpythonでimg-catの中身をS3に転送して結果をCSVに出力するプログラムを書いてみた。

import boto3, pathlib 

s3 = boto3.client('s3')

files = pathlib.Path('img-cat/').glob('*.jpg')
for file in files:
    s3.upload_file('img-cat/'+ file.name, 'バケット名', 'img-cat/' + file.name)

objs = s3.list_objects_v2(Bucket='バケット名')
csv = '{},{}\n'.format('file', 'size')

for o in objs.get('Contents'):
    key = o.get('Key')
    size = o.get('Size')
    if key[-4:]=='.jpg':
        csv += '{},{}\n'.format(key, int(size))

f = open('uplist.csv', 'w')
f.write(csv)

AWS CLIとboto3を使いこなして幸せになりたいな。

AWS 認定 クラウドプラクティショナー受験記録

はじめに

5月8日にAWS 認定 クラウドラクティショナーを受験してきました。  

試験までの流れ

1.試験前

きっかけは実務でAWSも触ってるし、説明するときの根拠付もあったほうがいいかなぁと思って以下の本を購入して勉強を開始しました。
勉強方法は「古典的なノートに書き写す」+「音読する」でやってました。

1冊目:

2冊目:

1冊目はAWSとは?クラウドとは?AWSのサービスや監視、課金方式や課金の確認方法などの幅広い範囲で図解付きで丁寧に説明してくれていたので良書でした。
最初は読むだけ読んで2冊目の問題集を説いていました。
問題集の正解と誤りの訂正箇所をセブンイレブンで売っているA5ノートにまとめていました。
それも飽きてきて、1冊目の本の内容をノートにまとめていました。
ちなみに2冊目はKndle Unlimitedに入っているおかげで読み放題。

期間的には平日は読むくらいに留めていましたが、GW中にガッツリ勉強してました。

2.試験当日

一夜漬け+当日もギリギリまで勉強していざ試験会場へ。
10年ぶりくらいに試験に行ったので謎に緊張しました。

試験会場では、ナイスミドルの案内で身分証明書(マイナンバーカード+クレジットカード)を提示して同意書に記入しました。
そのあと顔写真を撮って、身分証明書(マイナンバーカード)のみをポケットにいれて、スマホの電源を切って時計を外して、ロッカーに預けました。

ちなみに身分証明書は片方の名前がローマ字で書いてなくても大丈夫でした。

3.試験開始

試験会場に入る前にメモ用のボードとペンを借りました。
座席に案内されて身分証明書は机の上においておくよう指示され、備え付けのPCを設定してもらって試験を実施します。
そして、いざテスト開始ですが特に書くことはなく単純に問題を解くだけでした。
なお、騒音対策でイヤーマフが備え付けられていました。

4.試験終了

RTAしたわけではないですが、1時間以上の持ち時間を余らせて終わらせました。
本に書いていないサービスが頻繁に出てきたので、落ちたかなぁと思っていたらノーモーションで「合格」の文字が出てきて焦りつつ、席に備え付けらているボタンを押して退出。
AWSの試験はPCでは合格とでますが、結果レポートには審査は後日と記載されます。

後日とありましたが、実際は3時間位で結果レポートをもらえました。
また、特典などもすぐに利用できました。
PDF 証明書も貰えます。

5.振り返り

ギリギリまで勉強していましたが、本の内容をまとめるのは6割くらいしかできてませんでした。
次の上位を取るにあたっては、ページ数から時間を見積もってやるのがいいですね。(当たり前笑)

結果的に合格できたので良かったです。

次はデベロッパーかなぁ

python Amazon Rekognition Detect Text

はじめに

今回は画像からテキストを分析するDetect Textを使ってみる。

準備

下記のプログラムを用意する。

  • detect_text.py.py
from PIL import Image, ImageDraw, ImageFont
import boto3, sys, json, os, traceback

#画像の分析結果を返す
def detect_text(image):
    client=boto3.client('rekognition')
    #写真を読み出して、Byte変換してdetect_faces送信
    file = open(image,'rb')
    response = client.detect_text(Image={'Bytes':file.read()})

    return response

#BoundingBoxを設定する
def set_bounding_box(image, bounding_box_data):
    #画像の高さと幅を取得
    imgWidth, imgHeight = image.size
    draw = ImageDraw.Draw(image)

    #位置を算出
    left = bounding_box_data['Left'] * imgWidth
    top = bounding_box_data['Top'] * imgHeight
    width = bounding_box_data['Width'] * imgWidth
    height = bounding_box_data['Height'] * imgHeight

    points = (
            (left,top),
            (left + width, top),
            (left + width, top + height),
            (left , top + height),
            (left, top)

        )

    draw.line(points, fill='#00d400', width=2)
    
    return

#指定箇所に文字列を設定して返す
def set_bounding_box_text(image, text, bounding_box_data):

    #画像の高さと幅を取得
    imgWidth, imgHeight = image.size
    draw = ImageDraw.Draw(image)

    #位置を算出
    left = bounding_box_data['Left'] * imgWidth
    top = bounding_box_data['Top'] * imgHeight
    width = bounding_box_data['Width'] * imgWidth
    height = bounding_box_data['Height'] * imgHeight

    draw = ImageDraw.Draw(image)
    #フォントの設定
    font_ttf = "/usr/share/fonts/truetype/fonts-japanese-gothic.ttf"
    draw.font = ImageFont.truetype(font_ttf, 25)

    color = (0,255,0)
    pos = (left, top)
    #文字の設定
    draw.text(pos, text, color)
    return

if __name__ == '__main__':
    if len(sys.argv) != 3:
        exit()
    
    in_file_name = sys.argv[1]
    out_file_name = sys.argv[2]

    try:
        #画像分析
        #jsonが無ければ分析あれば使う
        json_file_name = in_file_name + '.json'
        if (os.path.exists(json_file_name) == True):
            file = open(json_file_name, 'r')
            response = file.read()
            response = json.loads(response)
        else:
            response = detect_text(in_file_name)
            file = open(json_file_name, 'w')
            file.write(json.dumps(response))

        #分析元の画像を読み込み
        image = Image.open(in_file_name)
        
        #画像に分析結果の設定
        cnt = 1
        for text in response['TextDetections']:
            #boundingboxを設定
            set_bounding_box(image, text['Geometry']['BoundingBox'])
            set_bounding_box_text(image, str(cnt), text['Geometry']['BoundingBox'])
            print(str(cnt) + ' is ' + 'Type:' + text['Type'] + ' [' + text['DetectedText'] + ']')
            cnt = cnt + 1

        #結果の出力
        image.save(out_file_name)


    except Exception as e:
        print(e)
        print(traceback.format_exc())

実行方法

python detect_text.py 分析したいファイル.jpg 出力したいファイル名.jpg
  • 実行結果
    今回は何枚か画像を貼り付けてみる
    数字がかぶって見づらいけど画像に数字を埋め込んで、ターミナルに数字と文字タイプ、文字列を表示するようにした。


1個めはIRON MAIDENのアルバムジャケット

f:id:halhalhal1:20210503101313j:plain

1 is Type:LINE [IRAN MAAIDEN]
2 is Type:LINE [Kllers]
3 is Type:WORD [IRAN]
4 is Type:WORD [MAAIDEN]
5 is Type:WORD [Kllers]

2個めはNIRVANAのアルバムジャケット
f:id:halhalhal1:20210503101603j:plain

1 is Type:LINE [NIRVANA]
2 is Type:LINE ["BLEACH'']
3 is Type:WORD [NIRVANA]
4 is Type:WORD ["BLEACH'']

3個めはネコは見ている系の寄せ集め
f:id:halhalhal1:20210503101825j:plain

1 is Type:LINE [7IL71]
2 is Type:LINE [HOMLSI]
:
48 is Type:WORD [LT ]
49 is Type:WORD [t]
50 is Type:WORD [OHOEN'OCFLS]
51 is Type:WORD [K]

まとめ

ラストが若干狂気じみているが、これはdetect textが日本語に対応していないからっぽい。
崩し文字は、そのままそれっぽく見えるアルファベットに変換してくれる。
NIRVANA」や「BLEACH」はさすがの検出力。



python Amazon Rekognition Recognize Celebrities

はじめに

今回は有名人の顔を分析するRecognize Celebritiesを使ってみる。

準備

下記のプログラムを用意する。

  • recognize_celebrities.py
import boto3, sys, json, cv2, math, os, traceback

#recognize_celebritiesで顔の分析結果を返す
def recognize_celebrities(in_image_file):
    client=boto3.client('rekognition')
    #写真を読み出して、Byte変換してdetect_faces送信
    file = open(in_image_file,'rb')
    response = client.recognize_celebrities(Image={'Bytes':file.read()})

    return response

#Bounding Boxを設定して返す
def set_bounding_box(image_file, bounding_box_data):
    #画像の高さと幅を取得
    imgHeight, imgWidth = image_file.shape[:2]

    #位置を算出
    left = math.ceil(bounding_box_data['Left'] * imgWidth)
    top = math.ceil(bounding_box_data['Top'] * imgHeight)
    width = math.ceil(bounding_box_data['Width'] * imgWidth)
    height = math.ceil(bounding_box_data['Height'] * imgHeight)

    image_file = cv2.rectangle(image_file
                            , (left, top)
                            , (width+left, height+top)
                            , (0,255,0)
                            , 2)

    return image_file

#Bounding Boxの左下に名前を設定して返す
def set_celebrity_name(image_file, celebrity_name, boundingBox):
    #画像の高さと幅を取得
    imgHeight, imgWidth = image_file.shape[:2]

    left = math.ceil(boundingBox['Left'] * imgWidth)
    top = math.ceil(boundingBox['Top'] * imgHeight)
    height = math.ceil(boundingBox['Height'] * imgHeight)

    image_file = cv2.putText(image_file
                            , celebrity_name
                            , (left, height+top)
                            , cv2.FONT_HERSHEY_PLAIN
                            , 2
                            , (255, 255, 255)
                            , 2
                            , cv2.LINE_AA)

    return image_file


if __name__ == '__main__':
    if len(sys.argv) != 3:
        exit()
    
    in_file_name = sys.argv[1]
    out_file_name = sys.argv[2]

    try:
        #顔分析
        #jsonが無ければ分析あれば使う
        json_file_name = in_file_name + '.json'
        if (os.path.exists(json_file_name) == True):
            file = open(json_file_name, 'r')
            response = file.read()
            response = json.loads(response)
        else:
            response = recognize_celebrities(in_file_name)
            file = open(json_file_name, 'w')
            file.write(json.dumps(response))

        #分析元の画像を読み込み
        origin_image = cv2.imread(in_file_name)
        after_image = origin_image.copy()
        
        #画像に分析結果の設定
        for celebrity in response['CelebrityFaces']:
            after_image = set_bounding_box(after_image, celebrity['Face']['BoundingBox'])
            after_image = set_celebrity_name(after_image, celebrity['Name'], celebrity['Face']['BoundingBox'])
            
        #結果の出力
        if after_image is not None:
            cv2.imwrite(out_file_name, after_image)


    except Exception as e:
        print(e)
        print(traceback.format_exc())

実行方法

python recognize_celebrities.py 分析したいファイル.jpg 出力したいファイル名.jpg
  • 実行結果 f:id:halhalhal1:20210426211733j:plain

BoundingBoxを設定して、名前を設定してみた。
動作はほぼ共通化していて、流用が簡単にできるのでAmazonAPIが共通的に作られているかがわかった。
やっぱ、似たようなAPIは似たような構造になるんだよな、普通。


まとめ

今までの集大成で一気に書き上げることができた。
text設定とかはもうちょっとうまくメソッド化できそうだなぁ。