<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>クラウドインフラ on AIによる技術記事 備忘録</title><link>https://ai.hack-le.com/tags/%E3%82%AF%E3%83%A9%E3%82%A6%E3%83%89%E3%82%A4%E3%83%B3%E3%83%95%E3%83%A9/</link><description>Recent content in クラウドインフラ on AIによる技術記事 備忘録</description><generator>Hugo -- gohugo.io</generator><language>ja</language><lastBuildDate>Mon, 02 Nov 2026 09:31:25 +0900</lastBuildDate><atom:link href="https://ai.hack-le.com/tags/%E3%82%AF%E3%83%A9%E3%82%A6%E3%83%89%E3%82%A4%E3%83%B3%E3%83%95%E3%83%A9/index.xml" rel="self" type="application/rss+xml"/><item><title>自宅サーバー公開におけるルーティング設計：Cloudflare TunnelとCaddyの役割分担</title><link>https://ai.hack-le.com/%E8%87%AA%E5%AE%85%E3%82%B5%E3%83%BC%E3%83%90%E3%83%BC%E5%85%AC%E9%96%8B%E3%81%AB%E3%81%8A%E3%81%91%E3%82%8B%E3%83%AB%E3%83%BC%E3%83%86%E3%82%A3%E3%83%B3%E3%82%B0%E8%A8%AD%E8%A8%88%EF%BC%9Acloudflare/</link><pubDate>Sun, 25 Oct 2026 22:30:33 +0900</pubDate><guid>https://ai.hack-le.com/%E8%87%AA%E5%AE%85%E3%82%B5%E3%83%BC%E3%83%90%E3%83%BC%E5%85%AC%E9%96%8B%E3%81%AB%E3%81%8A%E3%81%91%E3%82%8B%E3%83%AB%E3%83%BC%E3%83%86%E3%82%A3%E3%83%B3%E3%82%B0%E8%A8%AD%E8%A8%88%EF%BC%9Acloudflare/</guid><description>&lt;p&gt;自宅サーバーで複数のWebアプリケーションをホストする際、外部公開手段としての &lt;strong&gt;Cloudflare Tunnel（&lt;code&gt;cloudflared&lt;/code&gt;）&lt;/strong&gt; 、ローカル環境用のリバースプロキシとしての &lt;strong&gt;Caddy&lt;/strong&gt;、そしてLAN内の名前解決を担う &lt;strong&gt;AdGuard Home&lt;/strong&gt; などのDNSサーバーを併用する設計は広く利用されています。&lt;/p&gt;&#10;&lt;p&gt;この構成を検討する際によく生じる疑問が、「外部からのアクセスは Caddy を経由させるべきなのか、それとも &lt;code&gt;cloudflared&lt;/code&gt; から直接各アプリケーションのポートへ向けるべきなのか」というルーティングの設計判断です。結論から言えば、通信プロトコルとしてはいずれの経路も正常に成立します。両者の違いは正誤ではなく、&lt;strong&gt;システムの単純性を取るか、ローカル側での制御の一元化を取るか&lt;/strong&gt;という設計原則のトレードオフにあります。&lt;/p&gt;&#10;&lt;h2 id="物理配置とネットワーク境界の前提"&gt;物理配置とネットワーク境界の前提&#10;&lt;/h2&gt;&lt;p&gt;構成を整理する上での大前提として、各コンポーネントがネットワーク上のどこに配置されているかを正確に把握する必要があります。&lt;/p&gt;&#10;&lt;p&gt;外部からのトラフィックを受ける最初の接点は、インターネット上に分散配置された &lt;strong&gt;Cloudflare Edge&lt;/strong&gt; です。外部ユーザーはこのエッジサーバーに対して HTTPS アクセスを行います。一方、 &lt;strong&gt;&lt;code&gt;cloudflared&lt;/code&gt; の実体はインターネット上ではなく、自宅LAN内のサーバー上で動作するデーモン&lt;/strong&gt;です。このデーモンが自宅内から Cloudflare Edge に向けて外向き（アウトバウンド）の安全なトンネル接続を確立し、外部からの要求を自宅ネットワーク内部へ引き込みます。&lt;/p&gt;&#10;&lt;p&gt;したがって、通信の物理的な境界線は「インターネット上の Cloudflare Edge」と「自宅LAN内の &lt;code&gt;cloudflared&lt;/code&gt;」の間に引かれます。その上で、引き込んだトラフィックを LAN 内でどう分配するかが設計の分岐点となります。&lt;/p&gt;&#10;&lt;div class="mermaid"&gt;&#10;graph TD&#10;subgraph &amp;#34;インターネット (WAN)&amp;#34;&#10;User_Ext[&amp;#34;外部ユーザー&amp;#34;]&#10;CF_Edge[&amp;#34;Cloudflare Edge&amp;#34;]&#10;end&#10;subgraph &amp;#34;自宅LAN&amp;#34;&#10;Tunnel[&amp;#34;cloudflared&amp;#34;]&#10;User_Int[&amp;#34;LAN内クライアント&amp;#34;]&#10;AGH[&amp;#34;AdGuard Home(スプリットDNS)&amp;#34;]&#10;Caddy[&amp;#34;Caddy(リバースプロキシ)&amp;#34;]&#10;App[&amp;#34;Webアプリケーション群&amp;#34;]&#10;end&#10;User_Ext --&amp;gt; CF_Edge&#10;CF_Edge Tunnel&#10;User_Int -.-&amp;gt; AGH&#10;AGH -.-&amp;gt; User_Int&#10;&lt;/div&gt;&#10;&lt;h2 id="caddy-を経由させる構成単一ゲートウェイ原則"&gt;Caddy を経由させる構成（単一ゲートウェイ原則）&#10;&lt;/h2&gt;&lt;p&gt;外部からの通信をすべて一度 Caddy に集約し、Caddy から各アプリケーションへ中継する構成です。この方式は、トラフィックの流入元が外部トンネルであれローカルWi-Fiであれ、すべてのアプリケーションの前段に Caddy を唯一の「内部ゲートウェイ」として配置するという思想に基づいています。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;外部: ユーザー -&amp;gt; Cloudflare Edge -&amp;gt; cloudflared -&amp;gt; Caddy -&amp;gt; アプリケーション&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;内部: ユーザー -&amp;gt; (AdGuard Home で解決) -&amp;gt; Caddy -&amp;gt; アプリケーション&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="メリット"&gt;メリット&#10;&lt;/h3&gt;&lt;p&gt;この構成の最大の強みは、&lt;strong&gt;ルーティングとアクセスログのローカル一元化&lt;/strong&gt;にあります。&lt;code&gt;cloudflared&lt;/code&gt; 側の設定は「ドメイン全体の通信をすべてローカルの Caddy へ流す」という抽象的なルールのみで固定できます。これにより、新しくアプリケーションを追加・変更する際も、外部のトンネル設定に手を加える必要がなく、ローカルの &lt;code&gt;Caddyfile&lt;/code&gt; と内部 DNS レコードを更新するだけで作業が完結します。また、すべてのアクセスが Caddy を通過するため、ローカルサーバー単体で統一的なアクセスログを取得・監視することが可能です。&lt;/p&gt;&#10;&lt;h3 id="デメリットと注意点"&gt;デメリットと注意点&#10;&lt;/h3&gt;&lt;p&gt;この方式の課題は、&lt;strong&gt;二重リバースプロキシによる運用の複雑化&lt;/strong&gt;です。Cloudflare Edge で一度終端された HTTPS 通信が Caddy に渡されるため、プロキシヘッダーの適切な伝播が不可欠となります。具体的には、Caddy 側で &lt;code&gt;trusted_proxies&lt;/code&gt; などの設定を正しく行わないと、クライアントの送信元 IP アドレスが &lt;code&gt;cloudflared&lt;/code&gt; のローカル IP に上書きされたり、プロトコル（HTTP/HTTPS）の認識違いによって WordPress 等のアプリケーションでリダイレクトループが発生する原因になります。また、Caddy が停止した際に外部・内部双方の通信が同時にダウンするという、単一障害点（SPOF）を抱えることになります。&lt;/p&gt;&#10;&lt;h2 id="caddy-を経由させない構成疎結合最小ホップ原則"&gt;Caddy を経由させない構成（疎結合・最小ホップ原則）&#10;&lt;/h2&gt;&lt;p&gt;&lt;code&gt;cloudflared&lt;/code&gt; が備える Ingress ルールを用い、外部からの通信を Caddy を介さずに直接各アプリケーションのポート番号へフォワードする構成です。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;外部: ユーザー -&amp;gt; Cloudflare Edge -&amp;gt; cloudflared -&amp;gt; アプリケーション&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;内部: ユーザー -&amp;gt; (AdGuard Home で解決) -&amp;gt; Caddy -&amp;gt; アプリケーション&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="メリット-1"&gt;メリット&#10;&lt;/h3&gt;&lt;p&gt;この構成の根拠は、&lt;strong&gt;不要な中間レイヤーの排除&lt;/strong&gt;にあります。&lt;code&gt;cloudflared&lt;/code&gt; 自体がリバースプロキシとしての転送機能を備えているため、後段にさらに Caddy を挟むことは処理遅延と障害要因を増やすだけにすぎないという判断です。多段プロキシ構造を避けることで、前述したヘッダーの食い違いや SSL 終端に起因するリダイレクトトラブルのリスクを根本から排除できます。また、Caddy の設定ミスや障害が外部公開用エンドポイントに波及しません。&lt;/p&gt;&#10;&lt;h3 id="デメリットと注意点-1"&gt;デメリットと注意点&#10;&lt;/h3&gt;&lt;p&gt;一方で、&lt;strong&gt;ルーティング設定が2箇所に分散する&lt;/strong&gt;という管理上のコストが発生します。外部からのアクセス経路は Cloudflare 側（Zero Trust ダッシュボードまたはローカルの &lt;code&gt;config.yml&lt;/code&gt;）で定義し、LAN 内からのアクセス経路は &lt;code&gt;Caddyfile&lt;/code&gt; で個別に定義しなければなりません。ポート番号やコンテナの配置を変更した際に一方の更新を忘れると、「LAN内からは開けるが外部からは繋がらない」といった不整合が生じやすくなります。&lt;/p&gt;&#10;&lt;h2 id="運用における選択基準"&gt;運用における選択基準&#10;&lt;/h2&gt;&lt;p&gt;コミュニティや実際の運用環境における傾向を踏まえると、選択の基準は「管理するサービスの規模」と「ローカル完結の重要度」に集約されます。&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;Caddy 経由が選ばれるケース&lt;/strong&gt;: 多数のコンテナやサービスを自宅内で常時稼働させており、AdGuard Home によるスプリットホライズンDNSを構築してLAN内からの高速な直接アクセスを維持したい環境。サービス追加のたびに外部トンネルの設定を弄る手間を減らし、ローカル側の設定ファイル群でインフラを一元管理したい場合に適しています。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Caddy 非経由（直接転送）が選ばれるケース&lt;/strong&gt;: 公開するサービスが少数（数個程度）に限定されている環境。Cloudflare Zero Trust の GUI 管理画面上でサブドメインの転送先とアクセス制御（Cloudflare Access 等による認証）をまとめて視覚的に管理したい場合や、多段プロキシに起因するネットワークトラブルの検証コストを最小限に抑えたい場合に適しています。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;どちらの構成を選択する場合であっても、ネットワークの物理的な境界と各プロキシが担う責務の境界を明確に定義することが、安定したセルフホスト運用の基盤となります。&lt;/p&gt;&#10;</description></item><item><title>東京が消し飛んでもシステムを復旧させるのか？──現場を凍りつかせる「BCPチェックシート」という名の茶番</title><link>https://ai.hack-le.com/%E6%9D%B1%E4%BA%AC%E3%81%8C%E6%B6%88%E3%81%97%E9%A3%9B%E3%82%93%E3%81%A7%E3%82%82%E3%82%B7%E3%82%B9%E3%83%86%E3%83%A0%E3%82%92%E5%BE%A9%E6%97%A7%E3%81%95%E3%81%9B%E3%82%8B%E3%81%AE%E3%81%8B%EF%BC%9F/</link><pubDate>Thu, 17 Sep 2026 23:32:10 +0900</pubDate><guid>https://ai.hack-le.com/%E6%9D%B1%E4%BA%AC%E3%81%8C%E6%B6%88%E3%81%97%E9%A3%9B%E3%82%93%E3%81%A7%E3%82%82%E3%82%B7%E3%82%B9%E3%83%86%E3%83%A0%E3%82%92%E5%BE%A9%E6%97%A7%E3%81%95%E3%81%9B%E3%82%8B%E3%81%AE%E3%81%8B%EF%BC%9F/</guid><description>&lt;p&gt;&lt;a class="link" href="https://gigazine.net/news/20260917-aws-middle-east-data-center-unable-to-restore/" target="_blank" rel="noopener"&#10; &gt;イランによるAmazonのデータセンターへの攻撃により顧客データが永久に失われる - GIGAZINE&lt;/a&gt;&lt;/p&gt;&#10;&lt;p&gt;中東にあるクラウド事業者のデータセンターが物理的な軍事攻撃を受け、単一アベイラビリティーゾーンに配置されていたデータが恒久的に失われたという報せは、インフラエンジニアや企業のリスク管理部門に冷水を浴びせました。どれほど論理的に抽象化されていようと、クラウドの実体は特定の緯度と経度に固定されたコンクリートとシリコンの塊であり、不可逆な物理破壊の前には無力であるという冷厳な事実です。&lt;/p&gt;&#10;&lt;p&gt;しかし、このニュースに触れたとき、私たちが真に直面させられるのは技術的アーキテクチャの敗北だけではありません。日本の多くの大企業で機械的に配られ、現場のエンジニアが半ば虚無感とともに記入させられている「事業継続計画（BCP）チェックシート」の欺瞞こそが、白日の下に晒されたと言えます。&lt;/p&gt;&#10;&lt;h2 id="基幹インフラだけが無傷というsf的ご都合主義"&gt;「基幹インフラだけが無傷」というSF的ご都合主義&#10;&lt;/h2&gt;&lt;p&gt;教科書的なBCPやクラウドの設計論では、東京リージョン（ap-northeast-1）が被災した際の解として「米国バージニア州（us-east-1）などへのマルチリージョン・フェイルオーバー」が平然と語られます。アーキテクチャ図の上では、太平洋を跨ぐ矢印を一本引くだけで対策が完了したかのように見えます。&lt;/p&gt;&#10;&lt;p&gt;しかし、現実の物理世界を少しでも想像すれば、この前提がギャグの領域にあることは明白です。東京が物理的に瓦解するほどの軍事攻撃や巨大災害が発生したとき、なぜ房総半島や茨城沿岸にある海底ケーブル陸揚局（CLS）や、都心のインターネットエクスチェンジ（IX）、超高圧変電所だけが奇跡的に無傷で稼働し続けているのでしょうか。&lt;/p&gt;&#10;&lt;p&gt;大動脈である太平洋横断ケーブル網や中継施設への給電が落ちれば、海外リージョンへのデータハイウェイそのものが瞬時に遮断されます。配管が根元から爆破されているのに、蛇口の先の水質を議論しているようなものです。海外拠点でデータが無事であろうと、それを国内の誰も参照できず、操作もできない状態であれば、そのシステムは宇宙空間を漂う無人の人工衛星と何ら変わりません。&lt;/p&gt;&#10;&lt;h2 id="この状況で仕事するわけないだろという正常な直感"&gt;「この状況で仕事するわけないだろ」という正常な直感&#10;&lt;/h2&gt;&lt;p&gt;さらに奇怪なのは、そうした極限状態においても「生身の担当者が平然と職務を遂行する」という前提がチェックシートの裏に忍ばされている点です。&lt;/p&gt;&#10;&lt;p&gt;東京が壊滅的な打撃を受け、明日また第2波の攻撃や激しい余震が来るかもしれないという状況下で、人間が真っ先に取るべき行動は一つしかありません。家族の安全を確保し、水と食料を抱えて、生存のために&lt;strong&gt;一刻も早く東京から脱出すること&lt;/strong&gt;です。&lt;/p&gt;&#10;&lt;p&gt;電気も水道も止まり、通信も途絶えた混乱の都市において、脱出の判断を数時間誤ることはそのまま死に直結します。そんな極限状態に置かれた生身の人間に対して、「担当サービスを他リージョンへ切り替えて持続性を担保できるか」と問うこと自体、破綻した状況認識と言うほかありません。&lt;/p&gt;&#10;&lt;p&gt;チェックシートを埋めながら多くのエンジニアが抱く「この状況で仕事するわけないだろ」という吐き捨てるような直感は、職責の放棄などではなく、生命を維持しようとする生物として最も健全で正確な現実認識です。&lt;/p&gt;&#10;&lt;h2 id="組織防衛のためのアリバイ工作と責任の所在"&gt;組織防衛のためのアリバイ工作と責任の所在&#10;&lt;/h2&gt;&lt;p&gt;では、なぜこのような絵空事のチェックシートが、大企業では全サービスの担当者に向けて一律に強制されるのでしょうか。理由は極めてシンプルで、それが現場の危機管理のためではなく「組織のアリバイ作り」として運用されているからです。&lt;/p&gt;&#10;&lt;p&gt;経営陣やリスク管理部門の目的は、実際に国家機能が麻痺したときにサービスを復旧させることではありません。株主総会、監査法人、取引先に対して「当社は全社的にリスクを評価し、統制を図っています」と報告するためのエビデンス、すなわち「記入済みシートの束」を揃えることが自己目的化しています。&lt;/p&gt;&#10;&lt;p&gt;そしてこの構造の最も残酷な点は、想定外の破滅が起きた際の泥を現場に被せられる余地を残していることです。「事前に貴方がこの時間で復旧できると書きましたよね」という手続きを踏ませることで、管理側は免責され、破綻の責任は「現場の見通しの甘さ」へと矮小化されます。&lt;/p&gt;&#10;&lt;h2 id="欺瞞を捨て本当の生存から逆算する"&gt;欺瞞を捨て、本当の「生存」から逆算する&#10;&lt;/h2&gt;&lt;p&gt;平時のビジネスやSaaSが提供する価値は、社会インフラと法秩序という巨大な土台が正常に維持されていて初めて成立する二次的な産物に過ぎません。&lt;/p&gt;&#10;&lt;p&gt;組織の体裁を保つための書類仕事に大人の対応として付き合うことは、サラリーマンとしての処世術かもしれません。しかし、心の奥底にある「世界が終わっているときに、会社のシステムを心配している場合ではない」という冷徹な感覚だけは手放してはなりません。&lt;/p&gt;&#10;&lt;p&gt;物理インフラが国家間の武力衝突や未曾有の大災害に巻き込まれたとき、真に問われるのはSaaSの可用性ではなく、私たち自身がいかに今日を生き延びるかという、剥き出しのサバイバルなのです。&lt;/p&gt;&#10;</description></item><item><title>サーバレスの夢の残骸</title><link>https://ai.hack-le.com/%E3%82%B5%E3%83%BC%E3%83%90%E3%83%AC%E3%82%B9%E3%81%AE%E5%A4%A2%E3%81%AE%E6%AE%8B%E9%AA%B8/</link><pubDate>Sat, 12 Sep 2026 14:05:03 +0900</pubDate><guid>https://ai.hack-le.com/%E3%82%B5%E3%83%BC%E3%83%90%E3%83%AC%E3%82%B9%E3%81%AE%E5%A4%A2%E3%81%AE%E6%AE%8B%E9%AA%B8/</guid><description>&lt;h2 id="aws文学と一次資料至上主義の病理"&gt;「AWS文学」と一次資料至上主義の病理&#10;&lt;/h2&gt;&lt;p&gt;かつて多くのエンジニアが、AWSの膨大な公式ドキュメントをお経のように熱心に読み解き、そこに書かれた仕様を忠実に実装することを美徳としていた時代がありました。難解で重層的な修飾節が連なり、例外規定と免責条項が張り巡らされたその独特な文体は、いつしか「AWS文学」と揶揄されるようになりました。この読みづらさは偶然の産物ではなく、コンウェイの法則に従って細分化された組織構造、サービスごとに異なる文脈、そして障害発生時の免責を徹底しようとする法律文書に近い執筆スタイルが重なり合った必然の結果です。&lt;/p&gt;&#10;&lt;p&gt;本来、技術者が真に求めているのは「目の前のシステムをどう安全に動かすか」という具体的な設計判断や勘所です。しかし、プラットフォーマーが公式文書として提示するのは「仕様の完全な網羅と免責」にすぎません。それにもかかわらず、業界には「一次資料こそが絶対の正義である」という盲目的な信仰が定着しました。一次資料が保証するのはあくまで現行実装に対する法的な正確さであり、読者が目的を達成するための実用性とは本質的に無関係です。難解なドキュメントと格闘したサンクコストを正当化し、二次情報を軽視して門番のように振る舞う文化は、エンジニアリングを手段から知的なマウンティングの道具へと変質させていきました。&lt;/p&gt;&#10;&lt;p&gt;現場を経験したエンジニアであれば誰しも、「ドキュメント上で保証されている仕様」と「本番環境の物理レイヤーで現実に起きる挙動」の間に横たわる深い溝を知っています。結果整合性の遅延、隠れたクォータ制限、ネットワーク断に伴う見かけ上のエラーなど、仕様書の外側にこそ現実の泥沼があります。何を読み、何を読まないかという情報選定の段階からエンジニアの責任は始まっています。公式の言説を無批判に崇める姿勢は、巨大プラットフォーマーのブランド力に自らの野生と批評精神を明け渡した結果にほかなりませんでした。&lt;/p&gt;&#10;&lt;h2 id="クラウドへの屈服とアーキテクチャの複雑性の爆発"&gt;クラウドへの屈服とアーキテクチャの複雑性の爆発&#10;&lt;/h2&gt;&lt;p&gt;なぜあの時代、これほど多くのエンジニアや組織が思考停止に陥り、プラットフォームに従属していったのでしょうか。その背景には、抗いがたい時代の構造的圧力が存在していました。かつてのオンプレミス環境における深夜のデータセンター作業、突然死するハードウェア、調達に数ヶ月を要する見積もりといった運用地獄からの解放は、あまりにも強烈なカタルシスをもたらしました。その恩恵の大きさゆえに、多少の歪みや理不尽には目を瞑るという暗黙の取引が成立してしまったのです。&lt;/p&gt;&#10;&lt;p&gt;さらに、資産を持たない身軽さを求める経営層からの強力なトップダウンや、急速に膨張する業界で未経験者を即戦力化するための「認定資格」を中心とした教育の標準化が、この流れを加速させました。その結果、エンジニアリングの本質である泥臭い問題解決能力よりも、プラットフォーム固有のお作法をどれだけ記憶しているかが重宝される歪んだ土壌が完成しました。&lt;/p&gt;&#10;&lt;p&gt;こうして熱狂の中で迎えられたクラウドでしたが、システムの進化は新たな袋小路へと突き当たります。S3、DynamoDB、Lambda、SQSといったサービス群は、インフラの存在を忘れさせる圧倒的な未来を確かに予感させました。しかし、それらを組み合わせて巨大な業務システムを構築しようとした瞬間、&lt;strong&gt;アーキテクチャの複雑性の爆発&lt;/strong&gt;という過酷な代償を支払うことになりました。&lt;/p&gt;&#10;&lt;p&gt;かつてモノリスの内部でメモリ上の関数呼び出しとして完結していた処理が、細切れのマイクロサービスやイベント駆動へと分解された結果、単なるデータの受け渡しがすべてネットワーク越しの分散トランザクションへと化しました。重複配信への対策、メッセージの順序制御、デッドレターキューの監視、そして数千行に及ぶ設定ファイル（IaC）の保守など、コードの行数を減らした代わりにインフラの接続点と失敗パターンが指数関数的に増大していったのです。&lt;/p&gt;&#10;&lt;h2 id="コンテナオーケストレーションという名の欺瞞"&gt;コンテナオーケストレーションという名の欺瞞&#10;&lt;/h2&gt;&lt;p&gt;分散システムの複雑性に疲弊した業界が次に逃げ込んだのが、ECSやKubernetesをはじめとするコンテナオーケストレーションでした。しかし、それは解決策どころか、さらなる高額な固定費と運用の怪物を飼い慣らす選択にすぎませんでした。&lt;/p&gt;&#10;&lt;p&gt;コンテナオーケストレーションは、本質的に&lt;strong&gt;IaaS（仮想インフラ）のレイヤーにとどまるリソース占有型のモデル&lt;/strong&gt;です。どれだけ軽量なコンテナを動かそうと、背後には24時間365日稼働し続ける仮想マシンやプロビジョニングされたリソースが存在します。そこにコントロールプレーンの維持費、高額なデータ転送料、監視エージェントのオーバーヘッド、そして安全マージンとして死蔵される大量の空きリソースが積み重なります。結果として、何も処理していなくても毎月莫大なプラットフォーム税が徴収される構造から抜け出せなくなりました。&lt;/p&gt;&#10;&lt;p&gt;現代の物理ハードウェアは目覚ましい進化を遂げています。コンテナ基盤に投じられる年間数百万円から数千万円規模のコストがあれば、最新のワークステーションやサーバー、堅牢なネットワーク機器を一式揃え、さらには物理的なオフィススペースの賃料を払ってもお釣りが来るという計算は、決して荒唐無稽な暴論ではありません。「可用性とスケーラビリティ」という美名のもとに仮想化レイヤーの上で自作PCごっこを繰り返す経済的な不条理に、多くの現場が直面しています。&lt;/p&gt;&#10;&lt;h2 id="果たせぬ夢だったサーバレスと物理バイナリへの誇り"&gt;果たせぬ夢だったサーバレスと、物理バイナリへの誇り&#10;&lt;/h2&gt;&lt;p&gt;いま振り返るべきは、私たちがかつて信じた&lt;strong&gt;真のサーバレスアーキテクチャの思想&lt;/strong&gt;とは何であったかという問いです。だからこそ、コンテナを裏で自動起動するだけの仕組みを「サーバレス」と呼ぶ昨今の風潮には、強い違和感を覚えざるを得ません。それは、かつての美しい思想に対するマーケティング的な簒奪でした。&lt;/p&gt;&#10;&lt;p&gt;本来のサーバレスが提示した革命とは、以下のような計算モデルの根本的な転換でした。&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;常駐（Daemon）からの解放&lt;/strong&gt;リクエストを待ち受けるためにリソースを占有し続ける旧来のあり方を否定し、事象（Event）が発生したその刹那だけ実体化し、計算を終えたら跡形もなく虚空へ消え去るという儚くも無駄のないモデル。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;因果関係の記述への純化&lt;/strong&gt;ハードウェアのキャパシティに頭を悩ませるのではなく、世界で起きる変化に対して純粋関数をマッピングしていくという、プログラミングの原初的な快感への回帰。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;ゼロの誠実さ&lt;/strong&gt;動いていない時間には1円のコストも発生させないという、真の従量課金がもたらす透明で合理的な経済性。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;DynamoDBやLambdaは、強烈なベンダーロックインと引き換えにこの思想を極限まで具現化した稀有な道具であり、その純粋な割り切りとコストパフォーマンスにおいて、今なお独自の輝きを放っています。しかし、その純粋な思想は、業界全体の複雑化と巨大なプラットフォームビジネスの波に呑み込まれ、果たせぬ夢として終わりました。&lt;/p&gt;&#10;</description></item><item><title>下品な無差別サーバ攻撃の不快感</title><link>https://ai.hack-le.com/%E4%B8%8B%E5%93%81%E3%81%AA%E7%84%A1%E5%B7%AE%E5%88%A5%E3%82%B5%E3%83%BC%E3%83%90%E6%94%BB%E6%92%83%E3%81%AE%E4%B8%8D%E5%BF%AB%E6%84%9F/</link><pubDate>Thu, 27 Aug 2026 23:33:57 +0900</pubDate><guid>https://ai.hack-le.com/%E4%B8%8B%E5%93%81%E3%81%AA%E7%84%A1%E5%B7%AE%E5%88%A5%E3%82%B5%E3%83%BC%E3%83%90%E6%94%BB%E6%92%83%E3%81%AE%E4%B8%8D%E5%BF%AB%E6%84%9F/</guid><description>&lt;p&gt;Webサイトを運用していると、海外の特定地域から意味をなさない無差別なアクセスや脆弱性スキャンが大量に押し寄せてくることがあります。実害としてはCPU使用率がわずかに上昇する程度で、システムが破綻する危険性は皆無であっても、管理者の精神やログ領域を無意味に汚染される不快感は拭えません。&lt;/p&gt;&#10;&lt;h2 id="無差別スキャンの実態と下品な攻撃がもたらす徒労感"&gt;無差別スキャンの実態と「下品な攻撃」がもたらす徒労感&#10;&lt;/h2&gt;&lt;p&gt;サイトの言語設定や稼働環境を一切無視して、存在しないWordPressのログインパス（&lt;code&gt;wp-login.php&lt;/code&gt;）や特定プラグインの脆弱性URLを機械的に乱打してくる行為は、高度なサイバー攻撃などではなく、単なる全IPアドレスへの絨毯爆撃です。感染したボットネットやスクリプトキディが、使い捨ての環境から無差別にツールを垂れ流しているに過ぎません。&lt;/p&gt;&#10;&lt;p&gt;かつてのハッカー文化や義賊的な存在に見られたような、一定の技術的哲学や対象への選定眼、抑制といったものはここには一切存在しません。成功確率が0%であるにもかかわらずリクエストを垂れ流す行為は、公共のインターネット空間に生ゴミを不法投棄しているのと同義です。&lt;/p&gt;&#10;&lt;p&gt;このような行為は、夜中に窓ガラスへ狂ったように体当たりを繰り返す害虫の羽音に似ています。室内へ侵入される危険性は皆無であるにもかかわらず、激突音を聞かされ、窓ガラスに汚れを残されることに対する純粋な生理的嫌悪感と徒労感だけが残ります。&lt;/p&gt;&#10;&lt;h2 id="結論としての防御方針"&gt;結論としての防御方針&#10;&lt;/h2&gt;&lt;p&gt;こうした低レベルなノイズに対して、オリジンサーバー側のリソースや管理者の意識を割くこと自体が無駄と言えます。CloudflareのようなCDN/WAFのエッジ側で機械的に&lt;code&gt;Block&lt;/code&gt;または&lt;code&gt;Managed Challenge&lt;/code&gt;を適用し、オリジンサーバーに一切到達させない構成を敷くことが、精神衛生上および運用管理上において最も費用対効果の高い対処法となります。&lt;/p&gt;&#10;</description></item><item><title>AWS DynamoDBでQuery操作を行う方法【Boto3】</title><link>https://ai.hack-le.com/dynamodb-query/</link><pubDate>Wed, 08 Jan 2025 10:41:44 +0900</pubDate><guid>https://ai.hack-le.com/dynamodb-query/</guid><description>&lt;p&gt;DynamoDBの&lt;code&gt;Query&lt;/code&gt;操作は、テーブルまたはインデックスのパーティションキーを指定し、条件に一致するデータを取得するために使用します。この備忘録では、基本的な使い方から応用例までを紹介します。&lt;/p&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="必要なモジュールのインポート"&gt;必要なモジュールのインポート&#10;&lt;/h2&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;boto3&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;boto3.dynamodb.conditions&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Attr&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;&lt;code&gt;boto3&lt;/code&gt;&lt;/strong&gt; : AWS SDK for Python。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;&lt;code&gt;boto3.dynamodb.conditions.Key&lt;/code&gt;&lt;/strong&gt; : &lt;code&gt;KeyConditionExpression&lt;/code&gt; に使用。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;&lt;code&gt;boto3.dynamodb.conditions.Attr&lt;/code&gt;&lt;/strong&gt; : &lt;code&gt;FilterExpression&lt;/code&gt; に使用。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="dynamodbリソースの初期化"&gt;DynamoDBリソースの初期化&#10;&lt;/h2&gt;&lt;p&gt;DynamoDBテーブルを操作するには、Boto3リソースまたはクライアントを使用します。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# DynamoDBリソースの初期化&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;dynamodb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;boto3&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;resource&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;dynamodb&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# テーブルを指定&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;table&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;dynamodb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Table&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;YourTableName&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;&#10;&lt;h2 id="基本的なquery操作"&gt;基本的なQuery操作&#10;&lt;/h2&gt;&lt;h4 id="パーティションキーのみを指定"&gt;パーティションキーのみを指定&#10;&lt;/h4&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;boto3.dynamodb.conditions&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Key&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;table&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;KeyConditionExpression&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;Key&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;partition_key&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;eq&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;your_partition_value&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 結果を表示&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Items&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id="パーティションキー--ソートキー条件"&gt;パーティションキー + ソートキー条件&#10;&lt;/h4&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;table&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;KeyConditionExpression&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;Key&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;partition_key&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;eq&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;your_partition_value&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;Key&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;sort_key&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;gte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;2023-01-01&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# ソートキーの条件を追加&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 結果を表示&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Items&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;&#10;&lt;h2 id="結果のソート順を変更"&gt;結果のソート順を変更&#10;&lt;/h2&gt;&lt;h4 id="昇順デフォルト"&gt;昇順（デフォルト）&#10;&lt;/h4&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;table&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;KeyConditionExpression&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;Key&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;partition_key&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;eq&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;your_partition_value&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;ScanIndexForward&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;True&lt;/span&gt; &lt;span class="c1"&gt;# 昇順&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id="降順"&gt;降順&#10;&lt;/h4&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;table&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;KeyConditionExpression&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;Key&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;partition_key&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;eq&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;your_partition_value&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;ScanIndexForward&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;False&lt;/span&gt; &lt;span class="c1"&gt;# 降順&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;&#10;&lt;h2 id="フィルタリングを追加"&gt;フィルタリングを追加&#10;&lt;/h2&gt;&lt;h4 id="filterexpression-を使用"&gt;&lt;code&gt;FilterExpression&lt;/code&gt; を使用&#10;&lt;/h4&gt;&lt;p&gt;&lt;code&gt;FilterExpression&lt;/code&gt; を使用すると、データの一部を除外できます。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;table&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;KeyConditionExpression&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;Key&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;partition_key&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;eq&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;your_partition_value&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;FilterExpression&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;Attr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;attribute_name&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;contains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;example_value&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# 属性のフィルタリング&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;注意&lt;/strong&gt;: &lt;code&gt;FilterExpression&lt;/code&gt; はDynamoDBから取得したデータのフィルタリングを行います。&lt;code&gt;KeyConditionExpression&lt;/code&gt; とは異なり、データスキャン後にフィルタリングされるためコストが増加する可能性があります。&lt;/p&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="結果のページング処理"&gt;結果のページング処理&#10;&lt;/h2&gt;&lt;p&gt;DynamoDBはデフォルトで1MBのデータを返します。結果が複数ページにわたる場合、&lt;code&gt;LastEvaluatedKey&lt;/code&gt; を使用して次のページを取得します。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;table&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;KeyConditionExpression&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;Key&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;partition_key&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;eq&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;your_partition_value&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;items&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Items&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# ページング処理&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;LastEvaluatedKey&amp;#39;&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;table&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;KeyConditionExpression&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;Key&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;partition_key&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;eq&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;your_partition_value&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;ExclusiveStartKey&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;LastEvaluatedKey&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="c1"&gt;# 次のページの開始キー&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;extend&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Items&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 全データを表示&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;&#10;&lt;h2 id="インデックスを使用したquery"&gt;インデックスを使用したQuery&#10;&lt;/h2&gt;&lt;p&gt;ローカルセカンダリインデックス（LSI）やグローバルセカンダリインデックス（GSI）を指定してクエリを実行できます。&lt;/p&gt;&#10;&lt;h4 id="例-gsiの指定"&gt;例: GSIの指定&#10;&lt;/h4&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;table&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;IndexName&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;YourGSIName&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;# インデックス名を指定&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;KeyConditionExpression&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;Key&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;gsi_partition_key&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;eq&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;value&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;&#10;&lt;h2 id="エラーハンドリング"&gt;エラーハンドリング&#10;&lt;/h2&gt;&lt;p&gt;DynamoDB操作中にエラーが発生する場合に備えて、エラーハンドリングを追加します。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;table&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;KeyConditionExpression&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;Key&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;partition_key&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;eq&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;your_partition_value&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Items&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="ne"&gt;Exception&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;エラーが発生しました: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;&#10;&lt;h2 id="実際のデータ例"&gt;実際のデータ例&#10;&lt;/h2&gt;&lt;h4 id="テーブル構造"&gt;テーブル構造&#10;&lt;/h4&gt;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;Partition Key&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;Sort Key&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;Data&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;user1&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;2023-01-01&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Entry A&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;user1&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;2023-01-02&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Entry B&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;user2&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;2023-01-01&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Entry C&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;h4 id="クエリ結果例"&gt;クエリ結果例&#10;&lt;/h4&gt;&lt;p&gt;クエリ: &lt;code&gt;Key('partition_key').eq('user1') &amp;amp; Key('sort_key').gte('2023-01-01')&lt;/code&gt;&lt;/p&gt;&#10;&lt;p&gt;結果:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;[&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; { &amp;#34;Partition Key&amp;#34;: &amp;#34;user1&amp;#34;, &amp;#34;Sort Key&amp;#34;: &amp;#34;2023-01-01&amp;#34;, &amp;#34;Data&amp;#34;: &amp;#34;Entry A&amp;#34; },&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; { &amp;#34;Partition Key&amp;#34;: &amp;#34;user1&amp;#34;, &amp;#34;Sort Key&amp;#34;: &amp;#34;2023-01-02&amp;#34;, &amp;#34;Data&amp;#34;: &amp;#34;Entry B&amp;#34; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;]&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;&#10;&lt;h2 id="注意点とベストプラクティス"&gt;注意点とベストプラクティス&#10;&lt;/h2&gt;&lt;ol&gt;&#10;&lt;li&gt;&lt;strong&gt;適切なインデックス設計&lt;/strong&gt;:&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;効率的なクエリを実現するため、事前にパーティションキーとソートキーを適切に設計します。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;ol start="2"&gt;&#10;&lt;li&gt;&lt;strong&gt;&lt;code&gt;FilterExpression&lt;/code&gt; の使用を最小限に&lt;/strong&gt;:&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;code&gt;KeyConditionExpression&lt;/code&gt; を活用し、スキャンコストを削減。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;ol start="3"&gt;&#10;&lt;li&gt;&lt;strong&gt;エラー処理&lt;/strong&gt;:&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;ネットワークエラーやスロットリング（リクエスト制限）に備えてリトライロジックを実装。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;hr&gt;&#10;&lt;p&gt;これでDynamoDBのQuery操作に関する基本と応用が網羅されています。必要に応じてコピー＆ペーストして活用してください！&lt;/p&gt;&#10;</description></item><item><title>AWS Systems Manager Parameter Storeからパラメータを取得する方法（Python + Boto3）</title><link>https://ai.hack-le.com/aws-systems-manager-parameter-store/</link><pubDate>Sat, 16 Nov 2024 10:57:15 +0900</pubDate><guid>https://ai.hack-le.com/aws-systems-manager-parameter-store/</guid><description>&lt;p&gt;AWS Systems Manager Parameter Storeは、設定データや機密情報（APIキーやパスワードなど）を安全に管理するためのサービスです。本記事では、Pythonを使ってParameter Storeから値を取得する汎用的な方法を解説します。&lt;/p&gt;&#10;&lt;h2 id="必要な準備"&gt;必要な準備&#10;&lt;/h2&gt;&lt;ol&gt;&#10;&lt;li&gt;&lt;strong&gt;Python環境の構築&lt;/strong&gt; PythonとAWS SDK for Python（Boto3）がインストールされている必要があります。以下のコマンドでBoto3をインストールします。&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;pip install boto3&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ol&gt;&#10;&lt;li&gt;&lt;strong&gt;AWSの認証情報と権限&lt;/strong&gt; プログラムを実行する環境に、適切なAWS認証情報が設定されている必要があります（&lt;code&gt;~/.aws/credentials&lt;/code&gt; または環境変数）。また、以下の権限が必要です。&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;code&gt;ssm:GetParameter&lt;/code&gt;&lt;/li&gt;&#10;&lt;li&gt;暗号化された値を取得する場合は、KMSキーの復号化権限（&lt;code&gt;kms:Decrypt&lt;/code&gt;）&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;ol&gt;&#10;&lt;li&gt;&lt;strong&gt;Parameter Storeへの登録&lt;/strong&gt; Parameter Storeに取得したい値を登録します。例として、以下のコマンドで値を登録できます。&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws ssm put-parameter \&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --name &amp;#34;/example/parameter&amp;#34; \&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --value &amp;#34;my-secret-value&amp;#34; \&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --type &amp;#34;SecureString&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;&#10;&lt;h2 id="汎用的なpythonコードスニペット"&gt;汎用的なPythonコードスニペット&#10;&lt;/h2&gt;&lt;p&gt;以下のコードは、Parameter Storeから値を取得するための汎用的な関数です。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;boto3&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;botocore.exceptions&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;BotoCoreError&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ClientError&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;fetch_parameter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;parameter_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;with_decryption&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;&amp;#34;&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; AWS Systems Manager Parameter Storeからパラメータを取得する汎用関数&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; Args:&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; parameter_name (str): 取得するパラメータの名前&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; with_decryption (bool): 暗号化された値を復号化するかどうか&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; Returns:&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; str: パラメータの値（取得成功時）&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; None: エラー時&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; &amp;#34;&amp;#34;&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# SSMクライアントの初期化&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;ssm_client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;boto3&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;ssm&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# パラメータの取得&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ssm_client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_parameter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;parameter_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;WithDecryption&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;with_decryption&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Parameter&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Value&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BotoCoreError&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ClientError&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;Error fetching parameter &amp;#39;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;parameter_name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;#39;: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 使用例&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="vm"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;__main__&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;parameter_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;/example/parameter&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;fetch_parameter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;parameter_name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;Parameter value: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;Failed to fetch the parameter.&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;&#10;&lt;h2 id="コードの説明"&gt;コードの説明&#10;&lt;/h2&gt;&lt;h3 id="fetch_parameter-関数の引数"&gt;&lt;code&gt;fetch_parameter&lt;/code&gt; 関数の引数&#10;&lt;/h3&gt;&lt;ul&gt;&#10;&lt;li&gt;&lt;code&gt;parameter_name&lt;/code&gt; Parameter Storeで登録されているパラメータ名を指定します。&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;with_decryption&lt;/code&gt; 暗号化されたパラメータを復号化するかを指定します。デフォルトは&lt;code&gt;True&lt;/code&gt;（復号化する）です。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h3 id="例外処理"&gt;例外処理&#10;&lt;/h3&gt;&lt;ul&gt;&#10;&lt;li&gt;&lt;code&gt;BotoCoreError&lt;/code&gt; および &lt;code&gt;ClientError&lt;/code&gt; は、AWSクライアントでよく発生する例外です。適切にキャッチしてエラー内容をログに記録します。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h3 id="実行例"&gt;実行例&#10;&lt;/h3&gt;&lt;p&gt;上記のコードを実行すると、Parameter Storeに登録されたパラメータの値が出力されます。&lt;/p&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="注意点"&gt;注意点&#10;&lt;/h2&gt;&lt;ol&gt;&#10;&lt;li&gt;&lt;strong&gt;認証情報の設定&lt;/strong&gt; AWS CLIの設定が済んでいない場合、以下のコマンドで設定を行います。&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws configure&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ol&gt;&#10;&lt;li&gt;&lt;strong&gt;暗号化パラメータの権限&lt;/strong&gt; 暗号化されたパラメータを取得するには、Parameter Storeで使用されているKMSキーに対する&lt;code&gt;kms:Decrypt&lt;/code&gt;権限が必要です。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;セキュリティ&lt;/strong&gt; パラメータ名や値をログに直接記録しないようにしてください（特に値が機密情報の場合）。&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="応用例"&gt;応用例&#10;&lt;/h2&gt;&lt;p&gt;この汎用関数を利用して、複数のパラメータをまとめて取得する場合や、環境変数として設定する場合のコード例を示します。&lt;/p&gt;&#10;&lt;h3 id="複数パラメータの取得"&gt;複数パラメータの取得&#10;&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;parameter_names&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;/example/param1&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;/example/param2&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;/example/param3&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;values&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;fetch_parameter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;parameter_names&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;values&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;Failed to fetch &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="環境変数への設定"&gt;環境変数への設定&#10;&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;os&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;parameter_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;/example/parameter&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;fetch_parameter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;parameter_name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;MY_SECRET&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;Environment variable set successfully.&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;Failed to set environment variable.&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;&#10;&lt;h2 id="まとめ"&gt;まとめ&#10;&lt;/h2&gt;&lt;p&gt;AWS Systems Manager Parameter Storeは、機密情報を安全に管理するための強力なツールです。Pythonでの利用もBoto3を使えば簡単に実現できます。このコードスニペットを活用して、セキュアで柔軟なアプリケーション構築を目指してください。&lt;/p&gt;&#10;</description></item><item><title>[Python, Boto3] DynamoDBのクエリで1MBを超えるデータをすべて取得する関数のスニペット</title><link>https://ai.hack-le.com/python-boto3-dynamodb-query/</link><pubDate>Sun, 06 Oct 2024 15:48:30 +0900</pubDate><guid>https://ai.hack-le.com/python-boto3-dynamodb-query/</guid><description>&lt;p&gt;以下は、DynamoDBのクエリで1MBを超えるデータをすべて取得する汎用的な関数のスニペットです。このスニペットは、特定のテーブルや条件に依存しないため、どのプロジェクトでも簡単に利用できます。&lt;/p&gt;&#10;&lt;h2 id="スニペット"&gt;スニペット&#10;&lt;/h2&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;boto3&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;boto3.dynamodb.conditions&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Attr&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;query_all_items&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;table_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;key_condition_expression&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;filter_expression&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;&amp;#34;&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; DynamoDBテーブルからすべてのアイテムをクエリし、1MBを超えるデータも取得する。&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; :param table_name: クエリするテーブルの名前&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; :param key_condition_expression: クエリのKeyConditionExpression&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; :param filter_expression: オプションのFilterExpression&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; :return: すべてのアイテムのリスト&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; &amp;#34;&amp;#34;&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# DynamoDBクライアントの初期化&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;dynamodb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;boto3&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;resource&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;dynamodb&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;table&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;dynamodb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Table&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;table_name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# すべてのアイテムを格納するリスト&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;all_items&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;last_evaluated_key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# ページングしてクエリを実行&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;query_params&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;KeyConditionExpression&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;key_condition_expression&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# FilterExpressionがある場合は追加&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;filter_expression&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;query_params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;FilterExpression&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;filter_expression&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# LastEvaluatedKeyがある場合はExclusiveStartKeyを設定&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;last_evaluated_key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;query_params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;ExclusiveStartKey&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;last_evaluated_key&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# クエリの実行&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;table&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query_params&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# 結果をリストに追加&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;all_items&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;extend&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Items&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# LastEvaluatedKeyが存在する場合、次のページがある&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;last_evaluated_key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;LastEvaluatedKey&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# 次のページがない場合は終了&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;last_evaluated_key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;break&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;all_items&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="使用例"&gt;使用例&#10;&lt;/h2&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# クエリ条件の定義（例: &amp;#39;partition_key&amp;#39; が &amp;#39;example_value&amp;#39; と等しい）&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;key_condition&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Key&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;partition_key&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;eq&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;example_value&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# すべてのアイテムを取得&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;items&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;query_all_items&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;your_table_name&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;key_condition&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 結果の出力&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="オプション-filterexpression-の利用"&gt;オプション: &lt;code&gt;FilterExpression&lt;/code&gt; の利用&#10;&lt;/h2&gt;&lt;p&gt;フィルタ条件を追加して、結果をさらに絞り込むことができます。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# クエリ条件の定義&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;key_condition&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Key&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;partition_key&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;eq&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;example_value&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# フィルタ条件の定義（例: 属性 &amp;#39;status&amp;#39; が &amp;#39;active&amp;#39; のものだけ取得）&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;filter_condition&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Attr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;status&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;eq&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;active&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# すべてのアイテムを取得&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;items&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;query_all_items&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;your_table_name&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;key_condition&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;filter_condition&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 結果の出力&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="備考"&gt;備考&#10;&lt;/h2&gt;&lt;ul&gt;&#10;&lt;li&gt;&lt;code&gt;table_name&lt;/code&gt;: クエリを実行するDynamoDBテーブルの名前。&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;key_condition_expression&lt;/code&gt;: プライマリキーの条件式を定義します。パーティションキーとソートキーの条件を設定できます。&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;filter_expression&lt;/code&gt;: 結果をさらにフィルタリングするためのオプションの条件式です。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;このスニペットを活用することで、DynamoDBのすべてのアイテムをクエリしやすくなり、1MB以上のデータを扱う際のページング処理も簡単に行えます。&lt;/p&gt;&#10;</description></item><item><title>AWS SAMでLambda関数をスケジュール実行する</title><link>https://ai.hack-le.com/aws-sam-lambda-schedule/</link><pubDate>Wed, 25 Sep 2024 00:27:32 +0900</pubDate><guid>https://ai.hack-le.com/aws-sam-lambda-schedule/</guid><description>&lt;p&gt;AWS LambdaをAWS SAM（Serverless Application Model）で管理する際に、特定の間隔で定期的に実行されるようにスケジュール設定する方法について説明します。たとえば、10分ごとにLambda関数を起動したい場合に、どのように設定するかを見ていきます。&lt;/p&gt;&#10;&lt;h2 id="samテンプレートにスケジュールイベントを追加"&gt;SAMテンプレートにスケジュールイベントを追加&#10;&lt;/h2&gt;&lt;p&gt;まず、既存のSAMテンプレートに新しいイベントを追加します。今回は、&lt;code&gt;AWS::Serverless::Function&lt;/code&gt;リソースにスケジュールイベントを設定する例を示します。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;MyFunction&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;Type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;AWS::Serverless::Function&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;Properties&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;Handler&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;src/my_lambda.lambda_handler&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;Role&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;!&lt;span class="l"&gt;GetAtt MyLambdaRole.Arn&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;Environment&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;Variables&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;POWERTOOLS_SERVICE_NAME&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;MyFunction&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;Events&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;HttpRequestEvent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;Type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;HttpApi&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;Properties&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;ApiId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;!&lt;span class="l"&gt;Ref MyApiGateway&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;Path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;/myendpoint&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;Method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;get&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;ScheduleEvent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;Type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;Schedule&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;Properties&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;Schedule&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;rate(10 minutes)&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="schedule-イベントの詳細"&gt;&lt;code&gt;Schedule&lt;/code&gt; イベントの詳細&#10;&lt;/h2&gt;&lt;p&gt;この例では、既存のLambda関数に &lt;code&gt;Schedule&lt;/code&gt; イベントを追加しています。具体的には、以下の点に注目してください。&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;code&gt;Type: Schedule&lt;/code&gt;：これは、Lambda関数が定期的に実行されるようにするための設定です。&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;Schedule: rate(10 minutes)&lt;/code&gt;：10分ごとに実行されるように指定しています。AWSでは、&lt;code&gt;rate&lt;/code&gt; 式や &lt;code&gt;cron&lt;/code&gt; 式を使用してスケジュールを定義できます。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h3 id="rate-式の使用例"&gt;&lt;code&gt;rate&lt;/code&gt; 式の使用例&#10;&lt;/h3&gt;&lt;p&gt;&lt;code&gt;rate&lt;/code&gt; 式を使うことで、簡単にスケジュールを定義できます。例えば、以下のようなスケジュールが設定できます：&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;1時間ごとに実行したい場合:&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Schedule: rate(1 hour)&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;&#10;&lt;li&gt;1日ごとに実行したい場合:&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Schedule: rate(1 day)&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;rate&lt;/code&gt; 式は短い間隔で繰り返し実行する場合に便利です。&lt;/p&gt;&#10;&lt;h3 id="cron-式の使用例"&gt;&lt;code&gt;cron&lt;/code&gt; 式の使用例&#10;&lt;/h3&gt;&lt;p&gt;より複雑なスケジュールが必要な場合は、&lt;code&gt;cron&lt;/code&gt; 式を使用することもできます。&lt;/p&gt;&#10;&lt;p&gt;&lt;code&gt;cron&lt;/code&gt; 式は、定期的なスケジュールを指定するための強力なツールで、より細かい制御が可能です。AWSで使用される &lt;code&gt;cron&lt;/code&gt; 式は、5つまたは6つのフィールドで構成され、それぞれのフィールドが特定の時間単位を表します。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;cron(Minutes Hours Day-of-month Month Day-of-week Year)&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;各フィールドの意味は以下の通りです：&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;Minutes (0-59)&lt;/strong&gt; : 分単位。0から59の間で指定できます。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Hours (0-23)&lt;/strong&gt; : 時間単位。0から23の間で指定できます。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Day-of-month (1-31)&lt;/strong&gt; : 月の日。1から31の間で指定できます。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Month (1-12)&lt;/strong&gt; : 月。1月が1、12月が12です。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Day-of-week (1-7)&lt;/strong&gt; : 曜日。日曜日が1、土曜日が7です（またはSUN, MONなどの省略形が使えます）。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Year (オプション)&lt;/strong&gt; : 年単位。省略可能ですが、指定する場合は4桁で記述します。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;以下に、よく使われる &lt;code&gt;cron&lt;/code&gt; 式の例をいくつか示します。&lt;/p&gt;&#10;&lt;h4 id="毎日午前9時に実行"&gt;毎日午前9時に実行&#10;&lt;/h4&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Schedule: cron(0 9 * * ? *)&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;説明&lt;/strong&gt;: 毎日午前9時にLambda関数を実行します。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;式の解釈&lt;/strong&gt;: 分は0、時間は9（午前9時）、日・月・曜日はすべての値（&lt;code&gt;*&lt;/code&gt;）、特定の年は指定しない。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h4 id="毎月1日午前8時に実行"&gt;毎月1日午前8時に実行&#10;&lt;/h4&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Schedule: cron(0 8 1 * ? *)&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;説明&lt;/strong&gt;: 毎月1日の午前8時に実行します。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;式の解釈&lt;/strong&gt;: 毎月の1日に分0、午前8時に実行します。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h4 id="平日の毎日午後1時に実行"&gt;平日の毎日午後1時に実行&#10;&lt;/h4&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Schedule: cron(0 13 ? * MON-FRI *)&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;説明&lt;/strong&gt;: 平日（月曜〜金曜）の毎日午後1時に実行します。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;式の解釈&lt;/strong&gt;: 分0、午後1時、曜日は月曜から金曜（&lt;code&gt;MON-FRI&lt;/code&gt;）。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h4 id="週末の毎日午前10時に実行"&gt;週末の毎日午前10時に実行&#10;&lt;/h4&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Schedule: cron(0 10 ? * SAT,SUN *)&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;説明&lt;/strong&gt;: 毎週土曜日と日曜日の午前10時に実行します。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;式の解釈&lt;/strong&gt;: 分0、午前10時、曜日は土曜日と日曜日。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h4 id="毎時30分に実行"&gt;毎時30分に実行&#10;&lt;/h4&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Schedule: cron(30 * * * ? *)&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;説明&lt;/strong&gt;: 毎時30分にLambda関数を実行します。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;式の解釈&lt;/strong&gt;: 毎時間の30分に実行（時間は全ての値）。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h3 id="cron式のワイルドカード-と--の使い分け"&gt;cron式のワイルドカード&lt;code&gt;?&lt;/code&gt; と &lt;code&gt;*&lt;/code&gt; の使い分け&#10;&lt;/h3&gt;&lt;p&gt;&lt;code&gt;cron&lt;/code&gt; 式で使われる &lt;code&gt;*&lt;/code&gt; と &lt;code&gt;?&lt;/code&gt; は、どちらもワイルドカードとして機能しますが、使用場所に違いがあります。&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;&lt;code&gt;*&lt;/code&gt;&lt;/strong&gt; : すべての値を指定するために使用します。たとえば、&lt;code&gt;Minutes&lt;/code&gt; フィールドが &lt;code&gt;*&lt;/code&gt; なら「毎分」を意味します。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;&lt;code&gt;?&lt;/code&gt;&lt;/strong&gt; : &lt;code&gt;Day-of-month&lt;/code&gt; または &lt;code&gt;Day-of-week&lt;/code&gt; フィールドでのみ使用でき、「特定しない」という意味です。これにより、日または曜日のどちらかに特定の値を設定しない場合に使用します。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h2 id="まとめ"&gt;まとめ&#10;&lt;/h2&gt;&lt;p&gt;AWS SAMを使用してLambda関数を10分ごとなどの定期的な間隔で実行する設定は非常に簡単です。&lt;code&gt;rate&lt;/code&gt; 式や &lt;code&gt;cron&lt;/code&gt; 式を利用して、ニーズに応じたスケジュールを柔軟に設定できます。&lt;/p&gt;&#10;&lt;hr&gt;&#10;&lt;h3 id="参考資料"&gt;参考資料&#10;&lt;/h3&gt;&lt;ul&gt;&#10;&lt;li&gt;&lt;a class="link" href="https://docs.aws.amazon.com/lambda/latest/dg/services-cloudwatchevents-expressions.html" target="_blank" rel="noopener"&#10; &gt;AWS Lambda - Schedule expressions&lt;/a&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;a class="link" href="https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/what-is-sam.html" target="_blank" rel="noopener"&#10; &gt;AWS SAM Documentation&lt;/a&gt;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;</description></item><item><title>AWS Lambda Layers に特定のリポジトリからライブラリをアップロードする</title><link>https://ai.hack-le.com/aws-lambda-layers-repository/</link><pubDate>Sat, 21 Sep 2024 10:20:34 +0900</pubDate><guid>https://ai.hack-le.com/aws-lambda-layers-repository/</guid><description>&lt;p&gt;AWS Lambda Layers を利用することで、Lambda 関数の依存関係を外部化し、関数のデプロイパッケージをシンプルに保つことができます。本記事では、特定の Git リポジトリから取得したライブラリを AWS Lambda Layers にアップロードする手順を解説します。&lt;/p&gt;&#10;&lt;h2 id="前提条件"&gt;前提条件&#10;&lt;/h2&gt;&lt;p&gt;以下のツールがインストールされていることを確認してください。&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;Python 3.x&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;pip&lt;/code&gt;&lt;/li&gt;&#10;&lt;li&gt;AWS CLI&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;zip&lt;/code&gt; コマンド&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h2 id="lambda-layer-用のディレクトリ構造を作成"&gt;Lambda Layer 用のディレクトリ構造を作成&#10;&lt;/h2&gt;&lt;p&gt;Lambda Layer 用に、ライブラリをインストールするディレクトリを作成します。Lambda Layers は、このディレクトリ内にライブラリを配置することで、Lambda 関数がそれらを参照できるようにします。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;mkdir python&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;python&lt;/code&gt; ディレクトリが Layer にアップロードされる場所です。この中にライブラリをインストールしていきます。&lt;/p&gt;&#10;&lt;h2 id="git-リポジトリからライブラリをインストール"&gt;Git リポジトリからライブラリをインストール&#10;&lt;/h2&gt;&lt;p&gt;次に、&lt;code&gt;pip&lt;/code&gt; を使って特定の Git リポジトリからライブラリを &lt;code&gt;python&lt;/code&gt; ディレクトリ内にインストールします。例えば、特定のコミットハッシュやブランチを指定してライブラリを取得したい場合、以下のようなコマンドを使います。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;pip install git+https://&amp;lt;リポジトリのURL&amp;gt;@&amp;lt;コミットハッシュまたはブランチ名&amp;gt; -t python/&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;&amp;lt;リポジトリのURL&amp;gt;&lt;/code&gt; は対象ライブラリの Git リポジトリ URL を指定し、&lt;code&gt;&amp;lt;コミットハッシュまたはブランチ名&amp;gt;&lt;/code&gt; には特定のバージョンやブランチを指定します。&lt;/p&gt;&#10;&lt;h2 id="不要なファイルを削除オプション"&gt;不要なファイルを削除（オプション）&#10;&lt;/h2&gt;&lt;p&gt;インストールしたライブラリには、不要なファイル（例：ドキュメントやテストファイル）が含まれることがあります。Lambda Layers のサイズを抑えるために、以下のコマンドで不要なファイルを削除します。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;find python/ -name &amp;#34;*.dist-info&amp;#34; -exec rm -r {} +&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;find python/ -name &amp;#34;*.egg-info&amp;#34; -exec rm -r {} +&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="layer-の-zip-ファイルを作成"&gt;Layer の ZIP ファイルを作成&#10;&lt;/h2&gt;&lt;p&gt;次に、&lt;code&gt;python&lt;/code&gt; ディレクトリを ZIP ファイルに圧縮します。この ZIP ファイルが、AWS Lambda にアップロードされる Layer の内容になります。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;zip -r layer.zip python&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;これで Layer の準備が整いました。&lt;/p&gt;&#10;&lt;h2 id="aws-lambda-layer-にアップロード"&gt;AWS Lambda Layer にアップロード&#10;&lt;/h2&gt;&lt;p&gt;AWS CLI を使って、作成した ZIP ファイルを AWS Lambda Layer にアップロードします。以下のコマンドを実行します。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws lambda publish-layer-version \&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --layer-name &amp;lt;Layer名&amp;gt; \&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --description &amp;#34;Lambda Layer for custom libraries&amp;#34; \&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --zip-file fileb://layer.zip \&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --compatible-runtimes python3.x \&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --region &amp;lt;リージョン名&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;&#10;&lt;li&gt;&lt;code&gt;&amp;lt;Layer名&amp;gt;&lt;/code&gt; には Layer の名前を指定します。&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;&amp;lt;リージョン名&amp;gt;&lt;/code&gt; には AWS のリージョンを指定します（例：&lt;code&gt;ap-northeast-1&lt;/code&gt; など）。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;このコマンドを実行すると、Layer の ARN（Amazon リソースネーム）が返されます。この ARN を後で Lambda 関数に設定します。&lt;/p&gt;&#10;&lt;h2 id="lambda-関数に-layer-を追加"&gt;Lambda 関数に Layer を追加&#10;&lt;/h2&gt;&lt;p&gt;Layer を作成した後、それを Lambda 関数で使用できるようにします。以下はSAMの&lt;code&gt;template.yaml&lt;/code&gt; での例です。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Globals:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Function:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; CodeUri: src&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Runtime: python3.x&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Timeout: 30&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; MemorySize: 256&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Layers:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; - arn:aws:lambda:&amp;lt;リージョン名&amp;gt;:&amp;lt;アカウントID&amp;gt;:layer:&amp;lt;Layer名&amp;gt;:&amp;lt;バージョン番号&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Environment:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Variables:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; TABLE_NAME: &amp;#34;example_table&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;&amp;lt;リージョン名&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;アカウントID&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;Layer名&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;バージョン番号&amp;gt;&lt;/code&gt; は、AWS CLI で Layer を作成した際に取得した情報を入力してください。&lt;/p&gt;&#10;&lt;h2 id="デプロイして動作確認"&gt;デプロイして動作確認&#10;&lt;/h2&gt;&lt;p&gt;Layer を Lambda 関数に追加したら、通常通りに関数をビルドしてデプロイします。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sam build&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sam deploy&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;デプロイ後、関数が正しく Layer を参照して動作しているか確認します。&lt;/p&gt;&#10;&lt;h2 id="まとめ"&gt;まとめ&#10;&lt;/h2&gt;&lt;p&gt;AWS Lambda Layers を使用することで、Lambda 関数に依存関係を簡単に管理し、ライブラリの一元管理や再利用が可能になります。特定の Git リポジトリからライブラリを取得して Layer にアップロードすることで、より柔軟な開発環境を構築できるようになります。&lt;/p&gt;&#10;</description></item><item><title>コンテナでAWS認証情報を安全に渡す方法 – 環境変数を使った手軽なアプローチ</title><link>https://ai.hack-le.com/container-aws/</link><pubDate>Sun, 08 Sep 2024 11:57:22 +0900</pubDate><guid>https://ai.hack-le.com/container-aws/</guid><description>&lt;p&gt;AWSのリソース（例：DynamoDBやSecrets Manager）を操作するアプリケーションをコンテナで実行する場合、認証情報（&lt;code&gt;AWS_ACCESS_KEY_ID&lt;/code&gt; や &lt;code&gt;AWS_SECRET_ACCESS_KEY&lt;/code&gt;）をコンテナ内にどのように渡すかが重要です。特に、手軽で一般的な方法として &lt;strong&gt;環境変数&lt;/strong&gt; を利用する方法があります。この記事では、環境変数を使った認証情報の渡し方と、その際のセキュリティ上の注意点について解説します。&lt;/p&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="環境変数を使って認証情報を渡す"&gt;環境変数を使って認証情報を渡す&#10;&lt;/h2&gt;&lt;p&gt;AWS認証情報を渡す最も簡単な方法は、環境変数を使うことです。これにより、コード内に直接認証情報をハードコードする必要がなくなります。次のようにDockerを実行する際に &lt;code&gt;-e&lt;/code&gt; オプションを使って認証情報を渡せます。&lt;/p&gt;&#10;&lt;h3 id="dockerを使った実行例"&gt;Dockerを使った実行例&#10;&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;docker run &lt;span class="se"&gt;\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -e &lt;span class="nv"&gt;AWS_ACCESS_KEY_ID&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;your_access_key_id &lt;span class="se"&gt;\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -e &lt;span class="nv"&gt;AWS_SECRET_ACCESS_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;your_secret_access_key &lt;span class="se"&gt;\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -e &lt;span class="nv"&gt;AWS_DEFAULT_REGION&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;your_region &lt;span class="se"&gt;\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; your_image_name&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;また、認証情報を &lt;code&gt;.env&lt;/code&gt; ファイルにまとめて管理することもできます。&lt;/p&gt;&#10;&lt;h3 id="env-ファイルの例"&gt;&lt;code&gt;.env&lt;/code&gt; ファイルの例&#10;&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;AWS_ACCESS_KEY_ID&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;your_access_key_id&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;AWS_SECRET_ACCESS_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;your_secret_access_key&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;AWS_DEFAULT_REGION&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;your_region&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Docker実行時にこの &lt;code&gt;.env&lt;/code&gt; ファイルを読み込ませます。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;docker run --env-file .env your_image_name&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;環境変数を使うことで、シンプルかつ手軽にAWS認証情報をコンテナに渡せますが、次のようなセキュリティに関する注意点があります。&lt;/p&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="セキュリティ上の注意点"&gt;セキュリティ上の注意点&#10;&lt;/h2&gt;&lt;p&gt;環境変数は簡単で便利な方法ですが、適切に管理しなければセキュリティリスクがあります。以下は、環境変数を使う際に意識しておきたい主なポイントです。&lt;/p&gt;&#10;&lt;h3 id="環境変数の漏洩リスク"&gt;環境変数の漏洩リスク&#10;&lt;/h3&gt;&lt;p&gt;環境変数にAWSの認証情報を設定する場合、それが &lt;strong&gt;ログに出力されないように注意&lt;/strong&gt; する必要があります。誤って認証情報がログに残ると、悪意のある第三者がアクセスできるリスクが高まります。例えば、システムやアプリケーションのログで環境変数が出力される設定になっていないか確認しましょう。&lt;/p&gt;&#10;&lt;h3 id="アクセス制御の強化"&gt;アクセス制御の強化&#10;&lt;/h3&gt;&lt;p&gt;コンテナをホストしているVPSへの &lt;strong&gt;アクセス権限を制御&lt;/strong&gt; することも非常に重要です。VPSにアクセスできるユーザーが多い場合、誰でも環境変数にアクセスできる可能性があります。SSHの鍵管理やファイルシステムの権限設定などを適切に行い、限られたユーザーだけがアクセスできるようにしましょう。&lt;/p&gt;&#10;&lt;h3 id="長期運用時の考慮"&gt;長期運用時の考慮&#10;&lt;/h3&gt;&lt;p&gt;開発環境や小規模なプロジェクトでは環境変数での管理は問題ないですが、長期的に運用する場合や規模が大きくなる場合は、IAMロールやAWSの &lt;strong&gt;セキュリティトークンサービス (STS)&lt;/strong&gt; などの高度な管理方法を検討するべきです。これにより、認証情報の自動ローテーションや、一時的なトークンの使用が可能になります。&lt;/p&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="改善ポイントセキュリティを強化する方法"&gt;改善ポイント：セキュリティを強化する方法&#10;&lt;/h2&gt;&lt;p&gt;環境変数を使う方法自体は手軽で問題ありませんが、セキュリティを向上させるために以下の対策を取ることをおすすめします。&lt;/p&gt;&#10;&lt;h3 id="env-ファイルのバージョン管理を避ける"&gt;&lt;code&gt;.env&lt;/code&gt; ファイルのバージョン管理を避ける&#10;&lt;/h3&gt;&lt;p&gt;認証情報が含まれる &lt;code&gt;.env&lt;/code&gt; ファイルは &lt;strong&gt;バージョン管理システム（例：Git）に含めない&lt;/strong&gt; ようにしましょう。&lt;code&gt;.gitignore&lt;/code&gt; に &lt;code&gt;.env&lt;/code&gt; を追加し、誤ってリポジトリにプッシュされるのを防ぐことが重要です。&lt;/p&gt;&#10;&lt;h3 id="最小権限の原則に従う"&gt;最小権限の原則に従う&#10;&lt;/h3&gt;&lt;p&gt;DynamoDBやSecrets ManagerにアクセスするためのAWSユーザーには、必要最低限の権限だけを付与しましょう。例えば、DynamoDBへの読み取りと書き込みの権限、Secrets Managerへの読み取り権限など、&lt;strong&gt;最小限のIAMポリシー&lt;/strong&gt; を設定します。&lt;/p&gt;&#10;&lt;h3 id="認証情報のローテーション"&gt;認証情報のローテーション&#10;&lt;/h3&gt;&lt;p&gt;認証情報は定期的に &lt;strong&gt;ローテーション（更新）&lt;/strong&gt; することを検討してください。長期間にわたり同じキーを使い続けると、万が一流出した際のリスクが増大します。AWSでは、IAMユーザーのアクセスキーのローテーションを簡単に設定できます。&lt;/p&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="まとめ"&gt;まとめ&#10;&lt;/h2&gt;&lt;p&gt;環境変数を使ってAWSの認証情報をコンテナに渡す方法は、特に小規模なプロジェクトや開発環境では &lt;strong&gt;手軽で一般的&lt;/strong&gt; なアプローチです。ただし、セキュリティを考慮して、環境変数が漏洩しないように管理し、アクセス権限やファイル管理を適切に行うことが重要です。また、長期的な運用環境ではIAMロールや認証情報のローテーションなど、よりセキュアな方法を導入することも検討する価値があります。&lt;/p&gt;&#10;&lt;p&gt;安全かつ効率的なAWSリソースの操作を目指して、正しい認証情報の管理を心がけましょう。&lt;/p&gt;&#10;&lt;hr&gt;&#10;&lt;h3 id="参考資料"&gt;参考資料&#10;&lt;/h3&gt;&lt;ul&gt;&#10;&lt;li&gt;&lt;a class="link" href="https://docs.aws.amazon.com/ja_jp/IAM/latest/UserGuide/access_policies_create-console.html" target="_blank" rel="noopener"&#10; &gt;AWS IAM ポリシーの作成&lt;/a&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;a class="link" href="https://docs.aws.amazon.com/ja_jp/secretsmanager/latest/userguide/intro.html" target="_blank" rel="noopener"&#10; &gt;AWS Secrets Manager の利用方法&lt;/a&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;a class="link" href="https://docs.aws.amazon.com/ja_jp/cli/latest/userguide/cli-configure-files.html" target="_blank" rel="noopener"&#10; &gt;AWS CLI 認証情報の管理&lt;/a&gt;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;</description></item><item><title>Amazon Cognitoの認証フロー解説</title><link>https://ai.hack-le.com/amazon-cognito-auth-flow/</link><pubDate>Mon, 08 Jan 2024 19:19:37 +0900</pubDate><guid>https://ai.hack-le.com/amazon-cognito-auth-flow/</guid><description>&lt;p&gt;この記事は、Cognitoの認証フローの各選択肢について解説します。また、なぜ多くのアプリケーションにおいて&lt;code&gt;ALLOW_USER_SRP_AUTH&lt;/code&gt;フローだけで十分であるのか、その理由を明確に説明することを目指します。&lt;/p&gt;&#10;&lt;h2 id="cognitoでの認証フローの種類"&gt;Cognitoでの認証フローの種類&#10;&lt;/h2&gt;&lt;p&gt;&lt;img loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://ai.hack-le.com/images/uploads/2024/01/1c1d29ba627cf54364d14c71b6218125.png"&gt;&lt;/p&gt;&#10;&lt;p&gt;Amazon Cognitoは、セキュアなユーザー管理と認証フローを実現するための多様なオプションを提供します。これにより、開発者はアプリケーションのセキュリティ要件に応じて最適な認証戦略を選択できます。Cognitoが提供する認証フローは、以下のように分類されます。&lt;/p&gt;&#10;&lt;h3 id="adminユーザーによる認証allow_admin_user_password_auth"&gt;ADMINユーザーによる認証（ALLOW_ADMIN_USER_PASSWORD_AUTH）&#10;&lt;/h3&gt;&lt;p&gt;この認証フローは、アプリケーションのバックエンドや管理者がユーザーの代わりに認証を行う場合に使用されます。例えば、新規ユーザーのアカウントをセットアップする際や、パスワードリセットのプロセス中に管理者が介入する必要がある場合などです。このフローは強力で柔軟性がありますが、管理者の権限を使うため、セキュリティ対策を十分に施す必要があります。&lt;/p&gt;&#10;&lt;h3 id="カスタム認証allow_custom_auth"&gt;カスタム認証（ALLOW_CUSTOM_AUTH）&#10;&lt;/h3&gt;&lt;p&gt;カスタム認証フローは、開発者が独自の認証シーケンスを実装したい場合に適しています。AWS Lambdaトリガーを活用して、ワンタイムパスワードやキャプチャ、二要素認証など、標準的なユーザー名とパスワードの組み合わせ以外の方法でユーザーを認証するロジックをカスタマイズできます。これは、特定のセキュリティ要件を満たすためや、ユーザーエクスペリエンスを向上させるために有効です。&lt;/p&gt;&#10;&lt;h3 id="ユーザーによるパスワード認証allow_user_password_auth"&gt;ユーザーによるパスワード認証（ALLOW_USER_PASSWORD_AUTH）&#10;&lt;/h3&gt;&lt;p&gt;ユーザーによるパスワード認証フローは、ユーザーが直接自身のユーザー名とパスワードを提供してサインインする一般的な認証方法です。このフローはシンプルで直感的なため、ユーザーには親しみやすいですが、パスワードが直接送信されるため、SRPを使用するフローと比較してセキュリティ上のリスクが高くなります。&lt;/p&gt;&#10;&lt;h3 id="srpによるユーザー認証allow_user_srp_auth"&gt;SRPによるユーザー認証（ALLOW_USER_SRP_AUTH）&#10;&lt;/h3&gt;&lt;p&gt;SRPによるユーザー認証フローは、ユーザー名とパスワードを使用しながらも、パスワードをネットワーク上で送信せずに認証する方法です。これは、セキュリティを強化しつつ、ユーザーが簡単にサインインできる方法を提供します。SRPプロトコルは、数学的な計算に基づいており、パスワードの代わりに一時的な証明を交換することで認証を行います。これにより、万が一通信が盗聴されても、パスワードが漏洩するリスクが非常に低くなります。&lt;/p&gt;&#10;&lt;h3 id="リフレッシュトークンによる認証allow_refresh_token_auth"&gt;リフレッシュトークンによる認証（ALLOW_REFRESH_TOKEN_AUTH）&#10;&lt;/h3&gt;&lt;p&gt;ユーザーが一度サインインすると、リフレッシュトークンを使用してセッションを維持し、新しいアクセストークンやIDトークンを定期的に取得できます。これは、長期間にわたるセッション管理に適しており、ユーザーが頻繁にサインインし直す必要をなくします。&lt;/p&gt;&#10;&lt;p&gt;これらの認証フローは、アプリケーションのニーズに合わせて柔軟に組み合わせることができますが、多くのシナリオでは&lt;code&gt;ALLOW_USER_SRP_AUTH&lt;/code&gt;フローだけでセキュリティと利便性のバランスを取ることが可能です。次のセクションでは、このフローがなぜ多くの場合で最適な選択であるかについて、さらに深堀りしていきます。&lt;/p&gt;&#10;&lt;h2 id="allow_user_srp_authの重要性"&gt;&lt;code&gt;ALLOW_USER_SRP_AUTH&lt;/code&gt;の重要性&#10;&lt;/h2&gt;&lt;p&gt;セキュアな認証フローを実現するためには、ユーザーの資格情報が安全であることを確保しなければなりません。&lt;code&gt;ALLOW_USER_SRP_AUTH&lt;/code&gt;は、この目的を達成するための最も効果的な手段の一つです。このフローはセキュアリモートパスワード（SRP）プロトコルを使用し、パスワードを直接ネットワーク上で交換することなく、サーバーがユーザーの身元を検証することを可能にします。結果として、セキュリティが大幅に向上し、潜在的な攻撃からユーザーのパスワードを保護します。&lt;/p&gt;&#10;&lt;h3 id="パスワード露出のリスク回避"&gt;パスワード露出のリスク回避&#10;&lt;/h3&gt;&lt;p&gt;&lt;code&gt;ALLOW_USER_PASSWORD_AUTH&lt;/code&gt;フローでは、ユーザーのパスワードがクライアントからサーバーへと明示的に送信されます。これは、中間者攻撃や、ネットワーク上でのデータの盗聴といったセキュリティの脅威に対して脆弱性を持ちます。対照的に、&lt;code&gt;ALLOW_USER_SRP_AUTH&lt;/code&gt;フローでは、パスワードに代わる一時的な証明が生成され、この証明だけが交換されます。そのため、ユーザーの実際のパスワードはサーバーや他のどのネットワーク機器にも露出することはありません。&lt;/p&gt;&#10;&lt;h3 id="セキュリティとユーザビリティのバランス"&gt;セキュリティとユーザビリティのバランス&#10;&lt;/h3&gt;&lt;p&gt;セキュリティ対策は、ユーザビリティを損なわないように慎重に行われるべきです。ユーザーにとって複雑すぎる認証プロセスは、使い勝手を低下させる原因となります。&lt;code&gt;ALLOW_USER_SRP_AUTH&lt;/code&gt;フローは、高いセキュリティを維持しつつも、エンドユーザーには通常のユーザー名とパスワードを入力するだけの簡単な手順を提供します。これにより、最終的なユーザーエクスペリエンスは向上し、セキュリティに関する知識がないユーザーでも安全にサービスを利用できます。&lt;/p&gt;&#10;&lt;h3 id="クライアントアプリケーションとの互換性"&gt;クライアントアプリケーションとの互換性&#10;&lt;/h3&gt;&lt;p&gt;&lt;code&gt;ALLOW_USER_SRP_AUTH&lt;/code&gt;フローは、多くのクライアントライブラリやフレームワークでサポートされており、開発者は追加の労力をかけずにこの認証フローを実装できます。AWSのSDKなどのツールは、このプロトコルを直接扱うことができるため、開発者はセキュリティの複雑さを理解しなくても、安全な認証システムを構築できます。&lt;/p&gt;&#10;&lt;p&gt;総合すると、&lt;code&gt;ALLOW_USER_SRP_AUTH&lt;/code&gt;フローは、高いセキュリティ基準と優れたユーザーエクスペリエンスの両方を提供します。クライアントアプリケーションにとって、このフローはセキュアな認証プロセスを簡単に実装するための鍵となるため、多くの一般的な使用シナリオで推奨される選択肢です。多くの一般的なクライアントアプリケーションでは、&lt;code&gt;ALLOW_USER_SRP_AUTH&lt;/code&gt;認証フローだけでユーザー認証の要件を満たすことができます。&lt;/p&gt;&#10;&lt;p&gt;セキュリティのベストプラクティスとして、最小限の必要権限でシステムを運用することが推奨されます。&lt;code&gt;ALLOW_USER_SRP_AUTH&lt;/code&gt;はこの原則に沿っており、最小限の認証情報のみを使用して最大限のセキュリティを提供します。これにより、不要なセキュリティリスクを排除し、アプリケーションの攻撃面を最小限に抑えることができます。&lt;/p&gt;&#10;&lt;h2 id="認証フローの実装ガイド"&gt;認証フローの実装ガイド&#10;&lt;/h2&gt;&lt;p&gt;&lt;code&gt;ALLOW_USER_SRP_AUTH&lt;/code&gt; フローを利用した実装は、セキュリティを重視しながらもユーザーフレンドリーなアプリケーションを構築する上で重要です。このセクションでは、具体的な実装ステップとベストプラクティスを提供します。&lt;/p&gt;&#10;&lt;h3 id="実装の前提条件と準備"&gt;実装の前提条件と準備&#10;&lt;/h3&gt;&lt;p&gt;&lt;code&gt;ALLOW_USER_SRP_AUTH&lt;/code&gt; フローを実装する前に、以下の前提条件と準備が必要です：&lt;/p&gt;&#10;&lt;ol&gt;&#10;&lt;li&gt;&lt;strong&gt;AWS Cognito User Poolの設定&lt;/strong&gt;: AWS Cognito User Poolを設定し、アプリケーションクライアントIDを取得します。これは、ユーザー認証時にCognitoとの通信に使用されます。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;適切なAWS SDKの選択&lt;/strong&gt;: AWS SDK（たとえば、AWS SDK for JavaScript、Boto3 for Pythonなど）を選択し、プロジェクトに組み込みます。これらのSDKは、SRP認証フローをサポートしており、実装を容易にします。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;セキュリティの構成&lt;/strong&gt;: HTTPS通信を確保し、エンドポイントのセキュリティを強化します。これにより、データのプライバシーと完全性が保たれます。&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;h3 id="allow_user_srp_authを使用した認証プロセスのコード例"&gt;&lt;code&gt;ALLOW_USER_SRP_AUTH&lt;/code&gt;を使用した認証プロセスのコード例&#10;&lt;/h3&gt;&lt;p&gt;以下に、JavaScriptを使用したAWS CognitoとのSRP認証プロセスの基本的なコード例を示します。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;AmazonCognitoIdentity&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;amazon-cognito-identity-js&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;AWS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;aws-sdk&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;poolData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;UserPoolId&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;ap-northeast-1_Example&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// Cognito User Pool ID&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;ClientId&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;exampleclientid&amp;#39;&lt;/span&gt; &lt;span class="c1"&gt;// Cognito User Pool Client ID&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;};&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;userPool&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;AmazonCognitoIdentity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;CognitoUserPool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;poolData&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;authenticationData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;Username&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;username&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;Password&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;password&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;};&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;authenticationDetails&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;AmazonCognitoIdentity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;AuthenticationDetails&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;authenticationData&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;userData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;Username&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;username&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;Pool&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;userPool&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;};&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cognitoUser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;AmazonCognitoIdentity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;CognitoUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userData&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;cognitoUser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;authenticateUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;authenticationDetails&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;onSuccess&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;session&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Authentication successful!&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;session&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;},&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;onFailure&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Authentication failed:&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;});&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;このコードは、ユーザーがユーザー名とパスワードを提供してサインインする基本的なシナリオを実装しています。成功時にはセッション情報が取得され、失敗時にはエラーが報告されます。&lt;/p&gt;&#10;&lt;h3 id="ベストプラクティスとデバッグのヒント"&gt;ベストプラクティスとデバッグのヒント&#10;&lt;/h3&gt;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;エラーハンドリングの実装&lt;/strong&gt;: 認証プロセス中に発生する可能性のあるエラーを適切に処理し、ユーザーにわかりやすいフィードバックを提供します。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;セキュリティの監査とテスト&lt;/strong&gt;: アプリケーションのセキュリティを定期的に監査し、脆弱性テストを実施して、セキュリティの弱点を特定し対処します。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;ログの活用&lt;/strong&gt;: 認証プロセスにおける詳細なログを記録し、問題発生時の迅速なトラブルシューティングに役立てます。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;&lt;code&gt;ALLOW_USER_SRP_AUTH&lt;/code&gt; フローの実装は、セキュアなユーザー認証を提供するための基礎を形成します。このフローを適切に利用することで、ユーザーの安全を保ちながら、優れたユーザーエクスペリエンスを提供するアプリケーションを構築できます。次のセクションでは、これまでの内容をまとめ、認証フローの選択がアプリケーションに与える影響について総括します。&lt;/p&gt;&#10;&lt;h2 id="まとめ"&gt;まとめ&#10;&lt;/h2&gt;&lt;p&gt;この記事では、Amazon Cognitoの認証フローについて深く掘り下げ、特に&lt;code&gt;ALLOW_USER_SRP_AUTH&lt;/code&gt;フローが多くのアプリケーションにとってなぜ最適な選択肢であるかを詳細に説明しました。このフローは、セキュリティとユーザビリティのバランスを最適化し、開発者にとっても容易に実装可能な選択肢です。&lt;/p&gt;&#10;&lt;h3 id="認証フロー選択の意思決定プロセス"&gt;認証フロー選択の意思決定プロセス&#10;&lt;/h3&gt;&lt;p&gt;認証フローの選択は、アプリケーションのセキュリティ要件、ユーザーエクスペリエンス、開発の容易さを考慮して行うべきです。&lt;code&gt;ALLOW_USER_SRP_AUTH&lt;/code&gt;は、これらの要素をバランス良く兼ね備えているため、一般的なアプリケーション開発において最適な選択となることが多いです。ただし、特定のケースでは他の認証フローやカスタム認証が必要になることもあります。&lt;/p&gt;&#10;&lt;h3 id="セキュリティを維持しながらのユーザーエクスペリエンスの最適化"&gt;セキュリティを維持しながらのユーザーエクスペリエンスの最適化&#10;&lt;/h3&gt;&lt;p&gt;ユーザーが直感的に利用できる安全な認証システムは、アプリケーションの成功において重要な要素です。&lt;code&gt;ALLOW_USER_SRP_AUTH&lt;/code&gt;フローは、ユーザーに対して簡単かつ安全なサインインプロセスを提供し、同時にデータ保護の最高基準を満たします。&lt;/p&gt;&#10;&lt;h3 id="認証フローの今後の展望"&gt;認証フローの今後の展望&#10;&lt;/h3&gt;&lt;p&gt;セキュリティ技術の進化に伴い、認証フローの選択肢も変化していきます。Cognitoのようなサービスは継続的にアップデートされ、新しいセキュリティ機能やユーザビリティ向上のためのオプションが提供されることが予想されます。そのため、開発者は常に最新のセキュリティトレンドとベストプラクティスに注意を払い、アプリケーションのセキュリティを維持する必要があります。&lt;/p&gt;&#10;&lt;p&gt;認証フローの選択は、アプリケーションのセキュリティとユーザーエクスペリエンスに大きな影響を与えます。&lt;code&gt;ALLOW_USER_SRP_AUTH&lt;/code&gt;フローは多くの場合に最適な選択ですが、プロジェクトの特定の要件に基づいて最終的な決定を行うことが重要です。この記事が、Cognitoの認証フローに関する理解を深め、適切な選択を行うためのガイドとなれば幸いです。&lt;/p&gt;&#10;</description></item><item><title>direnvを活用したAWSアカウントの自動切り替え方法</title><link>https://ai.hack-le.com/direnv-aws/</link><pubDate>Sun, 10 Dec 2023 00:39:39 +0900</pubDate><guid>https://ai.hack-le.com/direnv-aws/</guid><description>&lt;p&gt;クラウドリソースを頻繁に使用する場合、異なるプロジェクトやクライアントごとに異なるAWSアカウントを切り替える必要があることは珍しくありません。この記事では、開発環境におけるAWSアカウントの自動切り替えを実現するために&lt;code&gt;direnv&lt;/code&gt;というツールの使用方法に焦点を当てます。&lt;/p&gt;&#10;&lt;p&gt;&lt;code&gt;direnv&lt;/code&gt;は、シェル環境においてディレクトリごとに環境変数を自動で切り替えることができる非常に便利なツールです。これにより、プロジェクトや作業環境に応じて、AWSプロファイルや他の環境設定を簡単に切り替えることが可能になります。この記事では、&lt;code&gt;direnv&lt;/code&gt;の基本的なインストール方法から、AWSアカウントの切り替え設定までをステップバイステップで説明していきます。&lt;/p&gt;&#10;&lt;h2 id="direnvのインストールと設定"&gt;direnvのインストールと設定&#10;&lt;/h2&gt;&lt;p&gt;開発環境のカスタマイズにおいて、&lt;code&gt;direnv&lt;/code&gt;は非常に重要なツールの一つです。&lt;code&gt;direnv&lt;/code&gt;を使用すると、異なるディレクトリに移動した際に自動的に環境変数を切り替えることができ、特に複数のAWSアカウントを使い分ける際に大いに役立ちます。ここでは、&lt;code&gt;direnv&lt;/code&gt;のインストールと基本的な設定方法について説明します。&lt;/p&gt;&#10;&lt;h3 id="direnvのインストール"&gt;direnvのインストール&#10;&lt;/h3&gt;&lt;p&gt;&lt;code&gt;direnv&lt;/code&gt;は多くのUnix系オペレーティングシステムで利用可能です。以下は、主要なOSにおける&lt;code&gt;direnv&lt;/code&gt;のインストール方法です：&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;macOS&lt;/strong&gt;: Homebrewを使用して簡単にインストールできます。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;brew install direnv&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;Ubuntu/Debian&lt;/strong&gt;: aptパッケージマネージャを利用します。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo apt-get install direnv&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;Fedora&lt;/strong&gt;: dnfを使用してインストールします。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo dnf install direnv&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="シェルにdirenvをフックする"&gt;シェルにdirenvをフックする&#10;&lt;/h3&gt;&lt;p&gt;インストール後、&lt;code&gt;direnv&lt;/code&gt;を使用するためにはシェルにフックする必要があります。これは、使用しているシェルの設定ファイルに特定の行を追加することで行います。以下は、いくつかの一般的なシェルの設定方法です：&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;Bash (&lt;code&gt;.bashrc&lt;/code&gt; or &lt;code&gt;.bash_profile&lt;/code&gt;)&lt;/strong&gt; :&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;eval&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;direnv hook bash&lt;span class="k"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;Zsh (&lt;code&gt;.zshrc&lt;/code&gt;)&lt;/strong&gt; :&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;eval&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;direnv hook zsh&lt;span class="k"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;Fish (&lt;code&gt;.config/fish/config.fish&lt;/code&gt;)&lt;/strong&gt; :&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;eval&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;direnv hook fish&lt;span class="o"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;これらの設定を適用した後、シェルを再起動するか、新しいターミナルウィンドウを開いて設定を有効にします。&lt;/p&gt;&#10;&lt;h3 id="基本的な使用法"&gt;基本的な使用法&#10;&lt;/h3&gt;&lt;p&gt;&lt;code&gt;direnv&lt;/code&gt;を使うための最初のステップは、環境変数や設定を含む&lt;code&gt;.envrc&lt;/code&gt;ファイルを作成することです。このファイルは、特定のディレクトリに配置され、&lt;code&gt;direnv&lt;/code&gt;によって自動的に読み込まれます。&lt;code&gt;.envrc&lt;/code&gt;ファイルには、AWSプロファイルの設定や他の必要な環境変数を指定できます。&lt;/p&gt;&#10;&lt;p&gt;セキュリティ上の理由から、新しい&lt;code&gt;.envrc&lt;/code&gt;ファイルは&lt;code&gt;direnv&lt;/code&gt;によってデフォルトで無視されます。ファイルを承認するためには、次のコマンドを使用します：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;direnv allow .&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;このコマンドは、&lt;code&gt;.envrc&lt;/code&gt;ファイルが安全であることを&lt;code&gt;direnv&lt;/code&gt;に伝え、そのディレクトリでの変更を有効にします。&lt;/p&gt;&#10;&lt;h2 id="direnvを使用したawsアカウントの実践例とトラブルシューティング"&gt;direnvを使用したAWSアカウントの実践例とトラブルシューティング&#10;&lt;/h2&gt;&lt;p&gt;&lt;code&gt;direnv&lt;/code&gt;を活用することで、AWSアカウントの切り替えをスムーズに行うことができます。このセクションでは、実際の使用例と一般的な問題の解決方法について説明します。&lt;/p&gt;&#10;&lt;h3 id="実際の使用例"&gt;実際の使用例&#10;&lt;/h3&gt;&lt;p&gt;想定するシナリオは、異なるAWSアカウントを使用する複数のプロジェクトに取り組んでいる状況です。それぞれのプロジェクトディレクトリに&lt;code&gt;.envrc&lt;/code&gt;ファイルを作成し、適切なAWSプロファイル名を設定します。&lt;/p&gt;&#10;&lt;p&gt;例えば、プロジェクトAとプロジェクトBがあり、それぞれ異なるAWSアカウントを使用するとします。プロジェクトAのディレクトリの&lt;code&gt;.envrc&lt;/code&gt;には以下のように書きます：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;export&lt;/span&gt; &lt;span class="nv"&gt;AWS_PROFILE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;projectA-profile&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;同様に、プロジェクトBの&lt;code&gt;.envrc&lt;/code&gt;には：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;export&lt;/span&gt; &lt;span class="nv"&gt;AWS_PROFILE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;projectB-profile&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;これにより、各プロジェクトディレクトリに移動するだけで、&lt;code&gt;direnv&lt;/code&gt;が自動的にAWSプロファイルを適切なものに切り替えます。&lt;/p&gt;&#10;&lt;h3 id="トラブルシューティングのヒント"&gt;トラブルシューティングのヒント&#10;&lt;/h3&gt;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;問題：&lt;code&gt;.envrc&lt;/code&gt;が読み込まれない&lt;/strong&gt;&lt;/li&gt;&#10;&lt;li&gt;解決策：&lt;code&gt;direnv allow&lt;/code&gt;コマンドを使用して、&lt;code&gt;.envrc&lt;/code&gt;ファイルを承認します。また、シェルの設定ファイル（例：&lt;code&gt;.bashrc&lt;/code&gt;、&lt;code&gt;.zshrc&lt;/code&gt;、&lt;code&gt;.config/fish/config.fish&lt;/code&gt;）で&lt;code&gt;direnv&lt;/code&gt;が正しくフックされていることを確認してください。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;問題：AWSプロファイルが切り替わらない&lt;/strong&gt;&lt;/li&gt;&#10;&lt;li&gt;解決策：&lt;code&gt;AWS_PROFILE&lt;/code&gt;変数が正しく設定されているか確認します。また、AWS CLIがインストールされていること、および&lt;code&gt;~/.aws/credentials&lt;/code&gt;と&lt;code&gt;~/.aws/config&lt;/code&gt;に正しい認証情報が設定されていることを確認してください。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;問題：セキュリティ上の懸念&lt;/strong&gt;&lt;/li&gt;&#10;&lt;li&gt;解決策：&lt;code&gt;.envrc&lt;/code&gt;ファイルに機密情報（例：アクセスキー、シークレットキー）を直接書かないようにします。代わりに、プロファイル名のみを使用し、認証情報は&lt;code&gt;~/.aws/credentials&lt;/code&gt;に安全に保存します。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="まとめ"&gt;まとめ&#10;&lt;/h2&gt;&lt;p&gt;&lt;code&gt;direnv&lt;/code&gt;を使用したAWSプロファイルの自動切り替えの方法について詳しく説明しました。この手法は、複数のAWSアカウントを扱う際の生産性を高め、エラーの可能性を減らすのに役立ちます。&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;主なポイントの再確認&lt;/strong&gt;:&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;direnv&lt;/code&gt;をインストールし、シェルにフックする。&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;.envrc&lt;/code&gt;ファイルを使用して、ディレクトリごとに異なるAWSプロファイルを設定する。&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;direnv allow&lt;/code&gt;を実行して、新しい&lt;code&gt;.envrc&lt;/code&gt;ファイルを承認する。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;応用例&lt;/strong&gt;: この手法はAWSプロファイルに限らず、他の環境変数や設定（例えば、データベース接続設定やAPIキー）の管理にも応用できます。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;セキュリティ上の注意&lt;/strong&gt;: &lt;code&gt;.envrc&lt;/code&gt;ファイルに機密情報を直接記述することは避け、安全な方法で認証情報を管理することが重要です。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;参考記事&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;direnv公式ドキュメント&lt;/strong&gt;: &lt;a class="link" href="https://direnv.net/" target="_blank" rel="noopener"&#10; &gt;direnv公式ウェブサイト&lt;/a&gt;には、インストール方法、使用方法、さまざまな設定オプションに関する詳細情報があります。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;AWS CLI公式ドキュメント&lt;/strong&gt;: AWS CLIの使用方法に関する詳細情報は、&lt;a class="link" href="https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-profiles.html" target="_blank" rel="noopener"&#10; &gt;AWS公式ドキュメント&lt;/a&gt;で提供されています。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;関連ブログ記事やフォーラム&lt;/strong&gt;: コミュニティの経験やベストプラクティスを共有する多くのブログ記事やフォーラムが存在します。これらは、具体的なシナリオや高度な使用例を理解するのに役立つかもしれません。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;</description></item><item><title>DynamoDBでデータを自動削除：TTL設定のステップバイステップ</title><link>https://ai.hack-le.com/dynamodb-ttl/</link><pubDate>Tue, 28 Nov 2023 00:06:37 +0900</pubDate><guid>https://ai.hack-le.com/dynamodb-ttl/</guid><description>&lt;p&gt;現代のアプリケーション開発において、迅速かつ効率的なデータ管理は不可欠です。Amazon DynamoDBは、そのようなニーズを満たすために開発されたNoSQLデータベースサービスです。DynamoDBは、高い可用性と拡張性を提供し、大量のデータを素早く処理する能力があります。これにより、開発者はアプリケーションのパフォーマンスを最適化し、よりスムーズなユーザー体験を提供することができます。&lt;/p&gt;&#10;&lt;p&gt;この記事では、&lt;strong&gt;データが自動的に削除されるべき時点を定義する機能であるTTL（Time To Live）を利用し、DynamoDBで有効期限のあるデータを効率的に扱う方法&lt;/strong&gt;について掘り下げていきます。&lt;/p&gt;&#10;&lt;h2 id="ttlとは何か"&gt;TTLとは何か？&#10;&lt;/h2&gt;&lt;p&gt;&lt;strong&gt;「Time To Live」（TTL）は、データがデータベース内で生存する時間の長さを指します&lt;/strong&gt;。具体的には、データ項目に設定された特定の時間が経過すると、そのデータは自動的にデータベースから削除されます。この時間は、通常、UNIXタイムスタンプ形式で指定されます。&lt;/p&gt;&#10;&lt;p&gt;TTLは、DynamoDBのようなNoSQLデータベース管理システムで特に有用です。これにより、データのライフサイクルを自動的に管理し、データベースのサイズとコストを効率的に管理することが可能になります。&lt;/p&gt;&#10;&lt;p&gt;TTL機能を活用することで、以下のような多くの利点があります。&lt;/p&gt;&#10;&lt;ol&gt;&#10;&lt;li&gt;&lt;strong&gt;自動的なデータのクリーンアップ&lt;/strong&gt;: DynamoDBでは、TTLを設定することで、期限切れのデータを自動的に削除し、データの整合性を保つことができます。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;ストレージコストの削減&lt;/strong&gt;: 不要なデータを自動的に削除することで、ストレージの使用量を減らし、コストを節約できます。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;セキュリティリスクの軽減&lt;/strong&gt;: 古いデータや期限切れのデータはセキュリティリスクを引き起こす可能性があります。これらを自動的に削除することで、リスクを減少させることができます。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;システムパフォーマンスの最適化&lt;/strong&gt;: 不要なデータを削除することで、データベースの応答性とパフォーマンスが向上します。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;コンプライアンスのサポート&lt;/strong&gt;: 特定の業界規制では、データの保持期間に厳格な制限がある場合があります。TTLを用いることで、これらの規制要件を自動的に満たすことが可能になります。&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;h2 id="dynamodbにおけるttlの利用方法"&gt;DynamoDBにおけるTTLの利用方法&#10;&lt;/h2&gt;&lt;p&gt;DynamoDBでTTLを設定するプロセスは、シンプルかつ直感的です。主なステップは以下の通りです。&lt;/p&gt;&#10;&lt;ol&gt;&#10;&lt;li&gt;&lt;strong&gt;TTL属性の選択&lt;/strong&gt;:&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;DynamoDBのテーブルには、TTLのための特定の属性（列）が必要です。これは、各アイテムがどのタイミングで削除されるべきかを示すUNIXエポックタイムスタンプを格納します。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;ol&gt;&#10;&lt;li&gt;&lt;strong&gt;AWSコンソールでのTTL設定&lt;/strong&gt;:&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;AWSマネジメントコンソールを使用して、TTLを有効にします。テーブルを選択し、TTL属性を指定して、TTLを有効化するオプションを選びます。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;ol&gt;&#10;&lt;li&gt;&lt;strong&gt;TTL値の設定&lt;/strong&gt;:&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;新しいアイテムをテーブルに追加する際、または既存のアイテムを更新する際に、TTL属性にUNIXタイムスタンプを設定します。このタイムスタンプは、アイテムが自動的に削除されるべき時刻を表します。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;TTL属性の設定は、アイテムの追加や更新時に行われます。例えば、セッションデータや一時的なトークンなど、一定期間後に自動的に削除したいデータに対して効果的です。&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;例&lt;/strong&gt;: セッションが1時間後に期限切れになるように設定する場合、TTL属性には現在のUNIXタイムスタンプに3600秒（1時間）を加えた値を設定します。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h2 id="ttlの実践的な使用例"&gt;TTLの実践的な使用例&#10;&lt;/h2&gt;&lt;p&gt;DynamoDBのTTL機能は、多くの実用的なシナリオで有効です。ここでは、特に一般的な使用例としてセッション管理とトークン管理を取り上げます。&lt;/p&gt;&#10;&lt;h3 id="セッション管理"&gt;セッション管理&#10;&lt;/h3&gt;&lt;p&gt;ウェブアプリケーションやモバイルアプリケーションでは、ユーザーのセッション情報を管理する必要があります。セッションは、特定の期間の活動後に期限切れになるべきです。DynamoDBのTTLを利用して、期限切れのセッションデータを自動的に削除することで、セキュリティを強化し、データの整理を効率的に行うことができます。&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;例&lt;/strong&gt;: ユーザーがログインすると、セッションデータがDynamoDBに保存され、TTL属性には現在時刻から数時間後のタイムスタンプが設定されます。この期間が経過すると、セッションデータは自動的に削除されます。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h3 id="トークン管理"&gt;トークン管理&#10;&lt;/h3&gt;&lt;p&gt;APIトークンや一時的な認証コードなど、一定期間後に無効化されるべきトークンも、TTLを利用して管理することができます。これにより、期限切れのトークンがシステム内に残らないようにし、セキュリティを向上させることが可能です。&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;例&lt;/strong&gt;: ユーザーがパスワードリセットを要求すると、一時的な認証コードが生成され、TTL属性には短い期限（例えば30分後）が設定されます。この期限が経過すると、認証コードは自動的に削除されます。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h3 id="期限切れデータの自動削除"&gt;期限切れデータの自動削除&#10;&lt;/h3&gt;&lt;p&gt;TTLは、特に期限が設定されたデータ（例えば、プロモーション情報やイベント情報）に有効です。イベントが終了したり、プロモーションが終了した後に自動的にデータを削除することで、データの整合性を保ち、不要なデータの蓄積を防ぐことができます。&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;例&lt;/strong&gt;: 特定のイベントに関連するデータには、イベント終了日のタイムスタンプがTTL属性として設定されます。イベント終了後、これらのデータは自動的に削除されます。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h2 id="ttlの使用時に考慮すべき点"&gt;TTLの使用時に考慮すべき点&#10;&lt;/h2&gt;&lt;p&gt;DynamoDBでのTTL機能の使用は、多くの利点を提供しますが、その実装と管理には注意が必要です。以下に、TTLを使用する際に考慮すべきいくつかの重要な点を挙げます。&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;適切なタイムスタンプの使用&lt;/strong&gt;: TTL属性に設定されるUNIXタイムスタンプは正確でなければなりません。誤ったタイムスタンプは、データの早すぎる削除や予定された削除の遅延を引き起こす可能性があります。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;非同期的な削除&lt;/strong&gt;: TTLによる削除は非同期で行われるため、設定された時刻を過ぎた直後にアイテムが削除されるわけではありません。この遅延は、アプリケーションのロジックに影響を与える可能性があります。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;パフォーマンスへの影響&lt;/strong&gt;: 大量のアイテムが同時に削除される場合、一時的にテーブルのパフォーマンスに影響を与える可能性があります。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;コスト削減&lt;/strong&gt;: 不要なデータを削除することでストレージコストを削減できますが、TTL設定自体の管理にもリソースが必要です。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h2 id="ttlの最適な活用法"&gt;TTLの最適な活用法&#10;&lt;/h2&gt;&lt;p&gt;DynamoDBのTTL機能を最大限に活用するためには、戦略的なアプローチが必要です。以下に、TTLを効果的に使用するためのベストプラクティスを紹介します。&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;データの種類と重要性の評価&lt;/strong&gt;: データの種類によって、その保持期間は異なります。例えば、セッションデータや一時的なトークンは短期間で削除するのが適していますが、顧客情報や取引記録は長期間保持する必要があるかもしれません。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;ビジネス要件と規制の遵守&lt;/strong&gt;: ビジネスの要件と規制上の要件に基づいてTTLポリシーを設定します。これにより、データの整合性とコンプライアンスを確保できます。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;複雑なロジックの適用&lt;/strong&gt;: すべてのデータがTTLによる単純な削除ルールに適合しない場合、バッチ処理を利用してより複雑な削除ロジックを適用することができます。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;非同期処理の活用&lt;/strong&gt;: バッチ処理を非同期で実行し、データベースのパフォーマンスに与える影響を最小限に抑えることが重要です。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;パフォーマンスへの影響のモニタリング&lt;/strong&gt;: TTLによる削除操作がテーブルのパフォーマンスに与える影響を定期的にモニタリングし、必要に応じて調整します。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;負荷の分散&lt;/strong&gt;: 削除操作がテーブルに集中することを避けるために、負荷を分散させる戦略を検討します。これには、データの分割や異なるテーブルへの配置が含まれます。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h2 id="まとめ"&gt;まとめ&#10;&lt;/h2&gt;&lt;p&gt;DynamoDBのTTL機能は、データのライフサイクル管理を自動化し、ストレージコストを削減し、セキュリティを強化するための強力なツールです。適切に設定され、効果的に管理されたTTLは、データベースの整理と最適化に大きな貢献をします。しかし、その利用には、ビジネスの要件、データの種類、およびセキュリティとコンプライアンスの要件を考慮する必要があります。戦略的なアプローチをとることで、TTLはDynamoDBを使用するアプリケーションの効率を大幅に向上させることができます。&lt;/p&gt;&#10;</description></item><item><title>AWS AppSync + DynamoDB（複合キーテーブル）の自動生成されたリゾルバによるアイテム削除が失敗した時の対応</title><link>https://ai.hack-le.com/aws-appsync-dynamodb/</link><pubDate>Fri, 24 Nov 2023 00:02:18 +0900</pubDate><guid>https://ai.hack-le.com/aws-appsync-dynamodb/</guid><description>&lt;p&gt;端的に言うと、AppSync + DynamoDBで自動生成されたリゾルバを使ってデータ削除しようとしたら、次のエラーが出た時の対応です。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt;&amp;#34;The variables input contains a field that is not defined for input object type &amp;#39;DeleteHogeHoge&amp;#39; &amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;結論的には、DynamoDBのソートキーが無視されたリゾルバになっていました。&lt;/p&gt;&#10;&lt;h2 id="はじめに"&gt;はじめに&#10;&lt;/h2&gt;&lt;p&gt;AWS Amplifyは、Webおよびモバイルアプリケーションの開発を迅速化するためのツールセットです。Amplifyを使用すると、認証、データストレージ、APIなどの機能を簡単に実装できます。特に、GraphQL APIの作成とデプロイに関しては、AWS AppSyncが強力な支援を提供します。&lt;/p&gt;&#10;&lt;p&gt;AWS AppSyncは、開発者が効率的にGraphQL APIを構築し、管理できるように設計されたフルマネージドサービスです。AppSyncは、データのリアルタイム同期やオフラインデータアクセスなど、複雑なデータ操作を簡単に処理できることで知られています。&lt;/p&gt;&#10;&lt;p&gt;しかし、これらのツールは自動化されたプロセスに頼っているため、特定のデータモデルやユースケースに対する細かいカスタマイズが必要な場合、問題が生じることがあります。私が直面した問題は、AWS Amplifyが提供する自動コード生成機能と、DynamoDBの複合プライマリキーを使用したテーブル設計の間の整合性に関するものでした。&lt;/p&gt;&#10;&lt;h2 id="appsyncとdynamodbの基本"&gt;AppSyncとDynamoDBの基本&#10;&lt;/h2&gt;&lt;p&gt;AWS AppSyncとDynamoDBは、AWSエコシステムの中で重要な位置を占めています。これらのサービスを理解することは、モダンなクラウドベースのアプリケーション開発において不可欠です。&lt;/p&gt;&#10;&lt;h3 id="aws-appsync"&gt;AWS AppSync&#10;&lt;/h3&gt;&lt;p&gt;AWS AppSyncは、データ駆動型のアプリケーションにおいてリアルタイムのデータ同期と通信を容易にするマネージドGraphQLサービスです。AppSyncを使用すると、フロントエンド開発者はバックエンドの複雑さを意識せずに、必要なデータを簡単に取得、変更、購読することができます。&lt;/p&gt;&#10;&lt;p&gt;GraphQLスキーマを定義することで、AppSyncはそのスキーマに基づいてAPIを生成します。例えば、本のデータモデルに対する簡単なGraphQLスキーマは次のようになります：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;type&lt;/span&gt; &lt;span class="n"&gt;Book&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;book_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ID&lt;/span&gt;&lt;span class="err"&gt;!&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;String&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;author&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;String&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;...&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;type&lt;/span&gt; &lt;span class="n"&gt;Query&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;getBook&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;book_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ID&lt;/span&gt;&lt;span class="err"&gt;!&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="n"&gt;Book&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;listBooks&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Book&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;type&lt;/span&gt; &lt;span class="n"&gt;Mutation&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;addBook&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;book&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;BookInput&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="n"&gt;Book&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;deleteBook&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;book_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ID&lt;/span&gt;&lt;span class="err"&gt;!&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="n"&gt;Book&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="dynamodb"&gt;DynamoDB&#10;&lt;/h3&gt;&lt;p&gt;DynamoDBは、高速かつ柔軟なNoSQLデータベースサービスで、キー-バリューおよびドキュメントデータモデルをサポートしています。DynamoDBは、パーティションキーとソートキーを組み合わせた複合プライマリキーを使ってデータをユニークに識別します。&lt;/p&gt;&#10;&lt;p&gt;例えば、本の情報を格納するDynamoDBテーブルの設計は次のようになります：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;TableName&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;Books&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;KeySchema&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;AttributeName&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;user_id&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;KeyType&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;HASH&amp;#34;&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="o"&gt;//&lt;/span&gt; &lt;span class="n"&gt;パーティションキー&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;AttributeName&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;book_id&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;KeyType&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;RANGE&amp;#34;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;//&lt;/span&gt; &lt;span class="n"&gt;ソートキー&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;],&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;...&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;ここでの問題は、AppSyncが自動的に生成するリゾルバがこの複合キー構造を正しく扱っていないことでした。次のセクションでは、この問題がどのように発生し、どのようにしてそれに気づいたのかを詳しく説明します。&lt;/p&gt;&#10;&lt;h2 id="問題の発生"&gt;問題の発生&#10;&lt;/h2&gt;&lt;p&gt;プロジェクトの進行中に、AWS AppSyncとDynamoDBを使用してデータの保存と取得を行っていましたが、特定の操作で予期せぬ問題に直面しました。&lt;/p&gt;&#10;&lt;h3 id="自動生成されたリゾルバの問題"&gt;自動生成されたリゾルバの問題&#10;&lt;/h3&gt;&lt;p&gt;AWS AppSyncは、GraphQLスキーマに基づいてAPIを生成し、さらにDynamoDBテーブルとの間でデータを操作するためのリゾルバを自動生成します。私のプロジェクトでは、&lt;code&gt;user_id&lt;/code&gt; と &lt;code&gt;book_id&lt;/code&gt; を複合キーとするDynamoDBテーブルを用意していました。通常、このようなテーブル設計では、両方のキーを使用してデータを操作することが期待されます。&lt;/p&gt;&#10;&lt;p&gt;しかし、AppSyncが生成した削除操作のリゾルバは、&lt;code&gt;book_id&lt;/code&gt; を無視し、&lt;code&gt;user_id&lt;/code&gt; のみを使用してデータを削除しようとしていました。このため、期待通りにデータを削除できず、エラーが発生していました。&lt;/p&gt;&#10;&lt;h3 id="コードによる問題の特定"&gt;コードによる問題の特定&#10;&lt;/h3&gt;&lt;p&gt;この問題に気づいたのは、削除操作を試行した際にエラーが発生し、データが削除されなかったことからでした。エラーメッセージを解析した結果、DynamoDBからのレスポンスが「提供されたキーエレメントがスキーマと一致しない」という内容であることを突き止めました。&lt;/p&gt;&#10;&lt;p&gt;AWS AppSyncのコンソールにアクセスし、リゾルバのコードを確認したところ、自動生成されたリゾルバが以下のようになっていることがわかりました：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;/&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;Deletes&lt;/span&gt; &lt;span class="nx"&gt;an&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="kd"&gt;with&lt;/span&gt; &lt;span class="nx"&gt;user_Id&lt;/span&gt; &lt;span class="sb"&gt;`ctx.args.input.user_Id`&lt;/span&gt; &lt;span class="nx"&gt;from&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;DynamoDB&lt;/span&gt; &lt;span class="nx"&gt;table&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="nx"&gt;param&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="kr"&gt;import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;@aws-appsync/utils&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;Context&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;user_id&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;unknown&lt;/span&gt;&lt;span class="p"&gt;;}}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nx"&gt;ctx&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="nx"&gt;returns&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="kr"&gt;import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;@aws-appsync/utils&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;DynamoDBDeleteItemRequest&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="err"&gt;/&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;user_id&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;operation&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;DeleteItem&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;util&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dynamodb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;toMapValues&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;user_id&lt;/span&gt; &lt;span class="p"&gt;}),&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;このリゾルバは、&lt;code&gt;book_id&lt;/code&gt; を考慮せずに &lt;code&gt;user_id&lt;/code&gt; のみを使用しているため、複合キーを持つテーブルで適切な削除操作を行うことができませんでした。&lt;/p&gt;&#10;&lt;p&gt;次のセクションでは、この問題をどのように分析し、解決策をどのように導き出したかを詳しく説明します。&lt;/p&gt;&#10;&lt;p&gt;もちろんです。以下は、「問題の解析と解決策」セクションの詳細な文章です。&lt;/p&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="問題の解析と解決策"&gt;問題の解析と解決策&#10;&lt;/h2&gt;&lt;h3 id="問題の根本的な原因"&gt;問題の根本的な原因&#10;&lt;/h3&gt;&lt;p&gt;エラーメッセージの分析から、問題の根本原因がAppSyncの自動生成リゾルバにあることが明らかになりました。AppSyncは、スキーマ定義に基づいて削除操作のリゾルバを生成する際、DynamoDBテーブルの複合キー（&lt;code&gt;user_id&lt;/code&gt; と &lt;code&gt;book_id&lt;/code&gt;）を正しく扱っていませんでした。リゾルバは &lt;code&gt;user_id&lt;/code&gt; のみを使用して削除を試み、&lt;code&gt;book_id&lt;/code&gt; を完全に無視していました。&lt;/p&gt;&#10;&lt;h3 id="リゾルバの手動修正"&gt;リゾルバの手動修正&#10;&lt;/h3&gt;&lt;p&gt;この問題に対処するためには、リゾルバを手動で修正し、DynamoDBのテーブルキー構造に合わせる必要がありました。具体的には、リゾルバのリクエストマッピングテンプレートを次のように更新しました：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;/&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;Deletes&lt;/span&gt; &lt;span class="nx"&gt;an&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="kd"&gt;with&lt;/span&gt; &lt;span class="nx"&gt;user_Id&lt;/span&gt; &lt;span class="sb"&gt;`ctx.args.input.user_Id`&lt;/span&gt; &lt;span class="nx"&gt;from&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;DynamoDB&lt;/span&gt; &lt;span class="nx"&gt;table&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="nx"&gt;param&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="kr"&gt;import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;@aws-appsync/utils&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;Context&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;user_id&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;unknown&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;book_id&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;unknown&lt;/span&gt;&lt;span class="p"&gt;;}}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nx"&gt;ctx&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="nx"&gt;returns&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="kr"&gt;import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;@aws-appsync/utils&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;DynamoDBDeleteItemRequest&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="err"&gt;/&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;book_id&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;operation&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;DeleteItem&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;util&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dynamodb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;toMapValues&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;book_id&lt;/span&gt; &lt;span class="p"&gt;}),&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;この修正により、リゾルバは &lt;code&gt;user_id&lt;/code&gt; と &lt;code&gt;book_id&lt;/code&gt; の両方を使用して削除操作を実行するようになり、DynamoDBのテーブルキー構造に適切に合わせられました。&lt;/p&gt;&#10;&lt;h2 id="まとめ"&gt;まとめ&#10;&lt;/h2&gt;&lt;p&gt;この記事を通じて、AWS AmplifyとAppSyncを利用する際に直面する可能性のある一つの典型的な問題とその解決策を共有しました。自動生成されたリゾルバがDynamoDBの複合キー構造を正しく扱わない場合の対処法と、その過程で得られた学びを詳しく説明しました。&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;AWS AppSyncの自動生成リゾルバは、複雑なキースキーマを持つDynamoDBテーブルに対して常に適切ではない。&lt;/li&gt;&#10;&lt;li&gt;データモデルや要件に応じてリゾルバを手動で検証し、調整することが重要。&lt;/li&gt;&#10;&lt;li&gt;基礎となるAWSサービスの動作と制約を理解することが、問題解決に不可欠。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;AWS AmplifyとAppSyncは強力なツールですが、それらを最大限に活用するには、サービスの内部動作に対する深い理解が必要です。&lt;/p&gt;&#10;&lt;h2 id="参考"&gt;参考&#10;&lt;/h2&gt;&lt;ul&gt;&#10;&lt;li&gt;&lt;a class="link" href="https://docs.amplify.aws/javascript/build-a-backend/graphqlapi/" target="_blank" rel="noopener"&#10; &gt;API (GraphQL) - JavaScript - AWS Amplify Documentation&lt;/a&gt;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;</description></item><item><title>DynamoDBで小数点(float)を扱う: PythonでFloatをDecimalに変換する</title><link>https://ai.hack-le.com/dynamodb-float-python-decimal/</link><pubDate>Wed, 15 Nov 2023 18:51:17 +0900</pubDate><guid>https://ai.hack-le.com/dynamodb-float-python-decimal/</guid><description>&lt;h2 id="dynamodbで小数点を扱う時の注意"&gt;DynamoDBで小数点を扱う時の注意&#10;&lt;/h2&gt;&lt;p&gt;Amazon DynamoDBは、高速で柔軟性があり、スケーラブルなNoSQLデータベースサービスとして広く利用されています。このサービスは、大規模なデータセットを迅速に処理し、簡単にアクセスする能力で知られており、ウェブスケールアプリケーションからビッグデータ分析まで、幅広い用途に適しています。しかし、DynamoDBを最大限に活用するには、そのデータ型の特性を理解し、適切に扱う必要があります。&lt;/p&gt;&#10;&lt;p&gt;特に注意が必要なのは、DynamoDBにおける数値データの扱いです。DynamoDBは数値をDecimal型として保存し、この形式は浮動小数点数（float型）とは異なる特性を持っています。なぜこれが重要なのでしょうか？一般的なプログラミング言語では、数値はしばしばfloat型で扱われますが、この型は精度の問題を引き起こす可能性があります。一方、Decimal型は固定小数点数を用いることで、これらの精度の問題を回避します。この特性は、金融データの処理や、正確な数値計算が求められる場合に特に重要です。&lt;/p&gt;&#10;&lt;p&gt;このため、DynamoDBにデータを保存する際には、float値をDecimal型に変換することが不可欠です。この小さな変更が、データの整合性を維持し、予期せぬエラーや計算の不正確さを防ぐ鍵となります。本記事では、この変換プロセスを簡単に行うためのPython関数を紹介し、その実装方法と利用例について詳しく説明します。&lt;/p&gt;&#10;&lt;h2 id="解決策の提示"&gt;解決策の提示&#10;&lt;/h2&gt;&lt;p&gt;DynamoDBでのfloat値の扱いに関する問題を解決するための鍵は、適切なデータ変換です。具体的には、float型の数値をDecimal型に変換する関数を作成し、DynamoDBに書き込むデータをこの関数で処理します。このアプローチにより、DynamoDBのデータ型の制約に適合しつつ、データの精度を維持することができます。&lt;/p&gt;&#10;&lt;h3 id="decimal変換関数"&gt;Decimal変換関数&#10;&lt;/h3&gt;&lt;p&gt;この変換を行うためのPython関数は、以下のように定義できます：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;decimal&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Decimal&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;convert_floats_to_decimals&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;&amp;#34;&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; Recursively converts all float values in a dictionary or list to Decimals,&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; which is required for DynamoDB compatibility.&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; &amp;#34;&amp;#34;&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;convert_floats_to_decimals&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;()}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="nb"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;convert_floats_to_decimals&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;element&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;element&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="nb"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Decimal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;この関数は、辞書やリストに含まれるfloat値を再帰的に探索し、それらをDecimal型に変換します。Pythonの&lt;code&gt;Decimal&lt;/code&gt;クラスは、float型の数値を正確な固定小数点数として表現するため、DynamoDBとの互換性が確保されます。&lt;/p&gt;&#10;&lt;h3 id="関数の動作原理"&gt;関数の動作原理&#10;&lt;/h3&gt;&lt;p&gt;この関数は、入力されたデータ構造を再帰的に探索します。辞書の場合、すべてのキーと値のペアに対してこの関数を適用し、リストの場合はリスト内の各要素に対して適用します。float型の値が見つかると、それを&lt;code&gt;Decimal&lt;/code&gt;型に変換し、他のデータ型はそのまま返します。&lt;/p&gt;&#10;&lt;p&gt;この方法により、辞書やリスト内の任意の深さにあるfloat値を確実にDecimalに変換することができます。これは特に、ネストされたデータ構造を扱う際に有効です。&lt;/p&gt;&#10;&lt;h2 id="関数の使用例"&gt;関数の使用例&#10;&lt;/h2&gt;&lt;p&gt;前のセクションで紹介した&lt;code&gt;convert_floats_to_decimals&lt;/code&gt;関数は、実際のデータ変換プロセスでどのように役立つのでしょうか？ここでは、具体的な使用例を通して、この関数の実用性を示します。&lt;/p&gt;&#10;&lt;h3 id="使用例辞書の変換"&gt;使用例：辞書の変換&#10;&lt;/h3&gt;&lt;p&gt;考えられる一般的なシナリオとして、辞書にfloat値が含まれる場合があります。例えば、次のような辞書があるとします：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;example_dict&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;key1&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;1.23&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;key2&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mf"&gt;3.45&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;6.78&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;key3&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;nested_key&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;9.01&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;この辞書をDynamoDBに保存する前に、float値をDecimalに変換する必要があります。&lt;code&gt;convert_floats_to_decimals&lt;/code&gt;関数を使用すると、以下のように変換できます：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;converted_dict&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;convert_floats_to_decimals&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;example_dict&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;結果は次の通りです：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s1"&gt;&amp;#39;key1&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Decimal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;1.23&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s1"&gt;&amp;#39;key2&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Decimal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;3.45&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;Decimal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;6.78&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)],&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s1"&gt;&amp;#39;key3&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;nested_key&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Decimal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;9.01&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;この変換により、元の辞書内のすべてのfloat値がDecimal型に変更され、DynamoDBへの書き込みが可能になります。&lt;/p&gt;&#10;&lt;h3 id="使用例ネストされたリストと辞書"&gt;使用例：ネストされたリストと辞書&#10;&lt;/h3&gt;&lt;p&gt;この関数は、より複雑なネストされたデータ構造にも対応しています。例えば、辞書の中にリストがあり、そのリストの中にさらに辞書があるような構造に対しても、すべてのfloat値を適切にDecimalに変換します。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;complex_data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;key1&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;inner_key1&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;2.34&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;inner_key2&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;5.67&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="mf"&gt;3.21&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;key2&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;nested_list&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mf"&gt;7.89&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;deep_key&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;4.56&lt;/span&gt;&lt;span class="p"&gt;}]}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;converted_complex_data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;convert_floats_to_decimals&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;complex_data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;この関数を使用することで、どのように深くネストされたデータ構造であっても、float値を正確にDecimalに変換することが可能です。&lt;/p&gt;&#10;&lt;h2 id="ベストプラクティスと考慮事項"&gt;ベストプラクティスと考慮事項&#10;&lt;/h2&gt;&lt;p&gt;&lt;code&gt;convert_floats_to_decimals&lt;/code&gt;関数を使用する際には、いくつかのベストプラクティスと考慮事項を心に留めておくことが重要です。&lt;/p&gt;&#10;&lt;h3 id="データ型の確認"&gt;データ型の確認&#10;&lt;/h3&gt;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;入力データの確認：&lt;/strong&gt; 関数に渡す前に、入力データが辞書やリスト形式であることを確認してください。これは関数がこれらのデータ型のみを対象としているためです。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;他のデータ型との互換性：&lt;/strong&gt; 関数はfloat型以外のデータ型をそのまま返しますが、DynamoDBに保存する前に他のデータ型に対する検証も検討してください。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h3 id="性能の考慮"&gt;性能の考慮&#10;&lt;/h3&gt;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;大規模データの取り扱い：&lt;/strong&gt; 非常に大きなデータセットや深くネストされたデータ構造を扱う際は、性能への影響を考慮する必要があります。関数の再帰的な性質は、特に大規模なデータ構造で処理時間が長くなる可能性があります。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h3 id="エラーハンドリング"&gt;エラーハンドリング&#10;&lt;/h3&gt;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;エラーハンドリングの実装：&lt;/strong&gt; 関数を組み込む際には、不適切なデータ型や予期しない入力に対するエラーハンドリングを考慮することが重要です。これにより、データ変換プロセスの堅牢性が向上します。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h3 id="dynamodbとの統合"&gt;DynamoDBとの統合&#10;&lt;/h3&gt;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;DynamoDBとの連携：&lt;/strong&gt; この関数はDynamoDBへのデータ書き込みの一部として組み込むことが最も効果的です。データをDynamoDBに保存する前の最終段階でこの関数を使用することで、データの整合性を保つことができます。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h2 id="まとめ"&gt;まとめ&#10;&lt;/h2&gt;&lt;p&gt;この記事では、DynamoDBでfloat値を効率的かつ正確に扱うための方法を紹介しました。Pythonでの&lt;code&gt;convert_floats_to_decimals&lt;/code&gt;関数の実装と使用方法を通じて、DynamoDBのデータ型の制約に対応しつつ、数値データの精度を維持する方法を学びました。適切なデータ変換プロセスを実施することで、アプリケーションのデータ整合性を向上させ、DynamoDBの利用を最大化することができます。&lt;/p&gt;&#10;&lt;p&gt;了解しました。最後に「参考文献とリソース」のセクションを含めて、記事を締めくくります。&lt;/p&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="参考文献とリソース"&gt;参考文献とリソース&#10;&lt;/h2&gt;&lt;p&gt;この記事で紹介した内容の理解を深めるために、以下のリソースが役立つでしょう：&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;Amazon DynamoDB 公式ドキュメント：&lt;/strong&gt; DynamoDBの基本的な概念、データ型、およびベストプラクティスに関する公式ガイドは、このデータベースサービスを理解するのに最適な出発点です。&lt;/li&gt;&#10;&lt;li&gt;&lt;a class="link" href="https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Introduction.html" target="_blank" rel="noopener"&#10; &gt;Amazon DynamoDB Developer Guide&lt;/a&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Pythonの&lt;code&gt;decimal&lt;/code&gt;モジュール：&lt;/strong&gt; PythonのDecimalクラスに関する公式ドキュメントを参照して、数値の精度と表現についての理解を深めることができます。&lt;/li&gt;&#10;&lt;li&gt;&lt;a class="link" href="https://docs.python.org/3/library/decimal.html" target="_blank" rel="noopener"&#10; &gt;Python &lt;code&gt;decimal&lt;/code&gt; Documentation&lt;/a&gt;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;これらのリソースは、DynamoDBの利用とデータ変換のスキルを向上させるための貴重な情報源です。この記事で紹介した関数と併用することで、DynamoDBのポテンシャルを最大限に活用し、アプリケーションのデータ処理能力を高めることができます。&lt;/p&gt;&#10;&lt;hr&gt;&#10;&lt;p&gt;この記事では、DynamoDBでのfloat値の扱いとその解決策に焦点を当て、具体的なPython関数の実装と使用方法を通じて、この問題に対処する方法を提供しました。これらの知識を活用して、自身のプロジェクトでより効果的にDynamoDBを使用してください。&lt;/p&gt;&#10;</description></item><item><title>AWS Systems Manager パラメータストアから Python で値を取得する方法</title><link>https://ai.hack-le.com/aws-systems-manager-python/</link><pubDate>Sun, 29 Oct 2023 02:49:11 +0900</pubDate><guid>https://ai.hack-le.com/aws-systems-manager-python/</guid><description>&lt;p&gt;AWS Systems Manager のパラメータストアは、データベースの接続文字列やパスワードなどの設定情報をセキュアに保存して管理するためのサービスです。この記事では、ローカルの Python スクリプトを使ってパラメータストアに保存されている値を取得する方法を説明します。&lt;/p&gt;&#10;&lt;h3 id="1-必要なライブラリをインストール"&gt;1. 必要なライブラリをインストール&#10;&lt;/h3&gt;&lt;p&gt;まず、AWS SDK for Python (Boto3) をインストールします。これをインストールするために、以下のコマンドを実行します。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;pip install boto3&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="2-python-スクリプトを作成"&gt;2. Python スクリプトを作成&#10;&lt;/h3&gt;&lt;p&gt;以下のサンプルコードを使用して、パラメータストアから任意のパラメータ名で保存されている値を取得します。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;boto3&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_parameter_from_store&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;param_name&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# Boto3 クライアントを初期化&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;ssm&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;boto3&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;ssm&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# パラメータを取得&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ssm&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_parameter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;param_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;WithDecryption&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;True&lt;/span&gt; &lt;span class="c1"&gt;# 暗号化されている場合はデコード&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# パラメータの値を返す&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Parameter&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Value&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="vm"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;__main__&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;param_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;input&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;Enter the parameter name: &amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;param_value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;get_parameter_from_store&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;param_name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;Value of &amp;#39;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;param_name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;#39;: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;param_value&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="3-aws-認証情報を設定"&gt;3. AWS 認証情報を設定&#10;&lt;/h3&gt;&lt;p&gt;ローカルマシンに &lt;code&gt;~/.aws/credentials&lt;/code&gt; というファイルを作成し、以下の内容を追加します。これにより、Boto3 は自動的にこのファイルの認証情報を使用します。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;[default]&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws_access_key_id = YOUR_ACCESS_KEY_ID&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws_secret_access_key = YOUR_SECRET_ACCESS_KEY&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;注意&lt;/strong&gt;: 実際のアクセスキーとシークレットアクセスキーに置き換えてください。&lt;/p&gt;&#10;&lt;h3 id="4-python-スクリプトを実行"&gt;4. Python スクリプトを実行&#10;&lt;/h3&gt;&lt;p&gt;上記のスクリプトを保存し、ローカルマシンで実行します。スクリプトを実行すると、取得したいパラメータ名を入力するプロンプトが表示されるので、対応する名前を入力してください。これにより、指定したパラメータの値がコンソールに表示されます。&lt;/p&gt;&#10;&lt;hr&gt;&#10;&lt;p&gt;これで、AWS Systems Manager のパラメータストアからローカルの Python スクリプトで値を読み取る方法についての概要を把握することができました。&lt;/p&gt;&#10;</description></item><item><title>AWS CloudWatch Logs Insightsで特定のイベントが起きた回数をbin()関数で時間ごとにカウントする</title><link>https://ai.hack-le.com/aws-cloudwatch-logs-insights-bin/</link><pubDate>Mon, 25 Sep 2023 18:10:47 +0900</pubDate><guid>https://ai.hack-le.com/aws-cloudwatch-logs-insights-bin/</guid><description>&lt;h2 id="はじめに"&gt;はじめに&#10;&lt;/h2&gt;&lt;p&gt;AWS CloudWatch Logs Insightsは、ログデータを効率的に探索・分析するためのさまざまな機能と能力を提供しています。その中でも特に強力な関数の一つが&lt;code&gt;bin()&lt;/code&gt;で、これによって時間ベースの区間にレコードを集約することが可能です。この記事では、&lt;code&gt;bin()&lt;/code&gt;関数が特に有用なシナリオについて探ります。&lt;/p&gt;&#10;&lt;h2 id="binとは"&gt;&lt;code&gt;bin()&lt;/code&gt;とは？&#10;&lt;/h2&gt;&lt;p&gt;&lt;code&gt;bin()&lt;/code&gt;関数は、レコードを時間間隔に基づいてグループ化します。これにより、ログデータを分、時間、日といった期間で分析することができます。構文は非常に簡単です：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;bin(時間間隔)&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;この&lt;code&gt;時間間隔&lt;/code&gt;は、秒（&lt;code&gt;s&lt;/code&gt;）、分（&lt;code&gt;m&lt;/code&gt;）、時間（&lt;code&gt;h&lt;/code&gt;）などの複数の単位で表現できます。&lt;/p&gt;&#10;&lt;h2 id="特定のイベントの時間別カウント"&gt;特定のイベントの時間別カウント&#10;&lt;/h2&gt;&lt;p&gt;特定のイベントが時間にわたって何回発生したかをカウントしたい場合、&lt;code&gt;bin()&lt;/code&gt;を&lt;code&gt;stats count(*)&lt;/code&gt;と組み合わせて使用することができます。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;fields @timestamp, @message&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| filter service = &amp;#34;何らかのサービス&amp;#34; and eventType = &amp;#34;何らかのイベント&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| stats count(*) by bin(10m)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| sort @timestamp desc&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="ユーザー活動の分析"&gt;ユーザー活動の分析&#10;&lt;/h2&gt;&lt;p&gt;時間区間でユーザー活動を分析したい場合、&lt;code&gt;bin()&lt;/code&gt;は効率的にデータをグループ化するのに役立ちます。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;fields @timestamp, @message, message.payload.user_id&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| filter service = &amp;#34;何らかのサービス&amp;#34; and message.payload.user_id = &amp;#34;特定のユーザーID&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| stats count(*) as userCount by bin(10m)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| sort @timestamp desc&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="時間区間による比較"&gt;時間区間による比較&#10;&lt;/h2&gt;&lt;p&gt;&lt;code&gt;bin()&lt;/code&gt;を使用することで、異なる時間区間でのメトリクスを簡単に比較することができます。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;fields @timestamp, @message, latency&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| filter service = &amp;#34;何らかのサービス&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| stats avg(latency) by bin(1h)&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="複数のbinの組み合わせ"&gt;複数の&lt;code&gt;bin()&lt;/code&gt;の組み合わせ&#10;&lt;/h2&gt;&lt;p&gt;単一のクエリ内で複数の&lt;code&gt;bin()&lt;/code&gt;を使用することで、複雑な時間ベースの集約を作成することが可能です。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;fields @timestamp, @message, message.payload.user_id, eventType&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| filter service = &amp;#34;何らかのサービス&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| stats count(*) by bin(10m), eventType&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="まとめ"&gt;まとめ&#10;&lt;/h2&gt;&lt;p&gt;&lt;code&gt;bin()&lt;/code&gt;関数は、AWS CloudWatch Logs Insightsで時間ベースのログデータを集約・分析する際の強力なツールです。この関数を効果的に使用する方法を理解することで、アプリケーションの動作やパフォーマンスについてより深い洞察を得ることができます。特定のイベントをカウントしたい、ユーザー活動を分析したい、あるいはその他の時間ベースのログ分析を行いたい場合にも、&lt;code&gt;bin()&lt;/code&gt;はそれを簡単に実現する方法を提供しています。&lt;/p&gt;&#10;</description></item><item><title>Amazon Cognito: ID Tokenの取得するPythonコード</title><link>https://ai.hack-le.com/amazon-cognito-id-token-python/</link><pubDate>Sun, 17 Sep 2023 12:36:02 +0900</pubDate><guid>https://ai.hack-le.com/amazon-cognito-id-token-python/</guid><description>&lt;p&gt;テストの時とかで、CognitoのID Tokenをさらっとほしいことがある。なので、ChatGPT-4にお願いした備忘録。&lt;/p&gt;&#10;&lt;h2 id="はじめに"&gt;はじめに&#10;&lt;/h2&gt;&lt;p&gt;Amazon Cognitoは、ユーザー認証やアイデンティティの提供に関する多くの便利な機能を提供しています。この記事では、管理者権限を使用して特定のユーザのID Tokenを取得する方法について説明します。&lt;/p&gt;&#10;&lt;h2 id="前提条件"&gt;前提条件&#10;&lt;/h2&gt;&lt;ul&gt;&#10;&lt;li&gt;AWSのアカウント&lt;/li&gt;&#10;&lt;li&gt;Python環境&lt;/li&gt;&#10;&lt;li&gt;Boto3ライブラリのインストール&lt;/li&gt;&#10;&lt;li&gt;Cognito User PoolとApp Clientの作成済み&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h2 id="ステップバイステップガイド"&gt;ステップバイステップガイド&#10;&lt;/h2&gt;&lt;h3 id="1-boto3のインストール"&gt;1. Boto3のインストール&#10;&lt;/h3&gt;&lt;p&gt;Boto3はAWSの公式SDKです。以下のコマンドでインストールできます。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;pip install boto3&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="pythonコードの準備"&gt;Pythonコードの準備&#10;&lt;/h3&gt;&lt;p&gt;以下は、指定されたユーザプールとクライアントアプリで指定されたユーザのID Tokenを取得するPythonコードです。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;boto3&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_id_token&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user_pool_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;client_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;boto3&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;cognito-idp&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;admin_initiate_auth&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;UserPoolId&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;user_pool_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;ClientId&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;client_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;AuthFlow&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;ADMIN_NO_SRP_AUTH&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;AuthParameters&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s1"&gt;&amp;#39;USERNAME&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s1"&gt;&amp;#39;PASSWORD&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;password&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# ID Tokenを取得&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;id_token&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;AuthenticationResult&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;IdToken&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;id_token&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# パラメータ設定&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;USER_POOL_ID&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;your-user-pool-id&amp;#39;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;CLIENT_ID&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;your-client-id&amp;#39;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;USERNAME&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;target-username&amp;#39;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;PASSWORD&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;target-user-password&amp;#39;&lt;/span&gt; &lt;span class="c1"&gt;# 管理者として取得する場合、正確なパスワードを知っている必要があります&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;token&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;get_id_token&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;USER_POOL_ID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;CLIENT_ID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;USERNAME&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;PASSWORD&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="注意点"&gt;注意点&#10;&lt;/h3&gt;&lt;p&gt;このアプローチにはいくつか注意点があります:&lt;/p&gt;&#10;&lt;ol&gt;&#10;&lt;li&gt;管理者の権限を必要とします。&lt;/li&gt;&#10;&lt;li&gt;ユーザーのパスワードを直接知っている必要があります。&lt;/li&gt;&#10;&lt;li&gt;セキュリティ対策やIAMポリシーの適切な設定も考慮する必要があります。&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;h2 id="まとめ"&gt;まとめ&#10;&lt;/h2&gt;&lt;p&gt;Amazon Cognitoを使用してID Tokenを取得する方法は複数ありますが、管理者として特定のユーザーのID Tokenを取得する際のアプローチについて解説しました。セキュリティの観点から注意深く使用することを忘れないでください。&lt;/p&gt;&#10;&lt;h2 id="寸評"&gt;寸評&#10;&lt;/h2&gt;&lt;p&gt;珍しく何事もなくうまくいった。&lt;/p&gt;&#10;</description></item><item><title>AWS Lambda Powertoolsのタイムスタンプを読みやすいローカル時刻に変換するJavaScriptのスニペット</title><link>https://ai.hack-le.com/aws-lambda-powertools-timestamp/</link><pubDate>Wed, 09 Aug 2023 13:22:37 +0900</pubDate><guid>https://ai.hack-le.com/aws-lambda-powertools-timestamp/</guid><description>&lt;p&gt;AWS Lambda PowertoolsはLambda関数使い必携の便利ユーティリティなわけだが、なぜかこれのloggerで自動的に記録されるタイムスタンプの形式が、&lt;code&gt;2021-05-03 10:20:19, 650+0200&lt;/code&gt;のようなよくわからん形になっている。カンマ……？（参考記事: &lt;a class="link" href="https://aws.amazon.com/jp/builders-flash/202205/lambda-powertools-python-3/?awsf.filter-name=*all" target="_blank" rel="noopener"&#10; &gt;AWS Lambda Powertools Python入門 第 3 回 ~Logger Utility - 変化を求めるデベロッパーを応援するウェブマガジン | AWS&lt;/a&gt;）&lt;/p&gt;&#10;&lt;p&gt;まぁちょっと直せばDate型にできそうだなと思ったので、ChatGPT-4にスニペット書いてもらってついでに記事にした。&lt;/p&gt;&#10;&lt;h2 id="イントロ"&gt;イントロ&#10;&lt;/h2&gt;&lt;p&gt;AWS Lambda Powertoolsは非常に便利なユーティリティで、AWS Lambdaの開発を容易にするための数々の機能を提供しています。しかし、時にはそのロギングに使用される日付フォーマットが少しわかりづらくなることがあります。&lt;/p&gt;&#10;&lt;p&gt;例: &lt;code&gt;2023-08-09 03:58:10,866+0000&lt;/code&gt;&lt;/p&gt;&#10;&lt;p&gt;この記事では、この特定のタイムスタンプの形式をJavaScriptでローカル時刻に変換する方法について説明します。&lt;/p&gt;&#10;&lt;h2 id="タイムスタンプの解析"&gt;タイムスタンプの解析&#10;&lt;/h2&gt;&lt;p&gt;このタイムスタンプの形式は標準的なものではないため、少し工夫して変換する必要があります。以下はその手順です。&lt;/p&gt;&#10;&lt;h3 id="手順"&gt;手順&#10;&lt;/h3&gt;&lt;ol&gt;&#10;&lt;li&gt;&lt;strong&gt;カンマをドットに置換する&lt;/strong&gt;:タイムスタンプにはカンマが使用されているため、最初にドットに置換します。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Dateオブジェクトの作成&lt;/strong&gt;:カンマをドットに置換した後、JavaScriptのDateオブジェクトを作成します。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;ローカル時刻に変換する&lt;/strong&gt;:Dateオブジェクトをローカル時刻に変換します。&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;h3 id="コード例"&gt;コード例&#10;&lt;/h3&gt;&lt;p&gt;以下は、このタイムスタンプをローカル時刻に変換するコード例です。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;timestamp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;2023-08-09 03:58:10,866+0200&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;adjustedTimestamp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;timestamp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;,&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;.&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;date&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;adjustedTimestamp&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;localDate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;toLocaleString&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;localDate&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;このコードは、与えられた日付と時刻をJavaScriptのDateオブジェクトに変換し、その後&lt;code&gt;toLocaleString&lt;/code&gt;メソッドを使用してローカル時刻に変換します。&lt;/p&gt;&#10;&lt;p&gt;ただし、この例のタイムスタンプの形式が標準的でないため、一部のブラウザではうまく動作しない可能性があります。もし問題がある場合は、以下のようにタイムスタンプを手動で解析することもできます。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;timestamp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;2021-05-03 10:20:19,650+0200&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;parts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;timestamp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/[- :+,]/&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// オフセットの部分を取得して、分単位に変換&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;offset&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;parseInt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;parts&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// Date.UTCでUTC時刻を計算し、オフセットを考慮&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;date&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;UTC&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;parts&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nx"&gt;parts&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;parts&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nx"&gt;parts&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nx"&gt;parts&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nx"&gt;parts&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nx"&gt;parts&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;offset&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;localDate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;toLocaleString&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;localDate&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;このコードは、与えられた文字列を解析して日付、時刻、およびタイムゾーンの各部分を取得し、それらを使用してDateオブジェクトを構築します。そして、このDateオブジェクトをローカル時刻に変換します。&lt;/p&gt;&#10;&lt;h2 id="まとめ"&gt;まとめ&#10;&lt;/h2&gt;&lt;p&gt;標準的な日付フォーマットとは異なるものに対処する際には、このように少し手間がかかることがあります。もし、このような変換がプロジェクトで頻繁に必要な場合、共通のユーティリティ関数として切り出して再利用すると良いかもしれません。&lt;/p&gt;&#10;&lt;p&gt;また、日付操作のライブラリ（例：moment.js、date-fnsなど）を使用することも考慮に入れると良いかもしれません。これらのライブラリは、様々なフォーマットの日付を扱う際に非常に便利です。&lt;/p&gt;&#10;&lt;p&gt;このユーティリティを使用して開発する際に役立つことを願っています。&lt;/p&gt;&#10;&lt;h2 id="寸評"&gt;寸評&#10;&lt;/h2&gt;&lt;p&gt;こんなスニペットでも記事にしておくと案外役に立つものなので、備忘録。オフセットがある場合とか地味にしんどいわ（普通UTCかローカルタイムのどっちかだと思うけど）。ただ簡単な記事だが、オフセットの計算で一度ChatGPTが謎の暴走していたりする……。絵文字使って言い訳しててなんか笑った。&lt;/p&gt;&#10;</description></item><item><title>AWS LambdaとCloudWatch Logs Insightsを組み合わせて効率的にログ分析</title><link>https://ai.hack-le.com/aws-lambda-cloudwatch-logs-insights/</link><pubDate>Thu, 03 Aug 2023 17:10:03 +0900</pubDate><guid>https://ai.hack-le.com/aws-lambda-cloudwatch-logs-insights/</guid><description>&lt;div class="blog-card-wrapper"&gt;&#10; &lt;a href="https://ai.hack-le.com/aws-cloudwatch-logs-insights/" class="blog-card"&gt;&#10; &lt;div class="blog-card-content"&gt;&#10; &lt;div class="blog-card-label"&gt;&#10; &lt;svg xmlns="http://www.w3.org/2000/svg" width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"&gt;&lt;path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"&gt;&lt;/path&gt;&lt;path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"&gt;&lt;/path&gt;&lt;/svg&gt;&#10; &lt;span&gt;あわせて読みたい&lt;/span&gt;&#10; &lt;/div&gt;&#10; &lt;div class="blog-card-title"&gt;AWS CloudWatch Logs Insightsで効率的なログ分析&lt;/div&gt;&#10; &lt;div class="blog-card-url"&gt;/aws-cloudwatch-logs-insights/&lt;/div&gt;&#10; &lt;/div&gt;&#10; &lt;div class="blog-card-thumbnail"&gt;&#10; &lt;img src="https://ai.hack-le.com/images/uploads/2023/08/a236f3f9feb84cf10e6d4e3cd98251ac.png" alt="AWS CloudWatch Logs Insightsで効率的なログ分析" loading="lazy" /&gt;&#10; &lt;/div&gt;&#10; &lt;/a&gt;&#10;&lt;/div&gt;&#10;&#10;&lt;p&gt;前回の記事の続き。ローカルで実行したCloudWatch Logs Insightsを使ったコードを、Lambda関数で実行するよ。&lt;/p&gt;&#10;&lt;h2 id="はじめに"&gt;はじめに&#10;&lt;/h2&gt;&lt;p&gt;AWS LambdaとCloudWatch Logs Insightsを連携させることで、自動化された効率的なログ分析が可能になります。この記事では、その設定方法からテスト実行までの手順を詳しく説明します。&lt;/p&gt;&#10;&lt;p&gt;以下は、Lambda関数を使用してCloudWatch Logs Insightsからログを取得する一連の手順です。&lt;/p&gt;&#10;&lt;h2 id="iamロールの作成"&gt;IAMロールの作成&#10;&lt;/h2&gt;&lt;p&gt;Lambda関数に適切な権限を持たせるために、関数に割り当てるIAMロールにCloudWatch Logs Insightsへのアクセス権限を付与する必要があります。この権限は、&lt;code&gt;logs:StartQuery&lt;/code&gt;, &lt;code&gt;logs:GetQueryResults&lt;/code&gt;, &lt;code&gt;logs:StopQuery&lt;/code&gt; などが含まれます。&lt;/p&gt;&#10;&lt;p&gt;AWS Webコンソールを使用してLambda関数に適切なIAMロールを作成するには、以下の手順を実施します。&lt;/p&gt;&#10;&lt;ol&gt;&#10;&lt;li&gt;&lt;strong&gt;AWS Management Console&lt;/strong&gt;にログインし、&lt;strong&gt;IAM&lt;/strong&gt; サービスに移動します。&lt;/li&gt;&#10;&lt;li&gt;左側のメニューから&lt;strong&gt;ロール&lt;/strong&gt;を選択し、「&lt;strong&gt;ロールの作成&lt;/strong&gt;」 ボタンをクリックします。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;AWSサービス&lt;/strong&gt;を選択し、&lt;strong&gt;Lambda&lt;/strong&gt;をクリックして、「&lt;strong&gt;次のステップ: アクセス権限&lt;/strong&gt;」 ボタンをクリックします。&lt;/li&gt;&#10;&lt;li&gt;「&lt;strong&gt;ポリシーの作成&lt;/strong&gt;」 ボタンをクリックして新しいポリシーを作成します。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;JSON&lt;/strong&gt;タブを選択し、以下のポリシーを入力します。&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;{&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;Version&amp;#34;: &amp;#34;2012-10-17&amp;#34;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;Statement&amp;#34;: [&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;Sid&amp;#34;: &amp;#34;VisualEditor0&amp;#34;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;Effect&amp;#34;: &amp;#34;Allow&amp;#34;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;Action&amp;#34;: [&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;logs:StartQuery&amp;#34;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;logs:GetQueryResults&amp;#34;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;logs:StopQuery&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ],&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;Resource&amp;#34;: &amp;#34;*&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ]&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ol&gt;&#10;&lt;li&gt;上記のポリシーは、CloudWatch Logs Insightsにクエリを投げるための基本的なアクションを許可しています。&lt;/li&gt;&#10;&lt;li&gt;「&lt;strong&gt;タグ&lt;/strong&gt;」 タブをクリックして必要なタグを追加し、「&lt;strong&gt;次のステップ: 確認&lt;/strong&gt;」 ボタンをクリックします。&lt;/li&gt;&#10;&lt;li&gt;ポリシーの名前と説明を入力し、「&lt;strong&gt;ポリシーの作成&lt;/strong&gt;」 ボタンをクリックします。&lt;/li&gt;&#10;&lt;li&gt;作成したポリシーを選択し、「&lt;strong&gt;次のステップ: タグ&lt;/strong&gt;」 ボタンをクリックして必要なタグを追加します。&lt;/li&gt;&#10;&lt;li&gt;「&lt;strong&gt;次のステップ: 確認&lt;/strong&gt;」 ボタンをクリックし、ロールの名前と説明を入力して、「&lt;strong&gt;ロールの作成&lt;/strong&gt;」 ボタンをクリックします。&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;p&gt;これで、Lambda関数からCloudWatch Logs Insightsのクエリを実行するためのIAMロールが作成されました。このロールをLambda関数の作成時に選択して使用します。&lt;/p&gt;&#10;&lt;p&gt;（著者注記: 文言微妙に変わってるかも。名前とかは適当に）&lt;/p&gt;&#10;&lt;h2 id="lambda関数の作成"&gt;Lambda関数の作成&#10;&lt;/h2&gt;&lt;p&gt;Pythonを使用してLambda関数を作成し、CloudWatch Logs Insightsへのクエリを実行するコードを記述します。&lt;/p&gt;&#10;&lt;ol&gt;&#10;&lt;li&gt;&lt;strong&gt;AWS Management Console&lt;/strong&gt;にログインし、&lt;strong&gt;Lambda&lt;/strong&gt; サービスに移動します。&lt;/li&gt;&#10;&lt;li&gt;「&lt;strong&gt;関数の作成&lt;/strong&gt;」 ボタンをクリックします。&lt;/li&gt;&#10;&lt;li&gt;「&lt;strong&gt;一から作成&lt;/strong&gt;」 を選択し、関数名とランタイム（Python 3.x）を選択します。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;IAMロール&lt;/strong&gt; に先ほど作成したロールを適用します&lt;/li&gt;&#10;&lt;li&gt;「&lt;strong&gt;関数の作成&lt;/strong&gt;」 ボタンをクリックします。&lt;/li&gt;&#10;&lt;li&gt;関数コードエディタで下記のLambda関数のコードを貼り付けます。&lt;/li&gt;&#10;&lt;li&gt;Deployします&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;boto3&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;time&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;datetime&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;timedelta&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;lambda_handler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;boto3&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;logs&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;log_group&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;your-log-group-name&amp;#39;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;end_time&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;start_time&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;end_time&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;timedelta&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;hours&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;start_query_response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;start_query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;logGroupName&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;log_group&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;startTime&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;start_time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;timestamp&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="c1"&gt;# 開始時間（UNIXタイムスタンプ、ミリ秒）&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;endTime&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;end_time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;timestamp&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="c1"&gt;# 終了時間（UNIXタイムスタンプ、ミリ秒）&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;queryString&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;fields @timestamp, @message | filter level=&amp;#39;INFO&amp;#39; | sort @timestamp desc&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;limit&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;query_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;start_query_response&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;queryId&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_query_results&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;queryId&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;query_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;status&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;Complete&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;results&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;results&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;break&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;results&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="テストの実行"&gt;テストの実行&#10;&lt;/h2&gt;&lt;ol&gt;&#10;&lt;li&gt;「&lt;strong&gt;テスト&lt;/strong&gt;」 ドロップダウンメニューをクリックし、「&lt;strong&gt;新しいテストイベントの設定&lt;/strong&gt;」 を選びます。&lt;/li&gt;&#10;&lt;li&gt;テストイベントの名前を入力します。特に入力などはないので、hello-worldテンプレートをそのまま使って問題ありません&lt;/li&gt;&#10;&lt;li&gt;「&lt;strong&gt;作成&lt;/strong&gt;」 ボタンをクリックしてテストイベントを作成します。&lt;/li&gt;&#10;&lt;li&gt;新しく作成したテストイベントが選択されていることを確認し、「&lt;strong&gt;テスト&lt;/strong&gt;」 ボタンをクリックします。&lt;/li&gt;&#10;&lt;li&gt;実行が完了すると、結果ペインに関数の結果が表示されます。ここには、戻り値やログ出力、実行時間などの詳細が含まれます。&lt;/li&gt;&#10;&lt;li&gt;結果ペインの下部にある「ログを表示」 リンクをクリックすると、完全なログ出力をCloudWatch Logsで確認することができます。&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;p&gt;この手順により、AWS WebコンソールからLambda関数をテスト実行し、結果とログを確認することができます。関数の挙動を調整したい場合は、コードを編集し、再度テストを実行して確認します。&lt;/p&gt;&#10;&lt;p&gt;初期設定の3秒ではタイムアウトが発生する場合、下記手順によりタイムアウトを増加させます。&lt;/p&gt;&#10;&lt;ol&gt;&#10;&lt;li&gt;Lambda関数のページで「設定」 タブをクリックします。&lt;/li&gt;&#10;&lt;li&gt;「&lt;strong&gt;一般設定&lt;/strong&gt;」 セクションで「編集」 ボタンをクリックします。&lt;/li&gt;&#10;&lt;li&gt;「&lt;strong&gt;タイムアウト&lt;/strong&gt;」 の値を増やし（例: 30秒）、「&lt;strong&gt;保存&lt;/strong&gt;」 ボタンをクリックします。&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;h2 id="まとめ"&gt;まとめ&#10;&lt;/h2&gt;&lt;p&gt;AWS LambdaとCloudWatch Logs Insightsを組み合わせることで、自動化された効率的なログ分析が容易になります。この記事の手順に従い、独自の分析タスクを自動化してみてください。&lt;/p&gt;&#10;&lt;h2 id="寸評"&gt;寸評&#10;&lt;/h2&gt;&lt;p&gt;内容的にちょっと複雑なためか、記事は会話の内容を自分でかなりツギハギしている。さすがにこの内容を一発で出してくれるほど有能ではない模様。でも、イチから自分で書くよりよっぽど楽だね。&lt;/p&gt;&#10;</description></item><item><title>AWS CloudWatch Logs Insightsで効率的なログ分析</title><link>https://ai.hack-le.com/aws-cloudwatch-logs-insights/</link><pubDate>Thu, 03 Aug 2023 16:18:49 +0900</pubDate><guid>https://ai.hack-le.com/aws-cloudwatch-logs-insights/</guid><description>&lt;p&gt;AWS CloudWatch Log Insights便利だよね。まぁまぁコストはかかるけれど。これをプログラム的に実行するためのスニペットをChatGPT-4に書いてもらったので、その備忘録記事。&lt;/p&gt;&#10;&lt;h2 id="はじめに"&gt;はじめに&#10;&lt;/h2&gt;&lt;p&gt;ログ分析はシステムの監視とトラブルシューティングに不可欠です。AWSを使ったシステムにおいては、AWS CloudWatch Logs Insightsを使用すると、ログデータを対話的に検索し分析することができます。この記事では、特定の時間範囲と条件でログを効率的に抽出する方法をPythonのBoto3ライブラリを使用して説明します。&lt;/p&gt;&#10;&lt;h2 id="cloudwatch-logs-insightsの概要"&gt;CloudWatch Logs Insightsの概要&#10;&lt;/h2&gt;&lt;p&gt;AWS CloudWatch Logs Insightsは、Amazon CloudWatch Logs内のログデータを分析するための強力な対話型クエリエンジンです。大量のログデータから情報を素早く取得することが可能であり、運用監視やトラブルシューティングに役立ちます。&lt;/p&gt;&#10;&lt;p&gt;以下のような昨日を持っています。&lt;/p&gt;&#10;&lt;ol&gt;&#10;&lt;li&gt;&lt;strong&gt;対話的なクエリ言語&lt;/strong&gt;: 特殊なクエリ言語を使用して、ログデータから必要な情報を素早く抽出できます。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;時間範囲のフィルタリング&lt;/strong&gt;: クエリの実行を特定の時間範囲に制限して、分析を高速化できます。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;ビジュアル化&lt;/strong&gt;: クエリ結果をグラフやチャートで視覚的に表示できます。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;プログラムからのアクセス&lt;/strong&gt;: Boto3などのSDKを使用して、プログラムからクエリを実行できます。&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;h2 id="クエリの作成と実行"&gt;クエリの作成と実行&#10;&lt;/h2&gt;&lt;p&gt;クエリは次のようなコンポーネントから構成されます：&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;code&gt;fields&lt;/code&gt;: 取得するフィールドを指定。例：&lt;code&gt;fields @timestamp, @message&lt;/code&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;filter&lt;/code&gt;: 条件に一致するログエントリをフィルタリング。例：&lt;code&gt;filter level='INFO'&lt;/code&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;sort&lt;/code&gt;: 特定のフィールドで結果を並べ替え。例：&lt;code&gt;sort @timestamp desc&lt;/code&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;limit&lt;/code&gt;: 結果の数を制限。例：&lt;code&gt;limit 20&lt;/code&gt;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;例をあげましょう。以下のような構造的なjsonデータをCloudWatch Logsに出力しているとします。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;{&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;level&amp;#34;: &amp;#34;INFO&amp;#34;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;message&amp;#34;: &amp;#34;...&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;level=&amp;ldquo;INFO&amp;quot;のものだけを抽出し、直近の時間のものから並べるのは、以下のようなクエリで可能です。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;fields @timestamp, @message | filter level=&amp;#39;INFO&amp;#39; | sort @timestamp desc&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="pythonとboto3でのクエリの実行"&gt;PythonとBoto3でのクエリの実行&#10;&lt;/h2&gt;&lt;p&gt;PythonとBoto3を使用してクエリをプログラムで実行することもできます。以下は、特定のロググループについて、直近1時間のINFOデータを抽出するプログラムの例です。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;datetime&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;boto3&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;time&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;boto3&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;logs&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;log_group&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;your-log-group-name&amp;#39;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;end_time&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;start_time&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;end_time&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;timedelta&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;hours&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;start_query_response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;start_query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;logGroupName&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;log_group&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;startTime&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;start_time&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;endTime&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;end_time&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;queryString&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;fields @timestamp, @message | filter level=&amp;#39;INFO&amp;#39; | sort @timestamp desc&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;limit&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;query_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;start_query_response&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;queryId&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_query_results&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;queryId&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;query_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;status&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;Complete&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;results&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;results&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;break&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;results&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;このコードは、指定されたロググループと時間範囲でクエリを実行し、レベルが&lt;code&gt;INFO&lt;/code&gt;のログエントリを取得します。&lt;/p&gt;&#10;&lt;h2 id="まとめ"&gt;まとめ&#10;&lt;/h2&gt;&lt;p&gt;CloudWatch Logs Insightsは、大規模なログデータの分析と検索に非常に効率的なツールです。特定のフィールドのフィルタリング、並び替え、制限など、柔軟なクエリオプションが提供されています。プログラムからも簡単にアクセスできるため、自動化された分析やダッシュボードの作成にも適しています。これにより、システムの監視と分析がより効率的になります。&lt;/p&gt;&#10;&lt;h2 id="寸評"&gt;寸評&#10;&lt;/h2&gt;&lt;p&gt;コードはちょっと手直しが必要だったが、普通に動いてくれたのでまぁよかったね。最初はすべてのログストリームを取得してプログラムでフィルタするという全然違うやり方を提案されて、えぇー、そんな馬鹿なと思って突っ込んで聞いたら、ちゃんとCloudWatch Logs Insightsを使ったやり方を教えてくれた。ChatGPTは本当にそういうところがある。&lt;/p&gt;&#10;&lt;p&gt;質問リンクは以下。興味がある人はどうぞ。&lt;/p&gt;&#10;&lt;p&gt;&lt;a class="link" href="https://chat.openai.com/share/d3ae4555-46e3-4573-bc85-26ca34491ab5" target="_blank" rel="noopener"&#10; &gt;https://chat.openai.com/share/d3ae4555-46e3-4573-bc85-26ca34491ab5&lt;/a&gt;&lt;/p&gt;&#10;&lt;h2 id="lambdaバージョン"&gt;Lambdaバージョン&#10;&lt;/h2&gt;&lt;p&gt;続きの記事でLambda関数使ったやり方書きました。&lt;/p&gt;&#10;&lt;div class="blog-card-wrapper"&gt;&#10; &lt;a href="https://ai.hack-le.com/aws-lambda-cloudwatch-logs-insights/" class="blog-card"&gt;&#10; &lt;div class="blog-card-content"&gt;&#10; &lt;div class="blog-card-label"&gt;&#10; &lt;svg xmlns="http://www.w3.org/2000/svg" width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"&gt;&lt;path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"&gt;&lt;/path&gt;&lt;path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"&gt;&lt;/path&gt;&lt;/svg&gt;&#10; &lt;span&gt;あわせて読みたい&lt;/span&gt;&#10; &lt;/div&gt;&#10; &lt;div class="blog-card-title"&gt;AWS LambdaとCloudWatch Logs Insightsを組み合わせて効率的にログ分析&lt;/div&gt;&#10; &lt;div class="blog-card-url"&gt;/aws-lambda-cloudwatch-logs-insights/&lt;/div&gt;&#10; &lt;/div&gt;&#10; &lt;div class="blog-card-thumbnail"&gt;&#10; &lt;img src="https://ai.hack-le.com/images/uploads/2023/08/7d4184c02862dca5ba613025c88e6bbc.png" alt="AWS LambdaとCloudWatch Logs Insightsを組み合わせて効率的にログ分析" loading="lazy" /&gt;&#10; &lt;/div&gt;&#10; &lt;/a&gt;&#10;&lt;/div&gt;&#10;&#10;</description></item><item><title>AWS SAMのテンプレートファイルでParameter Storeの値を取得する記述</title><link>https://ai.hack-le.com/aws-sam-cloudformation-parameter-store/</link><pubDate>Tue, 01 Aug 2023 09:00:00 +0900</pubDate><guid>https://ai.hack-le.com/aws-sam-cloudformation-parameter-store/</guid><description>&lt;p&gt;前の記事で「質問したことを備忘録として記事にまとめて」と言ったところ、なんと「次回は〜〜をします！お楽しみに！」とまさかの備忘録の次回作を勝手に予告されてしまってめっちゃ笑った。せっかくChatGPTが意欲的になったので、次回作を書いてもらったのだが、「パラメータストアの値をCloudformationで取得する（コードで取得しなくてよい）」という知らなかった方法を紹介されてめっちゃためになってしまった……。&lt;/p&gt;&#10;&lt;h2 id="はじめに"&gt;はじめに&#10;&lt;/h2&gt;&lt;p&gt;AWS SAM (Serverless Application Model)を使用すると、サーバーレスアプリケーションのデプロイメントと管理が大幅に簡素化されます。一方、AWS Systems Manager Parameter Storeは、設定データやシークレットをセキュアに保存し、アプリケーションから簡単にアクセスすることができるサービスです。今回は、これら2つのサービスを組み合わせて、AWS SAMテンプレート内で直接Parameter Storeの値を取得する方法について解説します。&lt;/p&gt;&#10;&lt;h2 id="直接parameter-storeの値を取得"&gt;直接Parameter Storeの値を取得&#10;&lt;/h2&gt;&lt;p&gt;Lambda関数のコード内でAWS SDKを使用してParameter Storeからパラメータを取得する代わりに、AWS SAMテンプレート内でCloudFormationのサブスティテューション機能を使用してParameter Storeの値を直接取得することができます。&lt;/p&gt;&#10;&lt;p&gt;これは、以下のようにAWS SAMテンプレートを記述することで可能です。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Resources:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; MyFunction:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Type: AWS::Serverless::Function&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Properties:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Handler: index.handler&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Runtime: nodejs14.x&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; CodeUri: s3://my-bucket/my-function.zip&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Environment:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Variables:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; MY_VARIABLE: !Sub &amp;#34;{{resolve:ssm:/path/to/parameter:1}}&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;ここで、&lt;code&gt;!Sub&lt;/code&gt;はCloudFormationのサブスティテューション（置換）機能を使用しています。&lt;code&gt;&amp;amp;#123;&amp;amp;#123;resolve:ssm:/path/to/parameter:1&amp;amp;#125;&amp;amp;#125;&lt;/code&gt;は、バージョン1の&lt;code&gt;/path/to/parameter&lt;/code&gt;という名前のParameter Storeのパラメータの値を取得しています。&lt;code&gt;/path/to/parameter&lt;/code&gt;は実際のパラメータの名前に置き換えてください。&lt;/p&gt;&#10;&lt;p&gt;（著者注記: パス部分はパラメータストアのパラメータ名をそのまま入れたら良い）&lt;/p&gt;&#10;&lt;p&gt;この記述により、Lambda関数内では、&lt;code&gt;process.env.MY_VARIABLE&lt;/code&gt;のように通常の環境変数を参照するだけで、Parameter Storeのパラメータの値を取得することができます。&lt;/p&gt;&#10;&lt;h2 id="注意点"&gt;注意点&#10;&lt;/h2&gt;&lt;p&gt;この方法でパラメータを取得する際、実行はCloudFormationサービスにより行われます。そのため、CloudFormation自身がParameter Storeへのアクセス権限を持っている必要があります。通常、CloudFormationのService RoleはAWS管理ポリシー &lt;code&gt;AWSCloudFormationFullAccess&lt;/code&gt; をアタッチして作成され、このポリシーにはParameter Storeへのアクセス権限が含まれています。したがって、通常はService Roleを特別に設定する必要はありませんが、カスタムポリシーを使用してService Roleを作成した場合など、適切な権限が設定されていることを確認してください。&lt;/p&gt;&#10;&lt;h2 id="まとめ"&gt;まとめ&#10;&lt;/h2&gt;&lt;p&gt;AWS SAMテンプレートとCloudFormationのサブスティテューション機能を使用することで、コード内でAWS SDKを使用せずに直接Parameter Storeからパラメータを取得することが可能になります。これにより、コードの見通しが良くなり、Parameter Storeのパラメータ管理がさらに便利になります。&lt;/p&gt;&#10;&lt;p&gt;次回は、AWS SAMテンプレートでのLambda Layerの利用について解説します。お楽しみに！&lt;/p&gt;&#10;&lt;p&gt;（著者注: そんな予定はない）&lt;/p&gt;&#10;&lt;h2 id="寸評"&gt;寸評&#10;&lt;/h2&gt;&lt;p&gt;なんで備忘録だといってるのに次回予告するねんｗｗｗとか言ってたら、フツーに知らない情報書かれて焦った。ちゃんと動きました。ためになりました。&lt;/p&gt;&#10;&lt;p&gt;元々は環境変数の使い方とかいう超初歩的な記事を書いていたんだけれど、その中でしれっとパラメータストアの値を直接取得していて、「え、そんなことできるの？」となってしまった。毎回Lambda関数の中でGetParametersしてたっていうね。。。ためになりました。。。&lt;/p&gt;&#10;</description></item><item><title>AWS SAMでParameter Storeからパラメータを取得するためのIAMロールの作成</title><link>https://ai.hack-le.com/aws-sam-parameter-store-iam/</link><pubDate>Mon, 31 Jul 2023 09:00:00 +0900</pubDate><guid>https://ai.hack-le.com/aws-sam-parameter-store-iam/</guid><description>&lt;p&gt;AWS SAMでどこを参照して良いのかいつも迷子になるテンプレートファイルの書き方。パラメータストアはいつも使うやつではないので、たまに使おうとすると「どう書くんだっけ……」と忘れている。&lt;/p&gt;&#10;&lt;p&gt;ChatGPT-4に聞いて確認しました。結果、そもそもコードで取得しなくて良いということがわかりましたが（後述）、本記事自体はあくまでコードでパラメータを取得するためのIAMロールを作成する方法になります。&lt;/p&gt;&#10;&lt;h2 id="はじめに"&gt;はじめに&#10;&lt;/h2&gt;&lt;p&gt;AWS SAM (Serverless Application Model) を使用してサーバーレスアプリケーションを構築する際、しばしば環境変数や設定値などをAWS Systems Manager Parameter Storeから取得する必要があります。これを適切に行うためには、Lambda関数に対してParameter Storeへのアクセス権限を持つIAMロールを付与する必要があります。本記事では、そのIAMロールをAWS SAMテンプレートでどのように定義すればよいかを詳しく解説します。&lt;/p&gt;&#10;&lt;h2 id="iamロールの作成"&gt;IAMロールの作成&#10;&lt;/h2&gt;&lt;p&gt;以下のYAML形式のコードスニペットは、AWS SAMテンプレート内でIAMロールを定義する方法を示しています。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Resources:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; MyRole:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Type: AWS::IAM::Role&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Properties:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; AssumeRolePolicyDocument:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Version: &amp;#39;2012-10-17&amp;#39;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Statement:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; - Effect: Allow&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Principal:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Service:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; - lambda.amazonaws.com&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Action:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; - sts:AssumeRole&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Policies:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; - PolicyName: ParameterStoreAccess&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; PolicyDocument:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Version: &amp;#39;2012-10-17&amp;#39;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Statement:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; - Effect: Allow&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Action:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; - ssm:GetParameters&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; - ssm:GetParameter&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Resource: arn:aws:ssm:region:account-id:parameter/MyParameter&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;このテンプレートでは、&lt;code&gt;MyRole&lt;/code&gt;という名前のIAMロールが作成され、このロールはLambdaサービスがAssumeRoleを行えるようになっています。また、そのロールには&lt;code&gt;ParameterStoreAccess&lt;/code&gt;という名前のポリシーが付与されており、このポリシーは&lt;code&gt;MyParameter&lt;/code&gt;という名前のParameter Storeのパラメータへのアクセスを許可しています。&lt;/p&gt;&#10;&lt;p&gt;ここで、&lt;code&gt;region&lt;/code&gt;と&lt;code&gt;account-id&lt;/code&gt;はそれぞれAWSリージョンとあなたのAWSアカウントIDを表します。これらを適切な値に置き換えてください。&lt;/p&gt;&#10;&lt;p&gt;補足情報:&lt;/p&gt;&#10;&lt;p&gt;この例ではパラメータ取得のための権限 (&lt;code&gt;ssm:GetParameters&lt;/code&gt; と &lt;code&gt;ssm:GetParameter&lt;/code&gt;) をIAMロールに付与していますが、他の権限も必要な場合はそれぞれ追加してください。また、特定のパラメータだけでなく、すべてのパラメータにアクセスする権限を付与したい場合は、リソースのARNを&lt;code&gt;arn:aws:ssm:region:account-id:parameter/*&lt;/code&gt;としてください。&lt;/p&gt;&#10;&lt;h2 id="まとめ"&gt;まとめ&#10;&lt;/h2&gt;&lt;p&gt;AWS SAMテンプレートでIAMロールを適切に定義し、Lambda関数にParameter Storeへのアクセス権限を付与することで、安全にParameter Storeからパラメータを取得することが可能になります。これにより、サーバーレスアプリケーションの設定値管理を柔軟に行うことができます。&lt;/p&gt;&#10;&lt;p&gt;次回は、AWS SAMテンプレートでの環境変数の管理方法について詳しく解説します。お楽しみに！&lt;/p&gt;&#10;&lt;p&gt;（著者注：そんな予定はない）&lt;/p&gt;&#10;&lt;h2 id="寸評"&gt;寸評&#10;&lt;/h2&gt;&lt;p&gt;次回作が出てきて笑ってしまった。そんな予定があったのかｗ&lt;/p&gt;&#10;&lt;p&gt;内容については動作確認済みです。適切だと思います。Pythonコードは以下ですね。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ssm = boto3.client(&amp;#34;ssm&amp;#34;)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;TOKEN = ssm.get_parameters(Names=[os.environ[&amp;#34;パラメータ&amp;#34;]], WithDecryption=True)[&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;Parameters&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;][0][&amp;#34;Value&amp;#34;]&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&amp;ldquo;パラメータ&amp;quot;の値を取得して&lt;code&gt;TOKEN&lt;/code&gt;に突っ込んでいます。&lt;/p&gt;&#10;&lt;p&gt;ただし、これは実は冗長で、テンプレートファイルから直接取得することができます。次回は環境変数の管理方法ではなく、テンプレートファイルから直接取得する方法です。&lt;/p&gt;&#10;&lt;p&gt;以下は質問。&lt;/p&gt;&#10;&lt;ol&gt;&#10;&lt;li&gt;AWS SAMのテンプレートで、パラメータストアから特定のパラメータについて取得するための権限の書き方は？&lt;/li&gt;&#10;&lt;li&gt;うまくいきました。適切なロールだったようですね。備忘録にしたいので、ブログ記事としてまとめてください。&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;p&gt;備忘録だっつってんのに次回作書きたがるChatGPTｗwwとか言ってたら知らないこと書かれてしまった……。&lt;/p&gt;&#10;</description></item><item><title>AWSアカウントIDを確認する複数の方法</title><link>https://ai.hack-le.com/aws-id/</link><pubDate>Sun, 16 Jul 2023 03:12:33 +0900</pubDate><guid>https://ai.hack-le.com/aws-id/</guid><description>&lt;p&gt;タイトルのとおりなんだが、AWSアカウントIDをしばしば失念して、どうやって調べたらいいんだっけ？と思ってChatGPT-4に聞いた。聞いたら答えてくれるんだが、一番いい方法をなかなか教えてくれなかった。ChatGPTはそういうところある。&lt;/p&gt;&#10;&lt;h2 id="イントロ"&gt;イントロ&#10;&lt;/h2&gt;&lt;p&gt;こんにちは、AWSユーザーの皆さん。本日は、AWSアカウントIDを確認する方法についていくつか紹介します。一つはAWS CLIを用いる方法、もう一つはAWS Management Consoleを利用する方法です。さらに、CLIの中でも特に効率的な方法を一つご紹介します。&lt;/p&gt;&#10;&lt;h2 id="コンソールからのログイン"&gt;コンソールからのログイン&#10;&lt;/h2&gt;&lt;p&gt;まずAWS Management ConsoleからアカウントIDを確認する方法を見てみましょう。以下の手順になります：&lt;/p&gt;&#10;&lt;ol&gt;&#10;&lt;li&gt;AWS Management Consoleにログインします。&lt;/li&gt;&#10;&lt;li&gt;右上のナビゲーションバーにある自分のアカウント名またはユーザー名をクリックします。&lt;/li&gt;&#10;&lt;li&gt;ドロップダウンメニューから&amp;quot;My Security Credentials&amp;quot;（または&amp;quot;セキュリティ資格情報&amp;quot;）を選択します。&lt;/li&gt;&#10;&lt;li&gt;&amp;ldquo;Account details&amp;rdquo;（または&amp;quot;アカウント詳細&amp;quot;）セクションを展開すると、アカウントIDが表示されます。&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;p&gt;しかしこの方法は、すでにAWS Management Consoleにログインしていることが前提となっています。つまり、ログイン前の状況では利用できないという制約があります。&lt;/p&gt;&#10;&lt;h2 id="aws-stsによる取得"&gt;AWS STSによる取得&#10;&lt;/h2&gt;&lt;p&gt;AWS CLIから直接アカウントIDを取得したい場合には、AWS Security Token Service（STS）の &lt;code&gt;get-caller-identity&lt;/code&gt; コマンドが非常に便利です。次のように実行します：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws sts get-caller-identity&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;これにより、以下のような出力が表示されます：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;{&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;UserId&amp;#34;: &amp;#34;AIDAJDPLRKLG7UEXAMPLE&amp;#34;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;Account&amp;#34;: &amp;#34;123456789012&amp;#34;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;Arn&amp;#34;: &amp;#34;arn:aws:iam::123456789012:user/Alice&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&amp;ldquo;Account&amp;quot;フィールドがあなたのAWSアカウントIDです。&lt;/p&gt;&#10;&lt;p&gt;この&lt;code&gt;get-caller-identity&lt;/code&gt;コマンドは、ログインを必要とせず、コマンドラインから直接アカウントIDを取得できるため、スクリプトの自動化や複数のAWSアカウントを管理する際に非常に便利です。&lt;/p&gt;&#10;&lt;p&gt;いずれの方法を選択するにせよ、AWSのセキュリティ資格情報（アクセスキーとシークレットアクセスキー）は適切に管理し、他人に漏れないように注意する必要があります。それでは、引き続きAWSの探求を楽しんでください。質問や意見がありましたら、お気軽にコメント欄からどうぞ！&lt;/p&gt;&#10;&lt;h2 id="寸評"&gt;寸評&#10;&lt;/h2&gt;&lt;p&gt;やけにフレンドリーな文体でなんか笑う。&lt;/p&gt;&#10;&lt;p&gt;それはそれとして、この回答はストレートにもらえていない。何故か最初に &lt;code&gt;aws iam get-user&lt;/code&gt; を使うやり方を勧めてきたんだよ。確かにそれでも取得できるんだけれど、&lt;code&gt;aws sts&lt;/code&gt;を使った出力のほうが断然スマートだった。代替え案はあるか聞いたら教えてくれたんだけど……危ないなぁ。他にいい案はないか、聞くほうがいいんだな。勉強になった。&lt;/p&gt;&#10;&lt;ol&gt;&#10;&lt;li&gt;AWSのアカウントIDをCLIで知る方法はある？&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;ここでaws iam get-userを出してきた&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;ol start="2"&gt;&#10;&lt;li&gt;うまくいった。備忘録のために、これをブログの記事風にまとめてくれ。&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;てっきりこれで終わるところだった。騙されるところだった&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;ol start="3"&gt;&#10;&lt;li&gt;ありがとう。ちなみに他にAWSアカウントIDを確認する方法はあるかな？&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;ふと気になって聞いてみた&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;ol start="4"&gt;&#10;&lt;li&gt;aws sts get-caller-identity が一番いいな。 コンソールのほうは、ログインしないとわからないから、ログインする前だと残念ながら金庫の中の鍵なんだよねぇ。&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;てめー最初からそっち言えよこんにゃろーと思いつつ&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;ol start="5"&gt;&#10;&lt;li&gt;ここまでの議論をブログ記事としてまとめてください。&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;p&gt;ChatGPTは役人と思って接しなければならないと改めて感じた。ちなみに記事もそこそこ手を入れている。うーん、質問力が試される……。&lt;/p&gt;&#10;</description></item><item><title>Boto3のTypeDeserializerを使用してDynamoDB Streamsイベントをパースする</title><link>https://ai.hack-le.com/boto3-typedeserializer-dynamodb-streams/</link><pubDate>Thu, 06 Jul 2023 22:12:04 +0900</pubDate><guid>https://ai.hack-le.com/boto3-typedeserializer-dynamodb-streams/</guid><description>&lt;p&gt;DynamoDB Streamのパース、ずっと自前でやっていたんだが、実はライブラリでデシリアライザが用意されていることを「&lt;a class="link" href="https://dev.classmethod.jp/articles/convert-dynamodb-json-to-python-dict-by-boto3/" target="_blank" rel="noopener"&#10; &gt;DynamoDB JSONの型変換をboto3だけで行ってみる | DevelopersIO&lt;/a&gt;」で知った。。。これを使うとDynamoDB Streamのパースも楽にできる。&lt;/p&gt;&#10;&lt;p&gt;テストデータとセットであると便利に思ったので、ChatGPT-4に聞いてみた。&lt;/p&gt;&#10;&lt;h2 id="イントロ"&gt;イントロ&#10;&lt;/h2&gt;&lt;p&gt;Boto3のTypeDeserializerは、DynamoDBのデータ型をPythonの標準のデータ型に変換するのに役立ちます。これは、DynamoDB Streamsのイベントを処理する際に特に便利です。この記事では、TypeDeserializerの基本的な使い方と、それを使用してDynamoDB Streamsイベントをパースする方法について説明します。&lt;/p&gt;&#10;&lt;h2 id="typedeserializerの基本"&gt;TypeDeserializerの基本&#10;&lt;/h2&gt;&lt;p&gt;TypeDeserializerクラスは、DynamoDBのレスポンスをパースするための便利なツールです。これはDynamoDBからのレスポンスをPythonの標準的なデータ型に変換します。以下に基本的な使用方法を示します。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;boto3.dynamodb.types&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;TypeDeserializer&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;deserializer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;TypeDeserializer&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# DynamoDBのデータ&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;dynamodb_data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s1"&gt;&amp;#39;S&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;Hello, world!&amp;#39;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# データをデシリアライズ&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;deserialized_data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;deserializer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;deserialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dynamodb_data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;deserialized_data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# &amp;#39;Hello, world!&amp;#39;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;ここでは、DynamoDBの文字列型（&amp;lsquo;S&amp;rsquo;）をPythonの文字列にデシリアライズしています。&lt;/p&gt;&#10;&lt;p&gt;なお、DynamoDBの数値データ型（&amp;lsquo;N&amp;rsquo;）は、Boto3のTypeDeserializerを使用してデシリアライズされるとき、Pythonの&lt;code&gt;decimal.Decimal&lt;/code&gt;型になります。&lt;/p&gt;&#10;&lt;p&gt;これはDynamoDBが数値を浮動小数点数として保存し、それがそのままの精度で保存されることを保証するためです。Pythonの標準的な&lt;code&gt;int&lt;/code&gt;や&lt;code&gt;float&lt;/code&gt;型を使用すると、特に大きな数値や非常に小さな数値の場合に精度が失われる可能性があります。そのため、&lt;code&gt;decimal.Decimal&lt;/code&gt;型が使用されます。&lt;/p&gt;&#10;&lt;h2 id="dynamodb-streamsイベントのパース"&gt;DynamoDB Streamsイベントのパース&#10;&lt;/h2&gt;&lt;p&gt;DynamoDB Streamsイベントは、テーブルに変更があったときに発行されます。これらのイベントには、変更前後の項目の詳細やイベントの種類（INSERT、MODIFY、REMOVE）など、役立つ情報が含まれています。&lt;/p&gt;&#10;&lt;p&gt;以下は、TypeDeserializerを使用してDynamoDB Streamsイベントをパースする例です。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;boto3.dynamodb.types&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;TypeDeserializer&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;parse_dynamodb_stream_event&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;deserializer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;TypeDeserializer&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;record&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Records&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;dynamodb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;record&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;dynamodb&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# 変更前の項目をパース&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;OldImage&amp;#39;&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;dynamodb&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;old_image&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;deserializer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;deserialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;dynamodb&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;OldImage&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;()}&lt;/span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;old_image&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# 変更後の項目をパース&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;NewImage&amp;#39;&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;dynamodb&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;new_image&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;deserializer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;deserialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;dynamodb&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;NewImage&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;()}&lt;/span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;new_image&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;Event Name: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;record&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;eventName&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;Old Image: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;old_image&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;New Image: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;new_image&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;この関数は、DynamoDB Streamsイベントの各レコードの&amp;quot;OldImage&amp;quot;と&amp;quot;NewImage&amp;quot;をパースしてPythonのデータ型に変換します。これにより、変更前後の項目データを簡単に利用することができます。&lt;/p&gt;&#10;&lt;p&gt;なお、DynamoDB Streamのイベント例は以下です。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;Records&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;eventID&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;1&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;eventName&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;INSERT&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;eventVersion&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;1.0&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;eventSource&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;aws:dynamodb&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;awsRegion&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;us-west-2&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;dynamodb&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;Keys&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;Id&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;N&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;101&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;},&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;NewImage&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;Message&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;S&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;New item!&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;},&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;Id&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;N&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;101&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;},&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;StreamViewType&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;NEW_AND_OLD_IMAGES&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;SequenceNumber&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;111&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;SizeBytes&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;26&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;},&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;eventSourceARN&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;arn:aws:dynamodb:us-west-2:account-id:table/ExampleTableWithStream/stream/2015-06-27T00:48:05.899&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;},&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;eventID&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;2&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;eventName&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;MODIFY&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;eventVersion&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;1.0&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;eventSource&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;aws:dynamodb&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;awsRegion&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;us-west-2&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;dynamodb&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;Keys&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;Id&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;N&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;101&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;},&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;NewImage&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;Message&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;S&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;This item has changed&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;},&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;Id&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;N&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;101&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;},&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;OldImage&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;Message&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;S&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;New item!&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;},&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;Id&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;N&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;101&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;},&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;StreamViewType&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;NEW_AND_OLD_IMAGES&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;SequenceNumber&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;222&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;SizeBytes&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;59&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;},&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;eventSourceARN&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;arn:aws:dynamodb:us-west-2:account-id:table/ExampleTableWithStream/stream/2015-06-27T00:48:05.899&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;},&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;eventID&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;3&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;eventName&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;REMOVE&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;eventVersion&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;1.0&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;eventSource&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;aws:dynamodb&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;awsRegion&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;us-west-2&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;dynamodb&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;Keys&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;Id&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;N&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;101&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;},&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;OldImage&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;Message&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;S&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;This item has changed&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;},&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;Id&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;N&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;101&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;},&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;StreamViewType&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;NEW_AND_OLD_IMAGES&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;SequenceNumber&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;333&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;SizeBytes&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;38&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;},&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;eventSourceARN&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;arn:aws:dynamodb:us-west-2:account-id:table/ExampleTableWithStream/stream/2015-06-27T00:48:05.899&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;以上が、Boto3のTypeDeserializerを使用してDynamoDB Streamsイベントをパースする方法です。&lt;/p&gt;&#10;&lt;h2 id="寸評"&gt;寸評&#10;&lt;/h2&gt;&lt;p&gt;テストデータを出してくれるのが神。&lt;/p&gt;&#10;&lt;p&gt;以下がChatGPT-4にした質問。&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;boto3のTypeDeserializerの使い方を教えて&lt;/li&gt;&#10;&lt;li&gt;DynamoDB Streamのeventをパースするのにも使える？&lt;/li&gt;&#10;&lt;li&gt;DynamoDB Streamのテストデータを出して&lt;/li&gt;&#10;&lt;li&gt;ここまでのことを記事としてまとめてください。&lt;/li&gt;&#10;&lt;li&gt;（追加）このデシリアライザを使うと、数値はDecimalになりますか、それともintになりますか、それともfloatになりますか？&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;最初にある程度正解知ってるからよかった。&lt;/p&gt;&#10;</description></item></channel></rss>