km_output

お勉強と趣味のアウトプット

【AWS】CloudFormationテンプレートでIAM Roleを作成したときの学び

最近はCloudFormationテンプレートを検証する機会が多い。

実現したいこと

  • CloudFormationテンプレートを使ってIAM Roleを新規作成したい。

IAM Role自体は新規作成したいが、

IAM Roleに紐づけるポリシーは既存+新規作成の2種類をつけたい。

解決方法、結論

  • IAM Roleを新規作成するときのCloudFormationテンプレートの書き方
テンプレート内での論理ロール名:
    Type: AWS::IAM::Role
    Properties:
      RoleName: 新規作成したいロール名
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Effect: Allow
            Principal:
              Service:
                - lambda.amazonaws.com ※今回はLambdaにアタッチするロールだったのでLambdaを指定。
            Action:
              - sts:AssumeRole
        Path: /
  • 既存のポリシーを新規作成したIAM Roleにつける

下記リンク参考。

既存の IAM 管理ポリシーを新規の IAM ロールに追加する

ManagedPolicyArns:
  - arn:aws:iam::XXXXXXXXXXX:policy/ポリシー1
  - arn:aws:iam::XXXXXXXXXXX:policy/ポリシー2

ARN書くだけなので楽ちん。

  • 新規作成したポリシーを新規作成したIAM Roleにつける

今回はインラインポリシーを新規作成。下記のようになる。

Policies:
        - PolicyName: つけたいポリシー名
          PolicyDocument:
            Version: '2012-10-17'
            Statement:
              - Effect: Allow
                Action:
                  - s3:ListBucket
                  - s3:GetBucketLocation
                Resource: 
                  - arn:aws:s3:::バケット名/
                  - arn:aws:s3:::バケット名/*

全体像は以下のような感じ。

テンプレート内での論理ロール名:
    Type: AWS::IAM::Role
    Properties:
      RoleName: 新規作成したいロール名
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Effect: Allow
            Principal:
              Service:
                - lambda.amazonaws.com ※今回はLambdaにアタッチするロールだったのでLambdaを指定。
            Action:
              - sts:AssumeRole
      Path: /
      ManagedPolicyArns:
       - arn:aws:iam::XXXXXXXXXXX:policy/既存のポリシー名1
       - arn:aws:iam::XXXXXXXXXXX:policy/既存のポリシー名2
      Policies:
        - PolicyName: つけたいポリシー名
          PolicyDocument:
            Version: '2012-10-17'
            Statement:
              - Effect: Allow
                Action:
                  - s3:ListBucket
                  - s3:GetBucketLocation
                Resource: 
                  - arn:aws:s3:::バケット名/
                  - arn:aws:s3:::バケット名/*

公式ドキュメントは以下。今後も何かあったら見よう・・・。

AWS::IAM::Role

【AWS】CloudFormationテンプレート内に日本語(マルチバイト文字)が使えなくて英語力を試された話

英語表現を知っていると捗るんだろうなあ。

実現したいこと

  • CloudFormationテンプレートを使ってLambda関数を新規作成したい。

もともとCloudFormationテンプレートで構築した環境に、Lambda関数を新規作成して連携させたい。

ハマったところ、エラー内容

CloudFormation>変更スタック作成画面にてS3にアップロードしたテンプレートのURLを貼りつけ、「次へ」ボタン押すとエラーになった。

今回お目にかかったのは以下のエラー。

Cannot parse template as YAML : special characters are not allowed

解決方法、結論

Lambda関数のソースコード内のコメントに日本語(=マルチバイト文字)を含めていたのでエラーが出ていた。

日本語を全て英語に直したところ、エラーもなくすんなり変更セットの作成完了。

エンジニアなら誰しも日本語を英語で言い換える場面があると思うのだが、こういうとき「どのレベルの英語を採用すべきか」で悩む。

万人が分かるように易しい、かつこちらの意図が伝わるような英語表現で書かないといけないからだ。

(文法よりも伝わりやすさ重視なので造語ちっくな英語もよく見かける)

今回は「Lambda関数の中で特定の条件に合致した場合、別のLambda関数を非同期処理で呼び出す部分」の説明に少し悩んだ。

該当箇所は以下。

# Lambda asynchronous call
    lambda_asynchronous_call = os.environ['lambda_asynchronous_call']
    response = boto3.client('lambda').invoke(
      FunctionName=lambda_asynchronous_call,
      InvocationType='Event',
      Payload=data
    ) 

これだとコメントの意味ないよなあ、と思いつつも、他になんて書けばいいか分からなかった。

コメントなくしたらなくしたで、この処理注目されずにスルーされるのが怖い。

ソースレビューしてもらえる環境で働けるように精進せねば。

【Ansible】ansible-playbook実行時に--checkを付けたら当然エラーになる部分がある話

ハマってはいけないところでハマった懺悔録。Ansible編。

実現したいこと

  • ansible-playbookコマンドを使ってサーバを新規構築したい。

サーバを新規に払い出すとき、現場でAnsibleを使っていた。

手順書もすでに作成されていたので、手順に従って設定ファイルを用意し、あとはコマンドを打つだけ!な状態。

ハマったところ、エラー内容

ansible-playbookコマンド末尾に --check をつけてDryRunしたらエラーになった。

正常終了していなかったので、該当部分を見ていたが原因が分からず。

--syntax-check で文法を見ても特にエラーなし。

yamlファイル自体は以前も使用されていたもののはず、どうして・・・となった。

解決方法、結論

エラーになった部分は --check をつけて流した際には当然エラーになる処理だった。

該当部分は以下の処理。

add_host

これはhostを動的に追加する処理のよう。

add_host – Add a host (and alternatively a group) to the ansible-playbook in-memory inventory — Ansible Documentation

今回のようにplaybook実行時には存在しないhostを追加したい場合に(つまり動的追加?)使うっぽい。

--check つけてコマンドを流すとDryRunとなるため実際にはhostが作られておらず、「追加できるhostがないよ」というエラーになる模様。。。

上記以外にはエラーがないことを確認してから --check を外して実行すると、無事に新規構築が完了。

手順書にはDryRun時の挙動が特に書いていなかったので、これは備忘のためにも書いておかねば。

【AWS】LambdaエラーログをCloudWatchインサイトから拾うときの検索クエリに気を付ける反省文

ハマってはいけないところでハマった懺悔録。

実現したいこと

  • Lambdaのメトリクスを見ていてエラーが数件出ていたので、該当エラーをCloudWatchインサイトで検索したい。

そもそもエラー時に通知を飛ばすようSNSなりで設定していればこのような目には遭わないと思われるのだが、

大きな影響があるLambdaではなかったため目視チェック&その都度検索をしていた経緯がある。

ハマったところ、エラー内容

今回はおそらくタイムアウトであるという目星がついていたため、いきなりタイムアウトのエラーログを探す。

Lambdaがタイムアウトすると以下の文字列を含むログが出る。

Task timed out after 900.09 seconds

※Lambdaの設定値にもよるが、今回はタイムアウト15分=900秒なので上記のエラー。

これをCloudWatchインサイトで検索してみた。

前回はデフォルトの検索クエリに以下のフィルターをつけて実行してみると検索できた。

| filter @message like /(?i)(timed)/

あれ、今回は引っかからない。時間帯もあっているはずなのに。

解決方法

変なフィルターがかかっていた。。。

filter @type = "REPORT"

これ、Lambda 関数画面の [ モニタリング ] > CloudWatch Logs Insights> [ CloudWatch Logs インサイトで表示 ] を押してインサイトに遷移するとついてる。

CloudWatch Logs インサイトを素直に開いたときとクエリ違ってたんだなあ(当たり前)としみじみ。こんなくだらないことで30分ハマってしまった。

結論として、CloudWatch>インサイトを開いたときのデフォルトクエリに

| filter @message like /(?i)(timed)/

つければ大丈夫だった。

クエリをよ~~~く確認しよう・・・

【AWS】Athenaのパーティション追加とWorkGroup指定で地味にハマった話

実現したいこと

実際の構成はCloudWatchルール→Lambda

Lambda内で指定したAthenaテーブルにパーティション追加する処理を書く。

ハマったところ、エラー内容

  • Athenaのパーティション追加しようとして MSCK REPAIR TABLE ~ を流したらエラー。

MSCK REPAIR TABLE ~ を使う場合は、対象S3パス以下全てにパーティションが設定されていないとエラーになる模様。

今回は日付ごとに2019/11/01・・・というような分け方をしていて、11月以降のみパーティション追加していきたかった。

対象S3パスを ~2019/11/ にすれば上記SQLで済むが、12月以降またテーブル作るのかいって話になるので、S3パスは変更したくない。

  • 上記エラー解決後、SQL実行時にデフォルトのWorkGroupを使っている。他のWorkGroupを指定したい。

何も指定していないのでデフォルトの primary というWorkGroupが選択されるのだが、環境の制約で primary は無効に設定されているためエラー。

解決方法

  • Athenaのパーティション追加時に ALTER TABLE テーブル名 ADD IF NOT EXISTS PARTITION ~ を使う

ちまちま日付ごとのパーティションを追加することにした。

`ALTER TABLE テーブル名 ADD IF NOT EXISTS PARTITION (year='2019',month='11',day='01') location 's3://バケット名/パス/~/2019/11/01/'

対象S3パスの場所がALBログの出力場所で、ALBログが出力される時間が読めないためCloudWatchルールは毎時1回起動する設定にした。

他にうまい方法ないのかなーと思いつつ(・_・;)

  • Lambda内で athena.start_query_execution するときに WorkGroup を指定する

ここに詳細が書いてある。

StartQueryExecution - Amazon Athena

実際は以下のような感じ。

athena.start_query_execution(
    QueryString= sql , # Lambda関数内で組み立てたSQL文を変数sqlに代入してある。 
    QueryExecutionContext={
      'Database': DB名
    },
    WorkGroup= workgroup, # 変数workgroupに実際のWorkGroup名を入れる仕様にした。
    ResultConfiguration={
      'OutputLocation': 's3://s3バケット名/パス/'
    }
  )

Python3 エンジニア認定基礎試験に受かった話・続

Python3 エンジニア認定基礎試験の合格体験記を書いた。

以前、Python3 エンジニア認定基礎試験に合格した。

合格体験記を書くと限定グッズがもらえるキャンペーンをやっていたのだが、

しばらく放置していた。(忘れていた。)

www.pythonic-exam.com

ある日ひょっこり合格体験記を覗いてみると、

限定グッズにポロシャツが追加されているではないか。

www.pythonic-exam.com

欲しい。

そんな経緯で合格体験記を書いてメールで送付した。

ポロシャツが届いた!!

合格体験記の受理~掲載後、1ヵ月かからないくらいで自宅に届いた。

f:id:km_tech:20191117130319j:plain
Python検定合格記念ポロシャツ_20191117

写真はポロシャツの裏。こういう文字入り服は持っていなかったので新鮮。

前から見ると普通の紺色ポロシャツとして使えるから、カーティガンと合わせて夏に重宝しそう。

数量限定なので合格している方はお早めに。

CloudWatch Logsに出力したJSON形式のログにメトリクスフィルターをかけたい。

実現したいこと

CloudWatch LogsのログストリームhogehogeにJSON形式のログを出力した。

このログストリームにメトリクスフィルターをかけ、フィールドhogeFieldの値が一定値以上のログだけ抽出したい。

ハマったところ

数値の絞り込みがうまくいかない。。。

試したこと

以下の公式ユーザーガイドを見ながらいろいろなフィルターパターンを試す。

ログイベントの語句の一致

{ $.hogeField >= 1 }

⇒エラーにはならないが、サンプルログに該当データがあっても一致なしという結果。うまく動かない。

{ $.hogeField = 1 }

⇒エラーにならず、サンプルログの該当データ件数と一致のためOK

{ $.hogeField != 1 }

⇒エラーにならず、サンプルログの該当データ件数と一致のためOK

解決!

上記ユーザガイドライン内に書いてある。

JSONの場合、メトリクスフィルターは{ SELECTOR EQUALITY_OPERATOR STRING }の形式で書く決まりになっていて、

EQUALITY_OPERATORは = または != だと・・・!?

数値比較じゃないというオチ。JSONだもの。

というわけで、メトリクスフィルターでの絞り込みは諦めて

数値しかこない→全て拾いたいがために、 { $.hogehoge != a } で全通過させたのちにLambdaでいじり倒すことになりそう。