Pythonを一行一行見ていく(Pythonでトークン取得・パラメータストア登録/更新・デプロイ後のテスト失敗〜成功まで

2020/10/19に公開

どうも、こんにちは。お元気ですか?

ネットで昔の動画が配信されていると、
懐かしさで観てしまいますよね。
懐かしいというのは、それだけでエンターテイメントになるんですね。

以前はServerless FrameworkやPythonについてなど
有識者の方々のを見たり、聞いたりして、教わりながら
色々と新しいことを体験しながら覚えていったので
それらの知見? 感想? をここに残しておきたいと思います。

まずは、handler.pyを一行一行、見ていこうと思います

こういう記述がありました、どういう中身なのでしょう。
Python(パイソン)と聞くと、ムキムキの黒人ボクサーを思い出してしまいますよね。
あの人って、海外版だとバルログっていう名前になってるんですよね。

handler.py
from util import logging_decorator, build_response_decorator, get_logger

import app

logger = get_logger('INFO')

@logging_decorator
def xxxx_handler(event, context):
    return app._token(event)

from util import logging_decorator, build_response_decorator, get_logger

import app

  • これは、下記に記述されている内容です。同階層にあります

logger = get_logger('INFO')

@logging_decorator

def xxxx_handler(event, context):

  • defとは 英語のdefine(定義する)の略からきている そうです(Defaultと間違えていました)
  • xxxx_handlerと、定義された関数の中で、event, contextという引数を呼び出しています

return app._token(event)


続いて、app.pyを一行一行、見ていこうと思います

こういう記述がありました。ServerlessFrameworkに使うPythonです。
あと結構伏せ字(xxx)にしたので、変数の流れが間違っていたらすみません。
処理内容は、指定されたIDとパスワードを使用し、トークン情報(json形式)を指定されたところから取得して、 トークン情報のみを抽出し、パラメータストアに登録する というものです。

app.py
import json
import boto3
import requests
import os

def _token(event):
    
    try:
        # ===================================================================
        # トークン取得処理 
        # ===================================================================
        
        # boto3を使い、パラメータストアを利用する
        client = boto3.client('ssm')

        # シークレットキー取得
        # get_parameterでパラメータの値を取得
        response_get = client.get_parameter(
            Name = '/xxx/xxxx/xxxx',
            WithDecryption = True
        )
        client_secret_get = response_get['Parameter']['Value']

        # トークン取得に必要なキー一覧
        CLIENT_SECRET = xxxxx_xxxx_get
        CLIENT_ID = os.environ['XXXX']
        XXXX_URL = "https://xxxxx/xxxx"

        # あの夏、ボクらはキーを手にしたんだ
        xxxx_xxxx_key = {
            'xxxx_secret': XXXX_SECRET,
            'xxxx_id': XXXX_ID,
        }

        # トークン情報にアクセスし必要な情報を入力
        response_xxxx = requests.post(XXXX_URL, data=xxxx_xxxx_key)

        # トークン情報を出力
        # 結果はJSON形式なのでデコードする
        xxxx_data = json.loads(response_xxxx.text)

        # トークン情報の中からアクセストークンの値のみ抽出
        xxxx_xxxx_data = xxxx_data.get('access_token')

        # ===================================================================
        # 上で取得したトークン情報を - AWS Systems Manager - パラメータストアに送る
        # ===================================================================

        # put_parameterでパラメータの値を更新
        response_put = client.put_parameter(
            Name = '/xxxx/xxxx',
            Value = xxxx_xxxx_xxxx,
            Type = 'SecureString',
            Overwrite = True
        )

import json

import boto3

import requests

import os

def _token(event):

try:

# エラーハンドリング
    except Exception as error:
        data = {'request': event}
        logger.exception(error, extra=dict(data))

        return_params = {
            'message': 'エラーが発生しました。もう一度操作を実行してください。 {}'.format(str(error))
        }
        return {
            'statusCode': 500,
            'body': return_params
        }

client = boto3.client('ssm')

response_get = client.get_parameter(

  • まずは事前にパラメーターストア画面に行って、あらかじめ頂いているキーを登録してきました
  • ↓↓↓↓ここのオレンジのところですね

image.png

  • こういう画面で作成していきます(名前はわかりやすく、説明もわかりやすく、標準で安全な文字列でキーを値の欄に書き込みました)

image.png

  • その後、登録したキー(JIjlksjdfaijklaIJ+IJ...こんな感じの文字列)をget_parameter関数で取ってきます

Name = '/xxx/xxxx/xxxx',

  • 登録した名前をここに書きます
  • ここに / が書いてあるのは、名前にあえて / を入れて、他に登録したキーなどと被らず、かつ、このキーはどこに所属しているものかを階層という表記にして、わかりやすくしています

WithDecryption = True

)

  • カッコ閉じ

client_secret_get = response_get['Parameter']['Value']

CLIENT_SECRET = xxxxx_xxxx_get

  • ここで、上で取得した、シークレットキーを CLIENT_SECRET という変数にします(文字なのに

CLIENT_ID = os.environ['XXXX']

XXXX_URL = "https://xxxxx/xxxx"

  • トークンのある場所のURLを XXXX_URL という変数に入れました

xxxx_xxxx_key = {

         'xxxx_secret': XXXX_SECRET,
         'xxxx_id': XXXX_ID,
  • ここではリストの辞書型を使い、キーをまとめて xxxx_xxxx_key という変数に入れます
  • トークンを取得するために必要な、シークレットキーとIDを同じ場所に記述してはセキュリティ上よろしくない(ハードコーディングになる:別の場所に分けて書いた方が良い処理や値をソースコードの中に直接書いちゃうことだよ)ということで、シークレットキーはパラメータストアに、IDはLambdaの環境変数に分けて登録したので、それらを取得する記述が必要になっています

}

response_xxxx = requests.post(XXXX_URL, data=xxxx_xxxx_key)

xxxx_data = json.loads(response_xxxx.text)

xxxx_xxxx_data = xxxx_data.get('access_token')

response_put = client.put_parameter(

  • 上の方でgetをした内容を今度はput(置く、貼る)をします
  • 仕組みとしてはget_parameterと同じですね

Name = '/xxxx/xxxx',

  • putしたいパラメータストアの名前です(/が入っていますが、URLではなくてこちらで決めたネーミングルールです)

Value = xxxx_xxxx_xxxx,

  • わかりやすい説明をここで書きます

Type = 'SecureString',

  • ここが面白くて String だとそのままの文字が送られますが、SecureString にすると ***** となります
  • セキュリティですね

image.png

Overwrite = True

  • 今回は週一でトークンを書き直す処理を行っているので、上書きOKとしています

)


終わりに 今回も長かった!

本ページ内のリンクで引用、参照させていただいた、
公式ドキュメントや記事の筆者にお礼申し上げます。ありがとうございます。

さて、この段階に来て、次にこんなことも起こりました。
何度やってもデプロイ後、Lambda画面でのテストに失敗した んです!

なぜLambda画面でのテストに失敗したのか、それは…

Lambda(つまりserverless.yml)で設定していたPythonのバージョンは3.8だったのですが、
ローカルで編集していたときのPython環境は3.7だったんです。
てっきりデプロイする(ローカルから離れる)タイミングで最新に切り替わると思っていたのですが、そうではなかった。
作業をしているローカル環境のPythonのバージョンを3.8にしてデプロイしたら正常に動きました。
みなさまもお気をつけくださいませ。

Discussion