機雷がなんだ! 全速前進!

SEというかプログラマというか、日々のエンジニア生活の中で体験したことなどを中心に書き残しています。

AWS 認定 DevOps エンジニア – プロフェッショナル(DOP-C02)を【再々】取得しました

先日(7/23)AWS AWS 認定 DevOps エンジニア – プロフェッショナル(DOP-C02)を【再々】取得しました。

AWS Certified DevOps Engineer - Professional (AWS 認定 DevOps エンジニア - プロフェッショナル) バッジ

更新期限は11/11と少し先でしたが、今回は諸事情のため、このタイミングでの受験となりました。

学習教材

今回は、以下の3種類の教材で学習しました。

学習方法

学習期間は全体で約3週間で、以下のような流れで学習しました。

  • 1周目:約2週間かけて実施。疑問に感じたことは都度AIに聞きながら実施した
  • 2周目:約1週間かけて実施。間違えた問題番号を記録して最終見直しに備える
  • 最終見直し:受験前々日~前日にかけて、間違えた問題に絞って見直しを実施

受験結果

AWS Certified DevOps Engineer - Professional (DOP-C02) のスケーリングスコアは 100~1,000点です。合格に必要なスケーリングスコアは 750 点です。 今回のスコアは 783 とギリギリの合格でしたが、何とか一発で合格できました。

試験結果は、受験後24時間くらいでメール通知されるようになっていますが、受験後2時間くらいで、既に AWS 認定アカウントのサイト に合否が掲載されていました。通知メールを待ってモヤモヤせずとも、自分から上記サイトを見に行けば、結果はすぐに分かりそうです。(※必ず当日中に分かるかは保証しませんが)

おわりに

今回の学習では、分からない問題や疑問に思ったことはすぐにAI(今回はCopilotがメイン)に聞いて、都度壁打ちしながら理解を深めるという学び方をしました。その中で、問題の前提が古い情報に基づいていたり、解説が間違っていたりすることに早く気付くことができました。もちろんAIが常に正しい訳でもなく、無邪気にハルシネーションをかましてきたりもするので、少しでも違和感を覚えた場合は、しかりと掘り下げることが大切ですが、AIが無かったころと比較して、明らかに学習コスト(主に調査コスト)が下がったと思います。


また、資格学習の方法について調べている過程で、学習教材の選定に関する興味深い話題も目にしました。有名なAWS試験対策サイト「CloudLicense」を巡る話題です。今年の4月頃から「新規会員登録」および「新たな有料会員募集」を停止していたようですが、7月末から募集を再開するようです。資格取得においては学習効率だけでなく、利用する教材やサービスを見極めることも重要であり、サービス利用者側にもリテラシーが求められることを改めて認識しました。

日の出・日の入を計算する新WebアプリをStreamlitで作成して公開してみた🌞

2026年5月20日にこんなメールが届きました。

Mercury Cloud is moving to MLJAR Platform

(Mercury Cloud はMLJARプラットフォームに移行します)

Mercury Cloud はMLJARプラットフォームに移行します。Mercury Cloud は6月30日にサービスを終了します。アカウントの移行は行わず、Mercury Cloudに保存されているすべてのファイルとデータは削除されます。Mercuryデプロイメントを引き続き使用したい場合は、MLJARプラットフォーム https://platform.mljar.com )からご利用いただけます。

以前趣味でつくったWebアプリをMercury Cloudの無料プランで公開させてもらっていたのですが、サービスを終了するようです。MLJARプラットフォームをチラッと覗いてみたのですが、なんだか使いにくそうでした。他に良い移行先が無いかと調べた結果、Streamlitというサービスが良さげだったので、そちらに乗り換えることにしました。

Streamlit(ストリームリット)とは?

Pythonだけで簡単にWebアプリ(特にデータ可視化やAI用UI)を作れるオープンソースのフレームワークです。

特徴

  • HTML / JavaScript 不要。
    • PythonコードだけでWeb画面を作れる
  • データ分析・AI用途に強い
    • グラフ表示、機械学習モデルのUI化が簡単
  • すぐ動く
    • streamlit run app.py ですぐブラウザに表示
  • インタラクティブ
    • ボタン・スライダー・入力フォームなども簡単

できること

例えば以下のようなアプリがサクッと作れます。

  • データ分析ダッシュボード
  • 機械学習モデルのデモ画面
  • レポート可視化
  • ChatGPTのようなUI

Streamlit.io

Streamlitの公式プラットフォームです。使い方やドキュメント、サンプルコードなどの情報が公開されており、Streamlit Community Cloud で、作ったアプリを無料で公開できるクラウドサービスも提供されています。GitHubと連携した自動デプロイができるのが非常に便利です。

やったこと

Jupyter Notebookベースで開発した旧アプリをStreamlit用に改造しました。新旧のソースコードは以下のとおりです。
ちなみに、改造は殆ど生成AIが自動でやってくれたので超楽でした。こういうマイグレーション的な用途は、生成AIによるバイブコーディングは非常に有用ですね。

公開アプリ

https://calcdaytime.streamlit.app/

画面右下にある「< Manage app」というボタンをクリックすると簡単にアプリのログも確認できるので、エラーが発生した場合でも簡単にデバッグできます。

 あとは、今回初めて使用したのですが、GitHub Codespaces もなかなか便利でした。イメージとしては、AWS Cloud9 みたいな感じですが、VSCodeライクなUIなので、感覚的に使用しやすかったです。さすがに大規模な開発で使用するにはもっさりしててしんどそうですが、軽い作業なら必要十分という感触でした。 

この画面で生成AI(Copilot)とチャットしながらバイブコーディングができます。そして、ソースコードの変更はGithubリポジトリ連携を設定したWebアプリへすぐに反映されます。非常に便利ですね。

おわりに

旧アプリを公開していた Mercury Cloud は、無料プランではアプリが1つしか公開できませんでしたが、今回の Streamlit Community Cloud は公開アプリ数に制限はないようなので、新しいアイデアを思い付いたら、またふらっとWebアプリをつくって公開してみようと思います。一定時間が経過するとアプリは自動的にSleepして再度利用する際はコールドスタート(厳密には、手動でボタンをクリックする)になるので、その点だけご注意ください。

【再掲・2019年】偉人たちの足跡を辿って - シリコンバレー訪問レポート

※本記事は 2019年12月に私が執筆 したレポートを、内容を変えずに再公開したものです。
 別サイトに掲載していましたが閉鎖され閲覧できなくなったためこちらに再掲載しました。

 

ラスベガスで開催されるre:Invent 2019開催前日の12月1日(日)の朝、我々はサンフランシスコ国際空港に降り立ちました。目的はシリコンバレーを訪れるためです。昨年re:Invent 2018へ参加したメンバーは「Amazonのパワーをもっともっと感じようではないか!」という理由からAmazon本拠地であるシアトルを訪れましたが、今年は米国ITベンチャー発祥の地であるシリコンバレーを見て気持ちを高めてからラスベガスで開催されるre:Invent 2019へ行くことにしました。

 

コンピュータ歴史博物館

最初に訪れたのがこちらコンピュータ歴史博物館です。米国だけでなく全世界のコンピュータの歴史を代表する品々がここに展示されています。
 

(コンピュータ歴史博物館のエントランス)

 
館内に展示されている古今東西のコンピュータに関する展示物それぞれを解説すると、それだけで何百枚もの写真と原稿になってしまうので、ここでは私が見て感動した2つのものについて少しだけ解説するにとどめたいと思います。
 
(暗号化装置エニグマ)
 
まずは、かつてドイツ軍で使用されていた解読不可能と言われた暗号化装置エニグマです。映画「イミテーション・ゲーム」や「U-571」、古くは「U・ボート」などに登場する、歴史的に有名な暗号化装置です。名前だけでもご存知の方は多いのではないでしょうか?映画はフィクションも含まれていますが、このエニグマを巡ってかつて様々な戦いやドラマが繰り広げられたのです。天才数学者アラン・チューリングらが暗号解読機ボンベ(bombe)を開発して、暗号を解読できるようになって戦局は大きく変わっていきました。これを目の前にするとかつての天才たちがしのぎを削った歴史を感じずにはいられません。
 
(The Mythical Man-month:人月の神話)
 
そしてこちらはフレデリック・ブルックスの著書「人月の神話(The Mythical Man-month)」です。最初の刊行が1975年なのですが、当時のものでしょうか。初版から既に44数年が経っているにも関わらず、この本は今でも尚、大規模開発プロジェクトにおけるソフトウェア工学の古典として読み継がれている名著です。本の横に書かれているのは、あの有名な『ブルックスの法則』で「遅れているソフトウェアプロジェクトへの要員追加は、さらにプロジェクトを遅らせるだけだ(Adding manpower to a late software project makes it later.)」です。日進月歩のコンピュータ業界において、40年を経ても名著として読み続けれているというの本当に驚きですが、逆に考えると、テクノロジーが進化しても大規模プロジェクトにおいて我々が直面する課題の本質というのはあまり変わっていないのかもしれません。改めてこの教訓を胸に刻んでおきたいと思いました。
 

グーグルプレックス

コンピュータ歴史博物館から徒歩で行ける距離にグーグルプレックス(Googleplex)があります。グーグルプレックスはGoogle本社の愛称です。その道すがら工事中の巨大なスタジアムのような建造物を見ましたが、2019年完成予定だった新社屋「Google Campus Charleston East」のようです。完成が遅れているのでしょうか。完成すると新たに2700人を収容できる巨大でモダンな新オフィスになるそうです。
 
(グーグルプレックス:Google本社)
 
いよいよ到着したGoogle本社です。この日が日曜日だったせいか、人も車もほとんどおらず閑散としていました。会社というより有名私立大学のキャンパスといった印象です。敷地内のあちこちにベンチやリクライニングチェアが設置してありました。この日は生憎の雨模様だったので座りませんでしたが、天気が良ければPCを抱えて外で気持ちよくcodingできそうな雰囲気です。
 
(グーグルプレックスのT-Rex化石標本)
 
何故か敷地内に恐竜の化石標本が展示されていました。この恐竜の名前はスタン(Stan)と言うらしいです。創業者達が近くのスタンフォード大学出身だからなのか、巨体故に環境に適応できずに絶滅してしまったことを反面教師にするためなのか真相は不明のようです。Google社の名前の由来がgoogol(10の100乗)に由来する、というのと同じくらい謎めいていますね。

 

(グーグルプレックスのドロイド君Pie)
 
Google社は2005年にAndroid社を買収した訳ですが、以来Androidのバージョンにはスイーツな開発コードネームが付けられてきました。写真のPieはAndroid 9.0のものです。現在最新のAndroidのバージョンはAndroid 10.0ですが、何故まだ古いバージョンのドロイド君が展示されたままなのか?というと実は悲しいかなAndroid 10.0からはGoogleは開発コードネームを廃止してしまったのです。それ故まだ旧バージョンのドロイド君が展示されたままなのだと思うのですが、彼がいつまで美味しそうなPieに囲まれたままで居られるのかは分かりません。この写真を撮影したのは2019年12月1日ですが、もしかしたらとても貴重な写真になるかもしれませんね。
 

カルトレイン(Caltrain)

我々が宿泊したホテルの最寄駅はサン・アントニオ駅なのですが、鉄道(Caltrain)に乗って3駅先がパロアルト駅です。せっかくシリコンバレーに来たので、地元の鉄道に乗車してパロアルトまで移動してみることにしました。
 
(Caltrainの乗車チケット自動販売機)
 
Caltrainの駅には改札もゲートも何もありません。ホームに乗車チケットを販売している自動販売機がありました。ですが、買い方が全然分かりません(汗)日本では出発~到着駅で値段が決まるので駅名が分かっていれば乗車チケットが買えますし、駅員さんに聞いてチケットを購入することもできます。ですが、ホームには駅員さんも居らず、自動販売機はゾーン(?)を指定してチケットを買うという謎仕様で、ゾーンの概念が分かってないと迂闊に手を出せません。ググってみたところ、スマホアプリでもチケットが買えるということが分かったのですぐにGoogle Playからダウンロードしてインストールしました。

 

(Caltrainのスマホアプリ)
 
このアプリを使えば、駅名をFROM-TOで入力するだけで簡単に乗車チケットが購入できます。支払いもGoogle Payなのでキャッシュレスで簡単です。もしCaltrainに乗車するならスマホアプリで購入することをオススメします。注意点としては、土日だったこともあってかこの鉄道1時間に1本くらいしか走っていないので、うっかり1本乗り逃すと次までかなり待たされることになるので気をつけましょう。

 

(Caltrainの車両)
 
Caltrainは全線が非電化で動力はディーゼル機関のようです。架線がないため景観はなかなか良いです。各駅停車の客車列車は2階建ての立派な車両でなんと日本車輌製だそうです。せっかくなのでこの客車列車の2階の座席に座って景色を眺めながら移動しました。また、Caltrainは自転車で通学、通勤する人も多いためか客車列車の他に自転車や大きい荷物を格納する車両もありました。駅のホームの中まで自転車で移動してきて、そのまま列車内に持ち込んでる人もいました。なかなか日本では味わえない感覚です。うーん、ダイナミック。こういうの好きです。 

 

(Caltrainパロアルト駅)
 

パロアルト周辺

いよいよパロアルト駅に到着しました。パロアルト駅はすぐ隣のスタンフォード駅と1km程と近くてすぐに歩ける距離です。スタンフォード大学は全米きっての名門大学であり、シリコンバレーで生まれた多くのスタートアップ企業の創始者達の母校でもあります。名前を出せばキリがないですが、あのGoogle、Hewlett-Packard、Yahoo、Sun Microsystems、Cisco、Netflixなどの名だたる企業を世に送り出した名門中の名門大学なのです。
 

(Hewlett-Packardガレージ)

 
パロアルト駅から15分程歩いた住宅街の一角に「Hewlett-Packardガレージ」があります。ここは今からおよそ80年前の1938年にHP(Hewlett-Packard)の創始者であるウィリアム・ヒューレットとデビッド・パッカードがこの場所を拠点にして創業したという場所で、言わばシリコンバレーの歴史が始まった発祥の地と言える場所です。ようやく辿り着いた時にはすっかり日も暮れ夜になっていたのでHPガレージに続く門は閉められてしまっていましたが、夜でも記念碑とガレージはライトアップされていて何とか見ることができました。わざわざ歩いて来た甲斐がありました。
 
(トヨタ・リサーチ・インスティテュート)
 
パロアルトからホテルへ帰る途中にトヨタ・リサーチ・インスティテュート(Toyota Research Institute, Inc.、略称:TRI)がありました。人工知能技術に関する先端研究、商品企画を目的として、2016年にトヨタ自動車により設立された研究所で、最近では自動運転のテレビCMでも時々見かけますね。日本を代表するモノづくりメーカー企業も、今後の生き残りを賭けて、米国の大学(MITやスタンフォード)と連携して最先端の研究開発を行っており、その拠点をシリコンバレーに置いているようです。

 

(Adobe Creek:アドビ川)
 
翌日12月2日(月)の朝、宿泊したホテルの周りを散歩していたら「Adobe Creek」の表示を見つけました。「Adobe」の名前が気になったので調べてみたところ、なんとあのPhotoshopやIllustratorで有名なAdobe Systemsの社名の由来となった「Adobe川」でした。創業者ジョン・E・ワーノック(John・E・Warnock)の自宅の裏をこの川が流れていたことから社名がAdobe Systemsになったんだとか。少しウロつくだけで、こういう面白いエピソードに出会えるからシリコンバレーは本当に面白いですね。
 
(アルタ・メサ記念公園:ジョブズのお墓)
 
Adobe川を遡って歩いて行くとアルタ・メサ記念公園があります。ここにはApple社の共同設立者スティーブ・ジョブズの遺体が埋葬されています。不思議なことに彼の墓石はどこにもありませんでした。その理由は分かりませんが、墓石で場所が分かってしまうと彼の墓を荒らす不届きな輩が居るかもしれませんので、むしろ良かったのかもしれません。ホテルからこのアルタ・メサ記念公園へ向かう道中は、平日(月曜日)の朝の通勤時間帯ということもあり、前日と比べて交通量も人も多くて賑わいがありましたが、この門を通り抜けた先は不思議な静寂に包まれていました。公園内の木々にはたくさんのリス達が居て、敷地内を走り回っていました。安らかに眠るにはとても良い場所だと思いました。
 
(アルタ・メサ記念公園:ホテルへの帰り道)
 
ホテルへの帰路、真っ赤に紅葉した木々や歩道に散った木の葉を見ると、まるで自分が秋の日本に居るような気持ちになりました。そうえば、ジョブズは日本の禅に傾倒していたそうですね。ふと2005年にスティーブ・ジョブズがスタンフォード大学の卒業式に招待され「点と点を繋ぐ(Connecting The Dots)」あの有名なスピーチをしたことを思い出しました。スピーチの最後は「ハングリーたれ。愚かたれ(Stay hungry, Stay foolish)」で締め括られます。その意味については人それぞれの解釈があるようですが色々と考えさせられる言葉だと思います。わたしはジョブズ信仰者ではないですが、彼のスピーチやプロダクトに徹底的に拘る姿勢、その生き様からは凄まじい情熱を感じます。彼は当時特別なものだったコンピュータを我々にとって身近なもの(Macintosh、Pixar、iPhone)に変えてしまった大変革者なのです。アルタ・メサは、既に故人となった彼について思い出し、そして、彼が言ったこと、やったことについて考える機会になりました。
 
(シリコンバレーでのえげつない量の朝食)
 
散歩から戻りラスベガスへ出発する朝の集合時間になって、近所のレストランへ皆で朝食を食べに行きました。メニューを見てもよく分からないので、適当に朝食セット的なものと温かいコーヒーを注文したところ、とんでもない量の朝食が出てきました。皆、ヒーヒー言いながら食べましたが、一緒に行ったメンバーの中には食べきれず残す人も。隣の席の(地元の?)おばあちゃんが同じ量をペロッと食べ切ってる姿を見て皆で苦笑いしました。シリコンバレーお婆ちゃん、恐るべし。朝食の値段はチップ込で21米ドル(約2300円)。高いですよね(汗)。シリコンバレーは一見すると素朴で田舎っぽい雰囲気ですが、とても物価が高い(この後行くラスベガスはもっと高かったけど...)のです。
ともあれ、これでラスベガスへ向かう心と体の準備が整いました!
さあ、いざ飛行機でラスベガスへ!待ってろよAWS re:Invent 2019!
 

※本記事は当時の体験を記録したものであり、現在の状況とは異なる場合があります。

生成AIで誰でも簡単に物理シミュレーションできる時代

時々 Google Colaboratory を使って遊んでいます。Webブラウザだけで簡単に計算したりシミュレーション結果を可視化したりできて非常に便利です。しかも基本的に無料で利用できます。以前の記事で紹介した通り、生成AI(Google Gemini)を使うことでサクッとプログラムの修正ができてしまうことを知ってからは、試してみたいけどちょっと面倒だと思ったことを、生成AIで簡単に試せることを知りました。

例えば、以下のような事がものの数分で簡単に試せてしまいます。なんて恵まれた時代だ。

例1:特殊相対性理論の可視化

プロンプト:

アインシュタインの特殊相対性理論の一般式(速度がゼロでない場合)
を光速は秒速30万km/sとして二次元のグラフで可視化してください。
縦軸を質量、横軸を速度としてください。また、グラフのラベルは英語表記としてください。

実行結果:

import numpy as np
import matplotlib.pyplot as plt

# Speed of light in km/s
c = 299792.458

# Rest mass (arbitrary value for demonstration)
m0 = 1.0  # Assume a rest mass of 1 unit

# Define a range of velocities from 0 up to (but not including) the speed of light
# We'll use a small epsilon value to avoid division by zero at v = c
v = np.linspace(0, c * 0.995, 500)  # velocities from 0 to 99.5% of c

# Calculate the relativistic mass
# The formula is m = m0 / sqrt(1 - (v^2 / c^2))
mass = m0 / np.sqrt(1 - (v**2 / c**2))

# Create the plot
plt.figure(figsize=(10, 6))
plt.plot(v, mass)

# Set labels and title
plt.xlabel('Velocity (km/s)')
plt.ylabel('Relativistic Mass (arbitrary units)')
plt.title('Relativistic Mass vs. Velocity')
plt.grid(True)

# Show the plot
plt.show()

この結果から、例えば、物体が光速の99.5%に達した場合、質量が約10倍程度になることが分かります。 また、さらにそれ以上に速度を上げようとすると質量は急激に増加してしまい、結局は光速に到達できないことも一目で分かります。 ブルーバックスなんかを読んでいると、本に記載されている内容を無性に試したり、確認してみたいという衝動に駆られた事が何度もありました。 しかし、その度に、それだけのためにいちいコード書いて試すのが面倒で思いとどまる事が多かったですが、今ではこんなに簡単にできてしまいます。

例2:プログラムの解説(要約)

もちろん解説や要約やレビューも生成AIにはお手の物です。

プロンプト:

このプログラムを解説してください。

実行結果:

このコードは、Albert Einstein特殊相対性理論(Special Relativity) における「相対論的質量」の式を使って、速度と質量の関係をグラフ化するものです。順番に解説します。

① 使っている理論式

特殊相対性理論では、物体が光速に近づくと質量が増加すると表されます(※現在の物理では“相対論的質量”よりも“エネルギー増加”で説明するのが主流ですが、この式は教育目的でよく使われます)。

相対論的質量の式

  • ( m_0 ):静止質量(rest mass)
  • ( v ):物体の速度
  • ( c ):光速
  • 分母の部分を ローレンツ因子(Lorentz factor) と呼びます

② コードの各部分の意味

1️⃣ ライブラリの読み込み

import numpy as np
import matplotlib.pyplot as plt
  • numpy → 数値計算
  • matplotlib → グラフ描画

2️⃣ 光速の設定

c = 299792.458

3️⃣ 静止質量

m0 = 1.0

デモ用に「1」としています。 単位は任意(arbitrary units)。

4️⃣ 速度の範囲

v = np.linspace(0, c * 0.995, 500)
  • 0 から 99.5% の光速まで
  • 500点で分割

なぜ 100% にしない?

だと

になり、ゼロ割りで無限大になるからです。

5️⃣ 相対論的質量の計算

mass = m0 / np.sqrt(1 - (v**2 / c**2))

式そのままです。

  • 低速ではほぼ m0
  • 光速に近づくと急激に増加
  • c に近づくと無限大へ発散

6️⃣ グラフ描画

plt.plot(v, mass)
横軸

Velocity (km/s)

縦軸

Relativistic Mass

③ グラフの物理的意味

このグラフは次の性質を示します:

🔹 低速領域
  • 質量はほぼ一定
  • ニュートン力学とほぼ同じ
🔹 中速領域
  • 少しずつ増加
🔹 光速に近づくと
  • 急激に上昇(ほぼ垂直に立ち上がる)

つまり:

物体は光速に到達できない

なぜなら、 到達するには「無限大のエネルギー」が必要だからです。

④ このコードの物理的ポイント

✔ 特殊相対性理論の一般式を使用 ✔ 速度がゼロでない場合を含む ✔ ローレンツ因子を利用 ✔ 発散(infinite behavior)を数値的に確認できる

⑤ 現代物理での注意

現在の物理では、

「質量が増える」という言い方よりも、

として

  • 質量は不変
  • エネルギーが増加する

と説明するのが一般的です。

⑥ まとめ

このコードは:

✔ 特殊相対性理論の相対論的質量を ✔ 数値的に計算し ✔ 光速に近づくと発散する様子を ✔ 英語ラベル付きで可視化する

教育用として非常にわかりやすい例です。


(↑↑↑ 生成AIの実行結果はここまで ↑↑↑)


こんな感じで壁打ち的に生成AIと会話しながら、次はこれ、その次は... と、どんどん試していけるのがいいですよね。

おまけ

(当たり前ですが)数学の数値シミュレーションも簡単に試せます。

プロンプト:

マンデルブロ集合を数値計算して可視化してください。

実行結果:

pip install numpy pandas matplotlib seaborn scikit-learn
import numpy as np
import matplotlib.pyplot as plt

def mandelbrot(c, max_iter):
    z = 0
    for n in range(max_iter):
        z = z*z + c
        if abs(z) > 2:
            return n
    return max_iter

width, height = 512, 512
max_iter = 256

x, y = np.linspace(-2, 1, width), np.linspace(-1.5, 1.5, height)
c = x[np.newaxis, :] + y[:, np.newaxis] * 1j

mandelbrot_set = np.vectorize(mandelbrot)(c, max_iter)

plt.figure(figsize=(12, 12))
plt.imshow(mandelbrot_set, extent=[-2, 1, -1.5, 1.5], cmap='viridis')
plt.xlabel("Re(c)")
plt.ylabel("Im(c)")
plt.title("Mandelbrot Set")
plt.colorbar()
plt.show()

コラッツ予想のシミュレーションなんかさせるのも楽しいですね(もちろん解決はできませんが...)。

参考

github.com

Microsoft Entra ID (旧 Azure AD) をIdPとしてOIDC認証する際の注意点(バックエンド)

前回記事では主にMicrosoft Entra ID (旧 Azure AD)側の設定とフロントエンド(SPA)を中心にした内容でしたが、今回はバックエンド側の注意点について記載します。

本記事では、バックエンドはJava(Spring Boot 3.5.8)で実装したWebAPIを想定しています。

変更前IdP:Amazon Cognito

Amazon CognitoをIdPとして以下のようなエンドポイントを指定していました。

バックエンドの設定

以下のように設定ファイル(application.yml)でエンドポイントを指定しました。

spring:
  security:
    oauth2:
      resourceserver:
        jwt:
          issuer-uri: https://cognito-idp.ap-northeast-1.amazonaws.com/ap-northeast-1_xxxxxxxxx

この設定で特に問題なくOIDC認証ができていました。

変更後IdP:Microsoft Entra ID (旧 Azure AD)

前提

  • Microsoft Entra ID (旧 Azure AD)側でIdP設定済
  • フロントエンドはReactで実装したSPAを想定

今回前提とする設定内容は前回記事の【最終版】と同様です。(詳細はそちらをご覧ください)

問題

Microsoft Entra ID (旧 Azure AD)をIdPに変更したところ、フロントエンドからバックエンドAPI呼び出しで以下の401エラーが発生してしまいました。

Www-Authenticate:

Bearer error="invalid_token", 
error_description="The aud claim is not valid", 
error_uri="https://tools.ietf.org/html/rfc6750#section-3.1"

これは、Spring SecurityのOAuth2リソースサーバが、受信したJWTトークン(アクセストークン)のaudクレームを検証した際、想定する値と一致しないため認証が失敗たことを示しています。

手順①:バックエンドの設定

以下のように設定ファイル(application.yml)でエンドポイントを指定していました。

spring:
  security:
    oauth2:
      resourceserver:
        jwt:
          issuer-uri: https://login.microsoftonline.com/4647xxxx-xxxx-xxxx-xxxx-xxxxxx394ecb/v2.0
          audiences:
            - api://4f82xxxx-xxxx-xxxx-xxxx-xxxxxx5fa07b

手順②:実行結果

アクセストークンを確認してみるとiss(issuer)は一致しているようです。(以下✅のところ) しかし、aud(audience)が一完全には致していないことが分かりました。(以下❌のところ)

{
  "aud": "4f82xxxx-xxxx-xxxx-xxxx-xxxxxx5fa07b", ← ❌ 完全一致してない(設定ファイルには「api://」がある)
  "iss": "https://login.microsoftonline.com/4647xxxx-xxxx-xxxx-xxxx-xxxxxx394ecb/v2.0", ← ✅ 完全一致している
:
(以下略)

解決方法

前述の設定ファイルとアクセストークンの差異を修正します。

手順①:バックエンドの設定

以下のように設定ファイル(application.yml)でエンドポイントを修正しました。

spring:
  security:
    oauth2:
      resourceserver:
        jwt:
          issuer-uri: https://login.microsoftonline.com/4647xxxx-xxxx-xxxx-xxxx-xxxxxx394ecb/v2.0
          audiences:
            - 4f82xxxx-xxxx-xxxx-xxxx-xxxxxx5fa07b

手順②:実行結果

アクセストークンを確認してみるとiss(issuer)とaud(audience)が一致していることが確認できました。(以下✅のところ)

{
  "aud": "4f82xxxx-xxxx-xxxx-xxxx-xxxxxx5fa07b", ← ✅ 完全一致している
  "iss": "https://login.microsoftonline.com/4647xxxx-xxxx-xxxx-xxxx-xxxxxx394ecb/v2.0", ← ✅ 完全一致している
:
(以下略)

今回のポイント

前回記事ではフロントエンドの設定でaud(audience)を指定する際、以下のように「api://」というプレフィックスを記述していました。

VITE_OIDC_SCOPE=openid profile email api://4f82xxxx-xxxx-xxxx-xxxx-xxxxxx5fa07b/.default

しかしバックエンドの設定ファイル(application.yml)では

          audiences:
            - api://4f82xxxx-xxxx-xxxx-xxxx-xxxxxx5fa07b ← ❌ 「api://」は不要

ではなく、以下のようにプレフィックスなしで記述する必要があるので注意が必要です。

          audiences:
            - 4f82xxxx-xxxx-xxxx-xxxx-xxxxxx5fa07b ← ✅ 「api://」なしが正解

また、aud(audience)は複数形の「audiences」でありリスト型式で記述します。(以下参照)

          audiences:
            - my-api-audience
            - another-allowed-audience

アクセストークンに含まれる'aud'クレームがこのリストのいずれかと一致するか検証されるという仕組みになっているようです。

参考

Microsoft Entra ID (旧 Azure AD) をIdPとしてOIDC認証する際の注意点(フロントエンド)

AWS CognitoでOIDC認証していたWebアプリケーション(SPA)のIdPをMicrosoft Entra ID (旧 Azure AD) に変更した時に遭遇した注意点について記載します。

本記事に記載した注意点を実際に動かして確認したい場合は、以下のサンプルアプリ(Reactで実装されたSPA)を使えば簡単に試すことができます。

github.com

変更前IdP:Amazon Cognito

Amazon CognitoをIdPとして以下のようなエンドポイントを指定していました。

フロントエンドの設定

以下のようなエンドポイントを指定しました。

VITE_OIDC_AUTHORITY=https://cognito-idp.ap-northeast-1.amazonaws.com/ap-northeast-1_xxxxxxxxx
VITE_OIDC_CLIENT_ID=xxxxxxxxxxxxxxxxxxxxxxxxxx
VITE_OIDC_REDIRECT_URI=http://localhost:5173
VITE_OIDC_SCOPE=openid profile email

この設定で特に問題なくOIDC認証ができていました。

変更後IdP:Microsoft Entra ID (旧 Azure AD)

Microsoft Entra ID (旧 Azure AD)をIdPに変更したところいくつかの問題に遭遇しました。

遭遇1:アクセストークンがInvalid Signature (無効な署名)になる

手順①:Microsoft Entra ID でアプリを新規登録

Azure ポータルのMicrosoft Entra ID で以下のようにアプリを登録しました。

概要

管理 -> Authentication (Preview):リダイレクトURIの構成

管理 -> API のアクセス許可

手順②:フロントエンドの設定

以下のようなエンドポイントを指定しました。

VITE_OIDC_AUTHORITY=https://login.microsoftonline.com/4647xxxx-xxxx-xxxx-xxxx-xxxxxx394ecb/v2.0
VITE_OIDC_CLIENT_ID=4f82xxxx-xxxx-xxxx-xxxx-xxxxxx5fa07b
VITE_OIDC_REDIRECT_URI=http://localhost:5173
VITE_OIDC_SCOPE=openid profile email

手順③:実行結果

取得したアクセストークンの署名検証結果がInvalid Signature(無効な署名)になってしまいました。 アクセストークンを確認してみると audience(aud)がMicrosoft Graphになっていました。(以下❌のところ)

{
  "aud": "00000003-0000-0000-c000-000000000000", ← ❌ Microsoft Graph になっている
  "iss": "https://sts.windows.net/4647xxxx-xxxx-xxxx-xxxx-xxxxxx394ecb/",
  "iat": 1771046123,
  "nbf": 1771046123,
  "exp": 1771051527,
  "acct": 0,
  "acr": "1",
  "acrs": [
    "p1"
  ],
  "aio": "xxxxx",
  "altsecid": "1:live.com:XXXXXXXXXXXXXXXX",
  "amr": [
    "pwd",
    "mfa"
  ],
  "app_displayname": "web-app-sample",
  "appid": "4f82xxxx-xxxx-xxxx-xxxx-xxxxxx5fa07b",
  "appidacr": "0",
  "email": "xxxxxxxxxx@gmail.com",
  "family_name": "山田",
  "given_name": "一郎",
  "idp": "live.com",
  "idtyp": "user",
  "ipaddr": "xxx.xxx.xxx.xxx",
  "name": "山田 一郎",
  "oid": "0bf5xxxx-xxxx-xxxx-xxxx-xxxxxxd0f6a6",
  "platf": "3",
  "puid": "1003200378EAFE7B",
  "rh": "xxxxx",
  "scp": "email User.Read profile openid",
  "sid": "0020xxxx-xxxx-xxxx-xxxx-xxxxxx5f5cab",
  "signin_state": [
    "kmsi"
  ],
  "sub": "xxxxx",
  "tenant_region_scope": "JPR",
  "tid": "4647xxxx-xxxx-xxxx-xxxx-xxxxxx394ecb",
  "unique_name": "live.com#xxxxxxxxxx@gmail.com",
  "uti": "xxxxx",
  "ver": "1.0",
  "wids": [
    "62e9xxxx-xxxx-xxxx-xxxx-xxxxxx145e10",
    "b79fxxxx-xxxx-xxxx-xxxx-xxxxxxe85509"
  ],
  "xms_acd": xxxxx,
  "xms_act_fct": "X X",
  "xms_ftd": "xxxxx"
  "xms_idrel": "X XX",
  "xms_st": {
    "sub": "xxxxx"
  },
  "xms_sub_fct": "X XX",
  "xms_tcdt": xxxxx,
  "xms_tnt_fct": "X XX"
}

これは以下の記事と同じことが発生しており Microsoft Entra IDとフロントエンドの両方で設定の見直しが必要です。

Microsoft ID プラットフォームのアクセストークンが”Invalid Signature”になる件 その1:Express + Passport編 | 株式会社アイオス


遭遇2:アクセストークンのバージョンが想定外(v1.0 トークン)

手順①:Microsoft Entra ID でアプリに設定追加

Azure ポータルのMicrosoft Entra ID で以下のようにアプリ設定を追加しました。

管理 -> API の公開

【↓】スコープ名は「web-app-backend」としています。

手順②:フロントエンドの設定

以下のようなエンドポイントを指定しました。

VITE_OIDC_AUTHORITY=https://login.microsoftonline.com/4647xxxx-xxxx-xxxx-xxxx-xxxxxx394ecb/v2.0
VITE_OIDC_CLIENT_ID=4f82xxxx-xxxx-xxxx-xxxx-xxxxxx5fa07b
VITE_OIDC_REDIRECT_URI=http://localhost:5173
VITE_OIDC_SCOPE=openid profile email api://4f82xxxx-xxxx-xxxx-xxxx-xxxxxx5fa07b/.default

手順③:実行結果

今回は得したアクセストークンの署名検証結果がSignature Verified(署名確認済み)になってしまいました。 アクセストークンを確認してみると audience(aud)やscope(scp)が登録したアプリのものに変更されていました。(以下✅のところ) しかしフロントエンドの設定でエンドポイントは2.0を指定したのに、iss(issuer)やアクセストークンのver(version)が「1.0」となっています。(上記❌のところ)

{
  "aud": "api://4f82xxxx-xxxx-xxxx-xxxx-xxxxxx5fa07b", ← ✅ 登録したアプリになっている
  "iss": "https://sts.windows.net/4647xxxx-xxxx-xxxx-xxxx-xxxxxx394ecb/", ← ❌ v1.0 のエンドポイント
  "iat": 1771043342,
  "nbf": 1771043342,
  "exp": 1771048647,
  "acr": "1",
  "aio": "xxxxx",
  "amr": [
    "pwd",
    "mfa"
  ],
  "appid": "4f82xxxx-xxxx-xxxx-xxxx-xxxxxx5fa07b",
  "appidacr": "0",
  "email": "xxxxxxxxxx@gmail.com",
  "family_name": "山田",
  "given_name": "一郎",
  "idp": "live.com",
  "ipaddr": "xxx.xxx.xxx.xxx",
  "name": "山田 一郎",
  "oid": "0bf5xxxx-xxxx-xxxx-xxxx-xxxxxxd0f6a6",
  "rh": "xxxxx",
  "scp": "web-app-backend", ← ✅ 登録したアプリになっている
  "sid": "0020xxxx-xxxx-xxxx-xxxx-xxxxxx3fb9da",
  "sub": "xxxxx",
  "tid": "4647xxxx-xxxx-xxxx-xxxx-xxxxxx394ecb",
  "unique_name": "live.com#xxxxxxxxxx@gmail.com",
  "uti": "xxxxx",
  "ver": "1.0", ← ❌ v1.0 トークン
  "xms_ftd": "xxxxx"
}

最終版:アクセストークンのバージョンを是正(v2.0 トークンへ)

手順①:Microsoft Entra ID でアプリの設定変更

Azure ポータルのMicrosoft Entra ID で以下のようにアプリ設定を変更しました。

管理 -> マニフェスト

変更前: "accessTokenAcceptedVersion": null,  ← v1.0 トークンを発行(デフォルト値)
変更後: "accessTokenAcceptedVersion": 2,     ← v2.0 トークンを発行

手順②:フロントエンドの設定

以下のようなエンドポイントを指定しました。(※問題2と同様のため変更不要です)

VITE_OIDC_AUTHORITY=https://login.microsoftonline.com/4647xxxx-xxxx-xxxx-xxxx-xxxxxx394ecb/v2.0
VITE_OIDC_CLIENT_ID=4f82xxxx-xxxx-xxxx-xxxx-xxxxxx5fa07b
VITE_OIDC_REDIRECT_URI=http://localhost:5173
VITE_OIDC_SCOPE=openid profile email api://4f82xxxx-xxxx-xxxx-xxxx-xxxxxx5fa07b/.default

手順③:実行結果

アクセストークンを確認してみるとちゃんとiss(issuer)やver(version)が「2.0」になっていました。(以下✅のところ)

{
  "aud": "4f82xxxx-xxxx-xxxx-xxxx-xxxxxx5fa07b",
  "iss": "https://login.microsoftonline.com/4647xxxx-xxxx-xxxx-xxxx-xxxxxx394ecb/v2.0", ← ✅ v2.0 のエンドポイント
  "iat": 1771043595,
  "nbf": 1771043595,
  "exp": 1771048913,
  "aio": "xxxxx",
  "azp": "4f82xxxx-xxxx-xxxx-xxxx-xxxxxx5fa07b",
  "azpacr": "0",
  "idp": "live.com",
  "name": "山田 一郎",
  "oid": "0bf5xxxx-xxxx-xxxx-xxxx-xxxxxxd0f6a6",
  "preferred_username": "xxxxxxxxxx@gmail.com",
  "rh": "xxxxx",
  "scp": "web-app-backend",
  "sid": "0020xxxx-xxxx-xxxx-xxxx-xxxxxx5f5cab",
  "sub": "xxxxx",
  "tid": "4647xxxx-xxxx-xxxx-xxxx-xxxxxx394ecb",
  "uti": "xxxxx",
  "ver": "2.0", ← ✅ v2.0 トークンになっている
  "xms_ftd": "xxxxx"
}

補足

上記の例ではフロントエンドの設定でscope(scp)を以下のように指定しましたが、末尾の .default というのがワイルドカード的な意味(全て)になっています。

VITE_OIDC_SCOPE=openid profile email api://4f82xxxx-xxxx-xxxx-xxxx-xxxxxx5fa07b/.default

より厳密に制御する必要がある場合は、以下のように許可するスコープ名を個別に指定するようにします。

VITE_OIDC_SCOPE=openid profile email api://4f82xxxx-xxxx-xxxx-xxxx-xxxxxx5fa07b/web-app-backend

ただし今回の例では、そもそもスコープが1つしか定義されていないため、いずれもアクセストークンのscope(scp)は同じ内容になります。

おわりに

当初は、各IdPともにOIDCという標準的な共通のルールに則って実装されているだろうからフロントエンドのエンドポイントの向き先を変更するだけでサクッと変更できるものと考えていましたが、実際にやってみると各IdPごとに違いがあり、クライアント側だけでなくIdP側も仕様を理解して正確に設定しないと期待した通り動作してくれませんでした。もちろん知っていれば非常に簡単な設定ではあるのですが、当初の認識の甘さも相まって期待した挙動になるまでに、何度も試行錯誤することになりました。このあたりの見通しの甘さは反省が必要ですね。

VSCodeでエディタ文字サイズ変更後にサクッと元に戻す方法

VSCodeで画面共有するときなど、一時的にエディタ文字サイズを変更したいことがあります。その方法と、その後サクッと元に戻すための小技メモです。

エディタ文字サイズ(のみ)を変更する方法

一時的にエディタ文字サイズ(のみ)を変更したい場合は、VSCodeの設定で「Editor: Mouse Wheel Zoom」をONにします。

この設定だけでChromeなどと同じノリ(「Ctrl」+ホイール)で簡単にエディタ文字サイズ(のみ)を変更できます。

<初期状態>


<拡大状態>

おっきくて見やすいですね

エディタ文字サイズ(のみ)を元に戻す方法

性格的な問題かもしれませんが、用が済んだら初期状態に戻さないと気持ち悪いので、その方法についても記載しておきます。残念ながら現状ではVSCodeの設定変更だけでは簡単に実現できなそうだったので拡張機能「Zoom Bar」をインストールしました。

この拡張機能をインストールするとVSCodeの画面の下側にステータスが表示されるようになります。この中で以下の「エディターのフォントのズームをリセット」と言うボタンをクリックすると一発で初期状態のフォントサイズに戻すことができます。

これでもう気持ち悪くない