NTT西日本のブログ - TECH PLAY

TECH PLAY

NTT西日本

NTT西日本 の技術ブログ

85

はじめに 対象読者 背景・目的 SimcirJSとは まずは触ってみよう JKフリップフロップ回路 まず、フリップフロップとは JKフリップフロップとは クロックとは カウンタ回路を作る 3進カウンタへの道 どうやって3進に 強制リセット なければ作る!? リセット付きJK-FF 登録のやり方・・・ httpdサーバ 自作部品の登録 自分で追加した回路を使って組み上げる 3進カウンタ 動作例 さいごに まとめ 執筆者 参考資料・出典 SimcirJSを利用できるサイト ライセンス はじめに NTT西日本の ふるかわ といいます。 本記事は、入社XX年(ナイショ)のベテラン(?)技術者が、ひさしぶりにディジタル回路シミュレータを触ってみたくなった顛末記のようなものです。 本記事は2025年11月時点の情報に基づいています。 対象読者 まわりの記事と比較すると、すこし異色かも知れません。 本記事は、ディジタル回路に興味があるひと、「コンピュータの中身ってどうやって動いてるんだっけ」ということをちょっと覗いてみたいひと、などに、ごく簡単な導入ができたらいいな、と思って書き記すものです。 あまり、お勉強お勉強にならないように気を付けますが、代わりに(?)学術的に厳密でもないかも知れないので、入門編の読み物としてサラっと読んでみていただけるとありがたいです。 背景・目的 あまりこれと言った背景はないのですが、なぜか無性に「3進カウンタ」が作りたくなりました。 0→1→2→0→1→2→… と、みっつの値を繰り返すカウンタです。野球の「ストライク」(または「アウト」)のカウンタをイメージしてもらうとよろしいかと思います。 ディジタル回路の特性上、2 n 進カウンタ(2進、4進、8進、…)はとても簡単に作れるのですがそれ以外のカウンタは、ちょっと面倒だったりします。 こんなとき、約四半世紀前に大学生をしていたころなら、巨大なディジタル回路実験盤を持ち出して大変な思いをしていましたが、イマドキそんなのはシミュレータを使えば簡単にシミュレーションできるようになっています。 しかもありがたいことに無償で使えるものもありますから、これを活用するのが便利です。ということで、ひさびさの利用になる「SimcirJS」というシミュレータを使ってみることにしました。 SimcirJSとは HTML5とJavaScriptでできたディジタル回路シミュレータで、MITライセンスで公開されています。 ブラウザから利用できるため、インストール不要で使い始めることができます。高専・大学等の授業でも多く利用されているようで、教材等が公開されているものもあります。 わたしも、いくつかのサイトを参考にさせていただきました。それらは、文末の参考資料の節にまとめます。 まずは触ってみよう SimcirJSの作者さんのサイト「Kazuhiko Arase's Workplace」 https://kazuhikoarase.github.io/simcirjs/index.html にアクセスすれば、すぐに利用することができます。 SimcirJSの画面例 左側から回路の要素を選んで、右側にドラッグアンドドロップし、 SimcirJSの操作例 回路の端子同士をドラッグ操作でつなぐと結線されます。 SimcirJSの結線操作例 このとき注意事項は、回路の右側の端子(白)は出力で、いくつも分岐させられますが、 回路の左側の端子(橙)は入力になるので、分岐はできません。 「DC」は直流電源(Direct Current)、「LED」は発光ダイオード(Light-Emitting Diode)なので、このふたつを結線すると、「LEDが光った」ことになり、 画面上ではLEDの表示が黒丸から赤丸に変わります。 SimcirJS動作例、DCとLEDを結線するとLEDが点灯する 試しに、ディジタル回路らしく、AND回路とOR回路の動きを確かめておきましょう。 どちらも入力をふたつ・出力をひとつ持つ回路ですが、 AND回路は入力が両方とも1のときだけ出力も1に、 逆にOR回路は入力が両方とも0のときだけ出力も0に、 それぞれなるような回路です。 ここで、0とは電圧なし、1は電圧ありのことなので、「DC」回路とトグルスイッチ(「Toggle」)を使って、次のような回路を組んでみましょう。 SimcirJSの動作例 AND回路とOR回路 「トグルスイッチ」とは、部屋の電気(照明)のスイッチのように、スイッチから指を離しても切り替わった状態が維持されるようなスイッチのことです。 「Toggle」の上にある「PushOn」「PushOff」のスイッチは、指で押している間だけON(またはOFF)になるようなスイッチです。 このような動作確認のときは、指を離しても切り替わったままになっている方が便利なので、トグルスイッチを利用するのがよいでしょう。 トグルスイッチをONにすれば「DC」とつながって電圧あり(つまり入力1)、OFFなら電圧なし(入力0)になりますから、 ANDとORの動きを確かめることができました。 JKフリップフロップ回路 まず、フリップフロップとは フリップフロップ回路とは、1bit (2値) の状態を保持できる回路のことです。 「フリップフロップ」(flip-flop) とは、シーソーがあっちこっちに傾くときの擬音だそうで、 その名の通り、シーソーを思い浮かべていただくのがいちばん分かりやすいと思います。 いま、なにも乗っていないシーソーが左に傾いているとします。なにもしなければ左に傾いているままです。 そこで右側にだけ荷物をのせると、今度は右に傾きます。ここまでは当たり前なのですが、 ミソはその次で、右に傾いたあとで、荷物を降ろすとどうなるでしょうか。そうです、荷物を降ろしても シーソーは右に傾いたままになります。次にもういちど左に荷物を載せて、左に傾けると、 その荷物を降ろした後もシーソーは左に傾いたままになります。 これはどういうことかというと、シーソーは、「最後に荷物が載った状態(降ろす直前の状態)」を「保持している」 ということになります。言い換えると「最後に荷物が載った側がどちらか」を「覚えている」とも言えます。 この「右」と「左」を「0」と「1」に読み替えると、シーソーは1bitのメモリ装置である、と言えることになります。 フリップフロップ回路もシーソーと同じように、最後にかけられた信号の状態を保持するような回路です。 JKフリップフロップとは フリップフロップ回路には、いくつかの種類があります。 その中のひとつであるJKフリップフロップ回路(以下 JK-FF) は、JとKのふたつの値とクロック(CLK)、合計3つの入力端子を持っています。 また、出力としてはQと~Qのふたつの端子を持っています。「~Q」は、「Qの逆」という意味で、Q=0なら~Q=1、Q=1なら~Q=0という関係です。 まずはふたつの値、JとKについて説明します。 (J,K)=(1,0)のときは、フリップフロップ回路の状態には「1」がセットされます。右に傾いた状態です。このときフリップフロップ回路の出力も「1」になります。 (J,K)=(0,1)のときは、同様に値0がセットされます。左に傾いた状態です。フリップフロップ回路の出力は「0」になります。 (J,K)=(0,0)のとき、つまり入力が何もないときは、前の状態を保持します。シーソーどちらにも荷物がない状態なので、 最後に傾いた方を覚えています。フリップフロップ回路の出力は、直前の出力が継続されます。 次にJK-FFのいちばんの特徴である、(J,K)=(1,1)のときの動きです。シーソーに喩えると、「両側に荷物を載せた状態」 とも言える、特殊な入力です。シーソーであれば、右にも左にも傾かず、水平に釣り合ってしまいます。ディジタル回路では、 これはすこしマズそうです。0でも1でもないものは存在させられないですから。なので、JK-FFでは、(J,K)=(1,1)のときは、 「いまの状態を反転させる」という特別な動きを定義しています。いまが1なら0をセット、いまが0なら1をセット、 というように動きます。したがって、フリップフロップからの出力も、直前の出力と逆のものに切り替えられます。 これを利用することで、JK-FFの状態を0→1→0→1…と順に変更していくことができます。 なにかに使えそうです。 ただしひとつ注意すべき点があります。(J,K)=(1,1)の状態をずっと続けるとどうなるでしょうか。 これもシーソーに喩えると、シーソーが右に左にバタバタしてしまいそうです。「ボタンを押したらシーソーが 左右に倒れる装置」があったとして、そのボタンをポチ・ポチ・…と押しているときはいいのですが、 「長押し」をしてしまうとよくなさそうです。さらに付け加えると、「長押し」でなかったとしても、 ポチっと1回だけ押したつもりがバタバタっと左右に2回分の動きになってしまうかも知れません。 これはまずいです。 最後に出力Q・~Qですが、これはJKーFFの状態により、0または1のどちらかが出力されます。 JK-FFの状態が0のときはQ=0が、JK-FFの状態が1のときはQ=1がそれぞれ出力されます。 先に述べたように(J,K)=(1,1)が入力され、JK-FFの状態が0→1→0→1…と切り替わるとき、 出力Qの値も、Q=0→1→0→1…と切り替わります。 クロックとは そこでJK-FFにもうひとつ、クロック(CLK)という入力を付けます。 クロックというのは、「CPUの最大クロックは5.4GHz」などと言っている、このクロックと同じものです。 クロックを喩えるなら、「メトロノーム」を思い浮かべてください。音楽の時間に使う、カチコチとリズムを取る、あれです。 ディジタル回路のさまざまな動作を、メトロノームがカチコチとリズムを刻んだ瞬間だけ動作するように制御します。 (J,K)=(1,1)の入力をずっと続けていても、メトロノームがカチコチと刻んだタイミングだけ、シーソーが倒れるように すればよい、というアイディアです。この「メトロノームがカチコチと刻んだタイミング」のことを、「クロックタイミング」といいます。クロックタイミングが1秒間に何回訪れるかを示すのが「クロック周波数」です。 ですので、クロック周波数が速いと、クロックタイミングがより頻繁に訪れ、よってシーソーの倒れる頻度が高くなります。 「CPUのクロック周波数が速いと計算能力も高い」ということと、なんとなくですが結び付きそうです。 ちなみにクロック波形には通常は矩形波(方形波)を入力しますが、矩形波の立ち上がりまたは立ち下がり どちらかの瞬間をクロックタイミングとするケースが多いです。SimcirJSのJK-FFでは、 立ち下がりの瞬間をクロックタイミングとしています。PushOnボタン操作でいうと、押して、離した瞬間が クロックタイミングになります。(これ、実は後の伏線になっています。) クロック波形の例 カウンタ回路を作る 前置きが長くなりましたが、このJK-FFを使って、カウンタ回路を作ることができます。 クロック入力付きのJK-FF回路は、SimcirJSに初めから登録されているので、これを利用しましょう。 SimcirJSのJKフリップフロップ回路 JK-FFの「(J,K)=(1,1)のときはいまの状態を反転させる」を利用すると、 J=K=1のとき、クロックタイミングごとに 状態がOFF→ON→OFF→ON…と変化していきます。 状態が変化するので、あわせて出力も0→1→0→1…と変化します。 これは、見方を変えると、入力をJ=K=1に固定しておくと、クロックが入るごとに状態が変わることになります。 さらに言い換えると、クロックが入った回数を、1回だけ数えている、ということになります。 記憶できる値が0か1かの1bitなので、すぐに桁あふれ(オーバーフロー)を起こしてしまいますが 動作としては「カウンタ」と言えるものができます。「1bitのカウンタ」です。 SimcirJSでJK-FFで1bitカウンタを作る ただ、数えられる値があまりに少なすぎて、「カウンタ」というイメージがあまり湧きません。 どうにかして、もう少し多くの値を数えられるようにならないでしょうか。 桁あふれ(オーバーフロー)してしまうのが問題なので、「桁上がり」の仕組みを作れば、桁数を増やして 数えられる値を増やしていけそうです。 桁上がりの仕組みなので、0→1になって、次に1→0になるときに、上位桁をひとつ繰り上げればよいことになります。 というのはよいのですが、実際問題として「1→0になるとき」を検出するのは、どうすればよいでしょうか。 1→0になる、ON→OFFになる、矩形波が立ち下がる、…。そうなんです、実は、JK-FFの出力(Q)を、 そのまま次のJK-FFのCLKに入れるだけでいいんです。「立ち下がりがクロックタイミングになっている」のは この応用を見越した伏線だったのです。非常に巧妙な設計ですね。 ということで、こういう回路を組んでみます。実際どうなるか SimcirJSでJK-FFで2bitカウンタを作る …と、2bitのカウンタができあがりました。2bitなので4値、つまり0→1→2→3→0→1→2→3→…、 と数えられます。同じように後ろに後ろにJK-FFをつなげていくと、3bit、4bit、…のカウンタが作れます。 冒頭で「2 n 進カウンタはとても簡単に作れる」と記載しましたが、このとおりです。 3進カウンタへの道 どうやって3進に さて、欲しいのは3進カウンタでした。つまり0→1→2→0→1→2→… と繰り返してほしいのです。 ぱっと思いつくのは、3より大きな最小の2 n 数である4進カウンタを使って、 0→1→2→3→0→1→2→3→…となるところの「余計なもの」つまり「→3」の部分を削る方法です。 「カウンタ状態が3のときにも、表示上は2と同じにする」という方法もありますが、 この場合0→1→2→2→0→1→2→2→…という、ちょっとコレジャナイ感のカウンタができてしまうので却下とします。 強制リセット 「→3 の部分を削る」と書きましたが、「→3」の瞬間で状態をリセットしてしまうと、→3が削られることになります。 JK-FFの状態を無理やりリセットできると便利そうです。 市販の実際のICチップでは、リセット(クリア)のついたJK-FFがいろいろ販売されています。 例えばテキサスインスツルメンツ社 SN74LS73AN、や、東芝社 TC74HC107AF などがそうです。 ですが、SimcirJSで用意されているJK-FFには、リセット端子はありません。 なければ作る!? 筆者は実家が町工場でして、幼少の頃より「なければ作る、壊れたら直す」の精神で生きてきました(若干誇張)。 「リセット付きJK-FF」も、ANDやORを組み合わせれば作れますので、なければ作るの精神で臨んでみましょう。 ちなみに元から用意されているJK-FFも、実はANDやORの組み合わせで作られています。JK-FFのパーツを ダブルクリックすると SimcirJSの標準準備のJK-FFの中身 のように、登録されている回路が出てきます。高級言語のライブラリ関数のようなものですね。 なので、同じように「リセット付きJK-FF」をひとつ自作して、登録してしまいましょう。 リセット付きJK-FF ということで、もとのJK-FFの中身を参考にしながら、リセット付きJK-FFの回路を作りました。 SimcirJSでのリセット付きJKフリップフロップ構成例 リセット付きJKフリップフロップの回路図例 これを解説しているとちょっと長くなりそうなので、すいませんが、ポイントだけにします。 SimcirJS標準のJK-FFの回路にリセット(RST)入力端子を付け足して、ここに入力があった際には、両方の「RS-FF」にリセット入力(~S,~R)=(1,0)が入るようにしました(青破線部) (このとき、SimcirJS標準搭載のRS-FFは、入力が(S,R)ではなく、(~S,~R)であることに注意) その他の部分はSimcirJS標準のJK-FFの回路を基にしていますが、「3入力NAND」回路を、2入力AND回路とNOT回路に分解しています(赤破線部) この通り作るか、またはJSONコードを載せておくので、使ってみてください。 リセット付きJK-FFのJSONコードを表示 { "width":800, "height":400, "showToolbox":false, "toolbox":[ ], "devices":[ {"type":"DC","id":"dev0","x":16,"y":144,"label":"DC"}, {"type":"Toggle","id":"dev1","x":80,"y":88,"label":"Toggle","state":{"on":false}}, {"type":"PushOn","id":"dev2","x":80,"y":144,"label":"PushOn"}, {"type":"PushOn","id":"dev3","x":80,"y":304,"label":"PushOn"}, {"type":"Toggle","id":"dev4","x":80,"y":208,"label":"Toggle","state":{"on":false}}, {"type":"AND","id":"dev5","x":208,"y":112,"label":"AND"}, {"type":"AND","id":"dev6","x":208,"y":184,"label":"AND"}, {"type":"AND","id":"dev7","x":264,"y":112,"label":"AND"}, {"type":"NOT","id":"dev8","x":328,"y":112,"label":"NOT"}, {"type":"NOT","id":"dev9","x":328,"y":184,"label":"NOT"}, {"type":"RS-FF","id":"dev10","x":384,"y":144,"label":"RS-FF"}, {"type":"NAND","id":"dev11","x":472,"y":112,"label":"NAND"}, {"type":"NAND","id":"dev12","x":472,"y":184,"label":"NAND"}, {"type":"NOT","id":"dev13","x":288,"y":320,"label":"NOT"}, {"type":"AND","id":"dev14","x":344,"y":320,"label":"AND"}, {"type":"OR","id":"dev15","x":312,"y":272,"label":"OR"}, {"type":"NOT","id":"dev16","x":472,"y":320,"label":"NOT"}, {"type":"AND","id":"dev17","x":536,"y":320,"label":"AND"}, {"type":"LED","id":"dev18","x":424,"y":32,"label":"LED"}, {"type":"LED","id":"dev19","x":576,"y":32,"label":"LED"}, {"type":"NOT","id":"dev20","x":208,"y":32,"label":"NOT"}, {"type":"OR","id":"dev21","x":512,"y":272,"label":"OR"}, {"type":"RS-FF","id":"dev22","x":552,"y":144,"label":"RS-FF"}, {"type":"AND","id":"dev23","x":264,"y":184,"label":"AND"}, {"type":"In","id":"dev24","x":144,"y":88,"label":"J"}, {"type":"In","id":"dev25","x":144,"y":144,"label":"CLK"}, {"type":"In","id":"dev26","x":144,"y":208,"label":"K"}, {"type":"In","id":"dev27","x":144,"y":304,"label":"RST"}, {"type":"Out","id":"dev28","x":632,"y":96,"label":"Q"}, {"type":"Out","id":"dev29","x":632,"y":192,"label":"~Q"} ], "connectors":[ {"from":"dev1.in0","to":"dev0.out0"}, {"from":"dev2.in0","to":"dev0.out0"}, {"from":"dev3.in0","to":"dev0.out0"}, {"from":"dev4.in0","to":"dev0.out0"}, {"from":"dev5.in0","to":"dev24.out0"}, {"from":"dev5.in1","to":"dev25.out0"}, {"from":"dev6.in0","to":"dev25.out0"}, {"from":"dev6.in1","to":"dev26.out0"}, {"from":"dev7.in0","to":"dev5.out0"}, {"from":"dev7.in1","to":"dev22.out1"}, {"from":"dev8.in0","to":"dev7.out0"}, {"from":"dev9.in0","to":"dev23.out0"}, {"from":"dev10.in0","to":"dev15.out0"}, {"from":"dev10.in1","to":"dev14.out0"}, {"from":"dev11.in0","to":"dev20.out0"}, {"from":"dev11.in1","to":"dev10.out0"}, {"from":"dev12.in0","to":"dev10.out1"}, {"from":"dev12.in1","to":"dev20.out0"}, {"from":"dev13.in0","to":"dev27.out0"}, {"from":"dev14.in0","to":"dev9.out0"}, {"from":"dev14.in1","to":"dev13.out0"}, {"from":"dev15.in0","to":"dev8.out0"}, {"from":"dev15.in1","to":"dev27.out0"}, {"from":"dev16.in0","to":"dev27.out0"}, {"from":"dev17.in0","to":"dev12.out0"}, {"from":"dev17.in1","to":"dev16.out0"}, {"from":"dev18.in0","to":"dev10.out0"}, {"from":"dev19.in0","to":"dev22.out0"}, {"from":"dev20.in0","to":"dev25.out0"}, {"from":"dev21.in0","to":"dev11.out0"}, {"from":"dev21.in1","to":"dev27.out0"}, {"from":"dev22.in0","to":"dev21.out0"}, {"from":"dev22.in1","to":"dev17.out0"}, {"from":"dev23.in0","to":"dev22.out0"}, {"from":"dev23.in1","to":"dev6.out0"}, {"from":"dev24.in0","to":"dev1.out0"}, {"from":"dev25.in0","to":"dev2.out0"}, {"from":"dev26.in0","to":"dev4.out0"}, {"from":"dev27.in0","to":"dev3.out0"}, {"from":"dev28.in0","to":"dev22.out0"}, {"from":"dev29.in0","to":"dev22.out1"} ] } 説明していませんでしたが、SimcirJSの回路は、全部JSONで表記が可能です。 ワークエリアを Ctrl+クリック すると表示が切り替わります。もういちどCtrl+クリックすると元の表示に戻ります。 (Mac系マシンご利用の場合は Command+クリック です) SimcirJSの画面例 JSONコード表示 登録のやり方・・・ さて登録だ、と思ったのですが、登録方法は「simcir-library.js ファイルに回路定義した内容を追記する」とのこと。 ということは、サイト上のSimcirJSの設定ファイルの編集権限が必要、ということになります。 つまり、誰かが立てたサイト上のSimcirJSを使わせてもらってるのではだめで、 自分でhttpdを立てて、自らSimcirJSをインストールせよ、ということになります。 httpdサーバ 筆者はたまたま手元にESXi環境があり、LinuxOSの仮想マシンが稼働していたので、ここにさっとhttpdを立てて、SimcirJSを置いてみました。 サイトさえ立てばよく、必ずしもLinuxである必要はありませんので、手元にLinux環境がない場合は、Windowsのローカル環境にhttpdを 立てるやり方でも大丈夫です。 SimcirJSの入手方法については、いま https://kazuhikoarase.github.io/simcirjs/index.html を利用しているなら、画面上の方にダウンロードボタンがあります。 SimcirJSのダウンロード または https://github.com/kazuhikoarase/simcirjs/archive/master.zip からダウンロードできます(同じリンク先です)。 インストールといっても./configure も make も不要で、ダウンロードしたZIPファイルを展開し、 そのファイル群を httpd の DocumentRoot 下のどこかにコピーするだけの簡単インストールです。 そのまま展開するとフォルダ名が「simcirjs-master」になりますが、ちょっと長いのでフォルダ名を「simcirjs」とし、 DocumentRoot直下の、/var/www/html/simcirjs/ に、一式をコピーしました。 あと、そのままでは index.html ファイルがなく、アクセスが少し面倒なので、sample.html をそのままコピーして index.html を作っておきました。 これで、自PC上のブラウザから、自前のSimcirJSが利用できるようになりました。 自作部品の登録 自作部品の登録は先は [DocumentRoot]/simcirjs/simcir-library.js のファイルです。先ほど作った「リセット付きJK-FF」を いちばん最後に追記しておきます。追記後の simcir-library.js を掲載しますが、ちょっと長いので、スクロールしてご覧ください。 部品の名称は「JK-FF-RST」としました。 // // SimcirJS - library // // Copyright (c) 2014 Kazuhiko Arase // // URL: http://www.d-project.com/ // // Licensed under the MIT license: // http://www.opensource.org/licenses/mit-license.php // // includes following device types: // RS-FF // JK-FF // T-FF // D-FF // 8bitCounter // HalfAdder // FullAdder // 4bitAdder // 2to4BinaryDecoder // 3to8BinaryDecoder // 4to16BinaryDecoder simcir.registerDevice('RS-FF', { "width":320, "height":160, "showToolbox":false, "toolbox":[ ], "devices":[ {"type":"NAND","id":"dev0","x":184,"y":32,"label":"NAND"}, {"type":"NAND","id":"dev1","x":184,"y":80,"label":"NAND"}, {"type":"In","id":"dev2","x":136,"y":24,"label":"~S"}, {"type":"In","id":"dev3","x":136,"y":88,"label":"~R"}, {"type":"Out","id":"dev4","x":232,"y":32,"label":"Q"}, {"type":"Out","id":"dev5","x":232,"y":80,"label":"~Q"}, {"type":"PushOff","id":"dev6","x":88,"y":24,"label":"PushOff"}, {"type":"PushOff","id":"dev7","x":88,"y":88,"label":"PushOff"}, {"type":"DC","id":"dev8","x":40,"y":56,"label":"DC"} ], "connectors":[ {"from":"dev0.in0","to":"dev2.out0"}, {"from":"dev0.in1","to":"dev1.out0"}, {"from":"dev1.in0","to":"dev0.out0"}, {"from":"dev1.in1","to":"dev3.out0"}, {"from":"dev2.in0","to":"dev6.out0"}, {"from":"dev3.in0","to":"dev7.out0"}, {"from":"dev4.in0","to":"dev0.out0"}, {"from":"dev5.in0","to":"dev1.out0"}, {"from":"dev6.in0","to":"dev8.out0"}, {"from":"dev7.in0","to":"dev8.out0"} ] } ); simcir.registerDevice('JK-FF', { "width":480, "height":240, "showToolbox":false, "toolbox":[ ], "devices":[ {"type":"RS-FF","id":"dev0","x":216,"y":112,"label":"RS-FF"}, {"type":"RS-FF","id":"dev1","x":344,"y":112,"label":"RS-FF"}, {"type":"NAND","numInputs":3,"id":"dev2","x":168,"y":80,"label":"NAND"}, {"type":"NAND","numInputs":3,"id":"dev3","x":168,"y":144,"label":"NAND"}, {"type":"NAND","id":"dev4","x":296,"y":80,"label":"NAND"}, {"type":"NAND","id":"dev5","x":296,"y":144,"label":"NAND"}, {"type":"NOT","id":"dev6","x":168,"y":24,"label":"NOT"}, {"type":"In","id":"dev7","x":120,"y":64,"label":"J"}, {"type":"In","id":"dev8","x":120,"y":112,"label":"CLK"}, {"type":"In","id":"dev9","x":120,"y":160,"label":"K"}, {"type":"Out","id":"dev10","x":424,"y":80,"label":"Q"}, {"type":"Out","id":"dev11","x":424,"y":144,"label":"~Q"}, {"type":"Toggle","id":"dev12","x":72,"y":64,"label":"Toggle"}, {"type":"PushOn","id":"dev13","x":72,"y":112,"label":"PushOn"}, {"type":"Toggle","id":"dev14","x":72,"y":160,"label":"Toggle"}, {"type":"DC","id":"dev15","x":24,"y":112,"label":"DC"} ], "connectors":[ {"from":"dev0.in0","to":"dev2.out0"}, {"from":"dev0.in1","to":"dev3.out0"}, {"from":"dev1.in0","to":"dev4.out0"}, {"from":"dev1.in1","to":"dev5.out0"}, {"from":"dev2.in0","to":"dev1.out1"}, {"from":"dev2.in1","to":"dev7.out0"}, {"from":"dev2.in2","to":"dev8.out0"}, {"from":"dev3.in0","to":"dev8.out0"}, {"from":"dev3.in1","to":"dev9.out0"}, {"from":"dev3.in2","to":"dev1.out0"}, {"from":"dev4.in0","to":"dev6.out0"}, {"from":"dev4.in1","to":"dev0.out0"}, {"from":"dev5.in0","to":"dev0.out1"}, {"from":"dev5.in1","to":"dev6.out0"}, {"from":"dev6.in0","to":"dev8.out0"}, {"from":"dev7.in0","to":"dev12.out0"}, {"from":"dev8.in0","to":"dev13.out0"}, {"from":"dev9.in0","to":"dev14.out0"}, {"from":"dev10.in0","to":"dev1.out0"}, {"from":"dev11.in0","to":"dev1.out1"}, {"from":"dev12.in0","to":"dev15.out0"}, {"from":"dev13.in0","to":"dev15.out0"}, {"from":"dev14.in0","to":"dev15.out0"} ] } ); simcir.registerDevice('T-FF', { "width":320, "height":160, "showToolbox":false, "toolbox":[ ], "devices":[ {"type":"JK-FF","id":"dev0","x":168,"y":48,"label":"JK-FF"}, {"type":"In","id":"dev1","x":120,"y":32,"label":"T"}, {"type":"In","id":"dev2","x":120,"y":80,"label":"CLK"}, {"type":"Out","id":"dev3","x":248,"y":32,"label":"Q"}, {"type":"Out","id":"dev4","x":248,"y":80,"label":"~Q"}, {"type":"Toggle","id":"dev5","x":72,"y":32,"label":"Toggle"}, {"type":"PushOn","id":"dev6","x":72,"y":80,"label":"PushOn"}, {"type":"DC","id":"dev7","x":24,"y":56,"label":"DC"} ], "connectors":[ {"from":"dev0.in0","to":"dev1.out0"}, {"from":"dev0.in1","to":"dev2.out0"}, {"from":"dev0.in2","to":"dev1.out0"}, {"from":"dev1.in0","to":"dev5.out0"}, {"from":"dev2.in0","to":"dev6.out0"}, {"from":"dev3.in0","to":"dev0.out0"}, {"from":"dev4.in0","to":"dev0.out1"}, {"from":"dev5.in0","to":"dev7.out0"}, {"from":"dev6.in0","to":"dev7.out0"} ] } ); simcir.registerDevice('D-FF', { "width":540, "height":200, "showToolbox":false, "toolbox":[ ], "devices":[ {"type":"In","id":"dev0","x":128,"y":24,"label":"D"}, {"type":"In","id":"dev1","x":168,"y":128,"label":"CLK"}, {"type":"NOT","id":"dev2","x":176,"y":64,"label":"NOT"}, {"type":"NAND","id":"dev3","x":224,"y":32,"label":"NAND"}, {"type":"NAND","id":"dev4","x":224,"y":96,"label":"NAND"}, {"type":"RS-FF","id":"dev5","x":272,"y":64,"label":"RS-FF"}, {"type":"NOT","id":"dev6","x":296,"y":128,"label":"NOT"}, {"type":"NAND","id":"dev7","x":352,"y":32,"label":"NAND"}, {"type":"NAND","id":"dev8","x":352,"y":96,"label":"NAND"}, {"type":"RS-FF","id":"dev9","x":400,"y":64,"label":"RS-FF"}, {"type":"Out","id":"dev10","x":480,"y":32,"label":"Q"}, {"type":"Out","id":"dev11","x":480,"y":96,"label":"~Q"}, {"type":"Toggle","id":"dev12","x":80,"y":24,"label":"Toggle"}, {"type":"PushOn","id":"dev13","x":80,"y":128,"label":"PushOn"}, {"type":"DC","id":"dev14","x":32,"y":72,"label":"DC"} ], "connectors":[ {"from":"dev0.in0","to":"dev12.out0"}, {"from":"dev1.in0","to":"dev13.out0"}, {"from":"dev2.in0","to":"dev0.out0"}, {"from":"dev3.in0","to":"dev0.out0"}, {"from":"dev3.in1","to":"dev1.out0"}, {"from":"dev4.in0","to":"dev1.out0"}, {"from":"dev4.in1","to":"dev2.out0"}, {"from":"dev5.in0","to":"dev3.out0"}, {"from":"dev5.in1","to":"dev4.out0"}, {"from":"dev6.in0","to":"dev1.out0"}, {"from":"dev7.in0","to":"dev5.out0"}, {"from":"dev7.in1","to":"dev6.out0"}, {"from":"dev8.in0","to":"dev6.out0"}, {"from":"dev8.in1","to":"dev5.out1"}, {"from":"dev9.in0","to":"dev7.out0"}, {"from":"dev9.in1","to":"dev8.out0"}, {"from":"dev10.in0","to":"dev9.out0"}, {"from":"dev11.in0","to":"dev9.out1"}, {"from":"dev12.in0","to":"dev14.out0"}, {"from":"dev13.in0","to":"dev14.out0"} ] } ); simcir.registerDevice('8bitCounter', { "width":320, "height":420, "showToolbox":false, "toolbox":[ ], "devices":[ {"type":"T-FF","id":"dev0","x":184,"y":16,"label":"T-FF"}, {"type":"T-FF","id":"dev1","x":184,"y":64,"label":"T-FF"}, {"type":"T-FF","id":"dev2","x":184,"y":112,"label":"T-FF"}, {"type":"T-FF","id":"dev3","x":184,"y":160,"label":"T-FF"}, {"type":"T-FF","id":"dev4","x":184,"y":208,"label":"T-FF"}, {"type":"T-FF","id":"dev5","x":184,"y":256,"label":"T-FF"}, {"type":"T-FF","id":"dev6","x":184,"y":304,"label":"T-FF"}, {"type":"T-FF","id":"dev7","x":184,"y":352,"label":"T-FF"}, {"type":"Out","id":"dev8","x":264,"y":16,"label":"D0"}, {"type":"Out","id":"dev9","x":264,"y":64,"label":"D1"}, {"type":"Out","id":"dev10","x":264,"y":112,"label":"D2"}, {"type":"Out","id":"dev11","x":264,"y":160,"label":"D3"}, {"type":"Out","id":"dev12","x":264,"y":208,"label":"D4"}, {"type":"Out","id":"dev13","x":264,"y":256,"label":"D5"}, {"type":"Out","id":"dev14","x":264,"y":304,"label":"D6"}, {"type":"Out","id":"dev15","x":264,"y":352,"label":"D7"}, {"type":"In","id":"dev16","x":120,"y":16,"label":"T"}, {"type":"In","id":"dev17","x":120,"y":112,"label":"CLK"}, {"type":"PushOn","id":"dev18","x":72,"y":112,"label":"PushOn"}, {"type":"DC","id":"dev19","x":24,"y":16,"label":"DC"}, {"type":"Toggle","id":"dev20","x":72,"y":16,"label":"Toggle"} ], "connectors":[ {"from":"dev0.in0","to":"dev16.out0"}, {"from":"dev0.in1","to":"dev17.out0"}, {"from":"dev1.in0","to":"dev16.out0"}, {"from":"dev1.in1","to":"dev0.out0"}, {"from":"dev2.in0","to":"dev16.out0"}, {"from":"dev2.in1","to":"dev1.out0"}, {"from":"dev3.in0","to":"dev16.out0"}, {"from":"dev3.in1","to":"dev2.out0"}, {"from":"dev4.in0","to":"dev16.out0"}, {"from":"dev4.in1","to":"dev3.out0"}, {"from":"dev5.in0","to":"dev16.out0"}, {"from":"dev5.in1","to":"dev4.out0"}, {"from":"dev6.in0","to":"dev16.out0"}, {"from":"dev6.in1","to":"dev5.out0"}, {"from":"dev7.in0","to":"dev16.out0"}, {"from":"dev7.in1","to":"dev6.out0"}, {"from":"dev8.in0","to":"dev0.out0"}, {"from":"dev9.in0","to":"dev1.out0"}, {"from":"dev10.in0","to":"dev2.out0"}, {"from":"dev11.in0","to":"dev3.out0"}, {"from":"dev12.in0","to":"dev4.out0"}, {"from":"dev13.in0","to":"dev5.out0"}, {"from":"dev14.in0","to":"dev6.out0"}, {"from":"dev15.in0","to":"dev7.out0"}, {"from":"dev16.in0","to":"dev20.out0"}, {"from":"dev17.in0","to":"dev18.out0"}, {"from":"dev18.in0","to":"dev19.out0"}, {"from":"dev20.in0","to":"dev19.out0"} ] } ); simcir.registerDevice('HalfAdder', { "width":320, "height":160, "showToolbox":false, "toolbox":[ ], "devices":[ {"type":"Toggle","id":"dev0","x":96,"y":80,"label":"Toggle"}, {"type":"DC","id":"dev1","x":48,"y":56,"label":"DC"}, {"type":"AND","id":"dev2","x":192,"y":80,"label":"AND"}, {"type":"XOR","id":"dev3","x":192,"y":32,"label":"XOR"}, {"type":"In","id":"dev4","x":144,"y":32,"label":"A"}, {"type":"In","id":"dev5","x":144,"y":80,"label":"B"}, {"type":"Out","id":"dev6","x":240,"y":32,"label":"S"}, {"type":"Out","id":"dev7","x":240,"y":80,"label":"C"}, {"type":"Toggle","id":"dev8","x":96,"y":32,"label":"Toggle"} ], "connectors":[ {"from":"dev0.in0","to":"dev1.out0"}, {"from":"dev2.in0","to":"dev4.out0"}, {"from":"dev2.in1","to":"dev5.out0"}, {"from":"dev3.in0","to":"dev4.out0"}, {"from":"dev3.in1","to":"dev5.out0"}, {"from":"dev4.in0","to":"dev8.out0"}, {"from":"dev5.in0","to":"dev0.out0"}, {"from":"dev6.in0","to":"dev3.out0"}, {"from":"dev7.in0","to":"dev2.out0"}, {"from":"dev8.in0","to":"dev1.out0"} ] } ); simcir.registerDevice('FullAdder', { "width":440, "height":200, "showToolbox":false, "toolbox":[ ], "devices":[ {"type":"In","id":"dev0","x":120,"y":32,"label":"Cin"}, {"type":"In","id":"dev1","x":120,"y":80,"label":"A"}, {"type":"In","id":"dev2","x":120,"y":128,"label":"B"}, {"type":"Toggle","id":"dev3","x":72,"y":32,"label":"Toggle"}, {"type":"Toggle","id":"dev4","x":72,"y":80,"label":"Toggle"}, {"type":"Toggle","id":"dev5","x":72,"y":128,"label":"Toggle"}, {"type":"DC","id":"dev6","x":24,"y":80,"label":"DC"}, {"type":"HalfAdder","id":"dev7","x":168,"y":104,"label":"HalfAdder"}, {"type":"HalfAdder","id":"dev8","x":248,"y":56,"label":"HalfAdder"}, {"type":"OR","id":"dev9","x":328,"y":104,"label":"OR"}, {"type":"Out","id":"dev10","x":376,"y":104,"label":"Cout"}, {"type":"Out","id":"dev11","x":376,"y":48,"label":"S"} ], "connectors":[ {"from":"dev0.in0","to":"dev3.out0"}, {"from":"dev1.in0","to":"dev4.out0"}, {"from":"dev2.in0","to":"dev5.out0"}, {"from":"dev3.in0","to":"dev6.out0"}, {"from":"dev4.in0","to":"dev6.out0"}, {"from":"dev5.in0","to":"dev6.out0"}, {"from":"dev7.in0","to":"dev1.out0"}, {"from":"dev7.in1","to":"dev2.out0"}, {"from":"dev8.in0","to":"dev0.out0"}, {"from":"dev8.in1","to":"dev7.out0"}, {"from":"dev9.in0","to":"dev8.out1"}, {"from":"dev9.in1","to":"dev7.out1"}, {"from":"dev10.in0","to":"dev9.out0"}, {"from":"dev11.in0","to":"dev8.out0"} ] } ); simcir.registerDevice('4bitAdder', { "width":280, "height":480, "showToolbox":false, "toolbox":[ ], "devices":[ {"type":"FullAdder","id":"dev0","x":120,"y":72,"label":"FullAdder"}, {"type":"FullAdder","id":"dev1","x":120,"y":136,"label":"FullAdder"}, {"type":"FullAdder","id":"dev2","x":120,"y":200,"label":"FullAdder"}, {"type":"FullAdder","id":"dev3","x":120,"y":264,"label":"FullAdder"}, {"type":"In","id":"dev4","x":40,"y":80,"label":"A0"}, {"type":"In","id":"dev5","x":40,"y":128,"label":"A1"}, {"type":"In","id":"dev6","x":40,"y":176,"label":"A2"}, {"type":"In","id":"dev7","x":40,"y":224,"label":"A3"}, {"type":"In","id":"dev8","x":40,"y":272,"label":"B0"}, {"type":"In","id":"dev9","x":40,"y":320,"label":"B1"}, {"type":"In","id":"dev10","x":40,"y":368,"label":"B2"}, {"type":"In","id":"dev11","x":40,"y":416,"label":"B3"}, {"type":"Out","id":"dev12","x":200,"y":72,"label":"S0"}, {"type":"Out","id":"dev13","x":200,"y":120,"label":"S1"}, {"type":"Out","id":"dev14","x":200,"y":168,"label":"S2"}, {"type":"Out","id":"dev15","x":200,"y":216,"label":"S3"}, {"type":"Out","id":"dev16","x":200,"y":280,"label":"Cout"}, {"type":"In","id":"dev17","x":40,"y":24,"label":"Cin"} ], "connectors":[ {"from":"dev0.in0","to":"dev17.out0"}, {"from":"dev0.in1","to":"dev4.out0"}, {"from":"dev0.in2","to":"dev8.out0"}, {"from":"dev1.in0","to":"dev0.out1"}, {"from":"dev1.in1","to":"dev5.out0"}, {"from":"dev1.in2","to":"dev9.out0"}, {"from":"dev2.in0","to":"dev1.out1"}, {"from":"dev2.in1","to":"dev6.out0"}, {"from":"dev2.in2","to":"dev10.out0"}, {"from":"dev3.in0","to":"dev2.out1"}, {"from":"dev3.in1","to":"dev7.out0"}, {"from":"dev3.in2","to":"dev11.out0"}, {"from":"dev12.in0","to":"dev0.out0"}, {"from":"dev13.in0","to":"dev1.out0"}, {"from":"dev14.in0","to":"dev2.out0"}, {"from":"dev15.in0","to":"dev3.out0"}, {"from":"dev16.in0","to":"dev3.out1"} ] } ); simcir.registerDevice('2to4BinaryDecoder', { "width":400, "height":240, "showToolbox":false, "toolbox":[ ], "devices":[ {"type":"AND","numInputs":3,"id":"dev0","x":280,"y":24,"label":"AND"}, {"type":"AND","numInputs":3,"id":"dev1","x":280,"y":72,"label":"AND"}, {"type":"AND","numInputs":3,"id":"dev2","x":280,"y":120,"label":"AND"}, {"type":"NOT","id":"dev3","x":192,"y":48,"label":"NOT"}, {"type":"AND","numInputs":3,"id":"dev4","x":280,"y":168,"label":"AND"}, {"type":"NOT","id":"dev5","x":192,"y":96,"label":"NOT"}, {"type":"In","id":"dev6","x":192,"y":176,"label":"OE"}, {"type":"In","id":"dev7","x":128,"y":48,"label":"D0"}, {"type":"In","id":"dev8","x":128,"y":96,"label":"D1"}, {"type":"Toggle","id":"dev9","x":80,"y":48,"label":"Toggle"}, {"type":"Toggle","id":"dev10","x":80,"y":96,"label":"Toggle"}, {"type":"DC","id":"dev11","x":32,"y":96,"label":"DC"}, {"type":"Out","id":"dev12","x":328,"y":24,"label":"A0"}, {"type":"Out","id":"dev13","x":328,"y":72,"label":"A1"}, {"type":"Out","id":"dev14","x":328,"y":120,"label":"A2"}, {"type":"Out","id":"dev15","x":328,"y":168,"label":"A3"}, {"type":"Toggle","id":"dev16","x":80,"y":144,"label":"Toggle"} ], "connectors":[ {"from":"dev0.in0","to":"dev3.out0"}, {"from":"dev0.in1","to":"dev5.out0"}, {"from":"dev0.in2","to":"dev6.out0"}, {"from":"dev1.in0","to":"dev7.out0"}, {"from":"dev1.in1","to":"dev5.out0"}, {"from":"dev1.in2","to":"dev6.out0"}, {"from":"dev2.in0","to":"dev3.out0"}, {"from":"dev2.in1","to":"dev8.out0"}, {"from":"dev2.in2","to":"dev6.out0"}, {"from":"dev3.in0","to":"dev7.out0"}, {"from":"dev4.in0","to":"dev7.out0"}, {"from":"dev4.in1","to":"dev8.out0"}, {"from":"dev4.in2","to":"dev6.out0"}, {"from":"dev5.in0","to":"dev8.out0"}, {"from":"dev6.in0","to":"dev16.out0"}, {"from":"dev7.in0","to":"dev9.out0"}, {"from":"dev8.in0","to":"dev10.out0"}, {"from":"dev9.in0","to":"dev11.out0"}, {"from":"dev10.in0","to":"dev11.out0"}, {"from":"dev12.in0","to":"dev0.out0"}, {"from":"dev13.in0","to":"dev1.out0"}, {"from":"dev14.in0","to":"dev2.out0"}, {"from":"dev15.in0","to":"dev4.out0"}, {"from":"dev16.in0","to":"dev11.out0"} ] } ); simcir.registerDevice('3to8BinaryDecoder', { "width":360, "height":440, "showToolbox":false, "toolbox":[ ], "devices":[ {"type":"In","id":"dev0","x":24,"y":144,"label":"D0"}, {"type":"In","id":"dev1","x":24,"y":192,"label":"D1"}, {"type":"In","id":"dev2","x":24,"y":240,"label":"D2"}, {"type":"In","id":"dev3","x":24,"y":304,"label":"OE"}, {"type":"NOT","id":"dev4","x":72,"y":240,"label":"NOT"}, {"type":"AND","id":"dev5","x":120,"y":248,"label":"AND"}, {"type":"AND","id":"dev6","x":120,"y":296,"label":"AND"}, {"type":"2to4BinaryDecoder","id":"dev7","x":184,"y":144,"label":"2to4BinaryDecoder"}, {"type":"2to4BinaryDecoder","id":"dev8","x":184,"y":224,"label":"2to4BinaryDecoder"}, {"type":"Out","id":"dev9","x":296,"y":32,"label":"A0"}, {"type":"Out","id":"dev10","x":296,"y":80,"label":"A1"}, {"type":"Out","id":"dev11","x":296,"y":128,"label":"A2"}, {"type":"Out","id":"dev12","x":296,"y":176,"label":"A3"}, {"type":"Out","id":"dev13","x":296,"y":224,"label":"A4"}, {"type":"Out","id":"dev14","x":296,"y":272,"label":"A5"}, {"type":"Out","id":"dev15","x":296,"y":320,"label":"A6"}, {"type":"Out","id":"dev16","x":296,"y":368,"label":"A7"} ], "connectors":[ {"from":"dev4.in0","to":"dev2.out0"}, {"from":"dev5.in0","to":"dev4.out0"}, {"from":"dev5.in1","to":"dev3.out0"}, {"from":"dev6.in0","to":"dev2.out0"}, {"from":"dev6.in1","to":"dev3.out0"}, {"from":"dev7.in0","to":"dev0.out0"}, {"from":"dev7.in1","to":"dev1.out0"}, {"from":"dev7.in2","to":"dev5.out0"}, {"from":"dev8.in0","to":"dev0.out0"}, {"from":"dev8.in1","to":"dev1.out0"}, {"from":"dev8.in2","to":"dev6.out0"}, {"from":"dev9.in0","to":"dev7.out0"}, {"from":"dev10.in0","to":"dev7.out1"}, {"from":"dev11.in0","to":"dev7.out2"}, {"from":"dev12.in0","to":"dev7.out3"}, {"from":"dev13.in0","to":"dev8.out0"}, {"from":"dev14.in0","to":"dev8.out1"}, {"from":"dev15.in0","to":"dev8.out2"}, {"from":"dev16.in0","to":"dev8.out3"} ] } ); simcir.registerDevice('4to16BinaryDecoder', { "width":440, "height":360, "showToolbox":false, "toolbox":[ ], "devices":[ {"type":"In","id":"dev0","x":32,"y":56,"label":"D0"}, {"type":"In","id":"dev1","x":32,"y":104,"label":"D1"}, {"type":"In","id":"dev2","x":32,"y":152,"label":"D2"}, {"type":"In","id":"dev3","x":32,"y":200,"label":"D3"}, {"type":"In","id":"dev4","x":32,"y":264,"label":"OE"}, {"type":"NOT","id":"dev5","x":80,"y":200,"label":"NOT"}, {"type":"AND","id":"dev6","x":136,"y":208,"label":"AND"}, {"type":"AND","id":"dev7","x":136,"y":256,"label":"AND"}, {"type":"3to8BinaryDecoder","id":"dev8","x":208,"y":32,"label":"3to8BinaryDecoder"}, {"type":"3to8BinaryDecoder","id":"dev9","x":208,"y":184,"label":"3to8BinaryDecoder"}, {"type":"BusOut","id":"dev10","x":320,"y":88,"label":"BusOut"}, {"type":"BusOut","id":"dev11","x":320,"y":184,"label":"BusOut"}, {"type":"Out","id":"dev12","x":376,"y":128,"label":"A0"}, {"type":"Out","id":"dev13","x":376,"y":184,"label":"A1"} ], "connectors":[ {"from":"dev5.in0","to":"dev3.out0"}, {"from":"dev6.in0","to":"dev5.out0"}, {"from":"dev6.in1","to":"dev4.out0"}, {"from":"dev7.in0","to":"dev3.out0"}, {"from":"dev7.in1","to":"dev4.out0"}, {"from":"dev8.in0","to":"dev0.out0"}, {"from":"dev8.in1","to":"dev1.out0"}, {"from":"dev8.in2","to":"dev2.out0"}, {"from":"dev8.in3","to":"dev6.out0"}, {"from":"dev9.in0","to":"dev0.out0"}, {"from":"dev9.in1","to":"dev1.out0"}, {"from":"dev9.in2","to":"dev2.out0"}, {"from":"dev9.in3","to":"dev7.out0"}, {"from":"dev10.in0","to":"dev8.out0"}, {"from":"dev10.in1","to":"dev8.out1"}, {"from":"dev10.in2","to":"dev8.out2"}, {"from":"dev10.in3","to":"dev8.out3"}, {"from":"dev10.in4","to":"dev8.out4"}, {"from":"dev10.in5","to":"dev8.out5"}, {"from":"dev10.in6","to":"dev8.out6"}, {"from":"dev10.in7","to":"dev8.out7"}, {"from":"dev11.in0","to":"dev9.out0"}, {"from":"dev11.in1","to":"dev9.out1"}, {"from":"dev11.in2","to":"dev9.out2"}, {"from":"dev11.in3","to":"dev9.out3"}, {"from":"dev11.in4","to":"dev9.out4"}, {"from":"dev11.in5","to":"dev9.out5"}, {"from":"dev11.in6","to":"dev9.out6"}, {"from":"dev11.in7","to":"dev9.out7"}, {"from":"dev12.in0","to":"dev10.out0"}, {"from":"dev13.in0","to":"dev11.out0"} ] } ); // // この下を追記 // simcir.registerDevice('JK-FF-RST', { "width":800, "height":400, "showToolbox":false, "toolbox":[ ], "devices":[ {"type":"DC","id":"dev0","x":16,"y":144,"label":"DC"}, {"type":"Toggle","id":"dev1","x":80,"y":88,"label":"Toggle","state":{"on":false}}, {"type":"PushOn","id":"dev2","x":80,"y":144,"label":"PushOn"}, {"type":"PushOn","id":"dev3","x":80,"y":304,"label":"PushOn"}, {"type":"Toggle","id":"dev4","x":80,"y":208,"label":"Toggle","state":{"on":false}}, {"type":"AND","id":"dev5","x":208,"y":112,"label":"AND"}, {"type":"AND","id":"dev6","x":208,"y":184,"label":"AND"}, {"type":"AND","id":"dev7","x":264,"y":112,"label":"AND"}, {"type":"NOT","id":"dev8","x":328,"y":112,"label":"NOT"}, {"type":"NOT","id":"dev9","x":328,"y":184,"label":"NOT"}, {"type":"RS-FF","id":"dev10","x":384,"y":144,"label":"RS-FF"}, {"type":"NAND","id":"dev11","x":472,"y":112,"label":"NAND"}, {"type":"NAND","id":"dev12","x":472,"y":184,"label":"NAND"}, {"type":"NOT","id":"dev13","x":288,"y":320,"label":"NOT"}, {"type":"AND","id":"dev14","x":344,"y":320,"label":"AND"}, {"type":"OR","id":"dev15","x":312,"y":272,"label":"OR"}, {"type":"NOT","id":"dev16","x":472,"y":320,"label":"NOT"}, {"type":"AND","id":"dev17","x":536,"y":320,"label":"AND"}, {"type":"LED","id":"dev18","x":424,"y":32,"label":"LED"}, {"type":"LED","id":"dev19","x":576,"y":32,"label":"LED"}, {"type":"NOT","id":"dev20","x":208,"y":32,"label":"NOT"}, {"type":"OR","id":"dev21","x":512,"y":272,"label":"OR"}, {"type":"RS-FF","id":"dev22","x":552,"y":144,"label":"RS-FF"}, {"type":"AND","id":"dev23","x":264,"y":184,"label":"AND"}, {"type":"In","id":"dev24","x":144,"y":88,"label":"J"}, {"type":"In","id":"dev25","x":144,"y":144,"label":"CLK"}, {"type":"In","id":"dev26","x":144,"y":208,"label":"K"}, {"type":"In","id":"dev27","x":144,"y":304,"label":"RST"}, {"type":"Out","id":"dev28","x":632,"y":96,"label":"Q"}, {"type":"Out","id":"dev29","x":632,"y":192,"label":"~Q"} ], "connectors":[ {"from":"dev1.in0","to":"dev0.out0"}, {"from":"dev2.in0","to":"dev0.out0"}, {"from":"dev3.in0","to":"dev0.out0"}, {"from":"dev4.in0","to":"dev0.out0"}, {"from":"dev5.in0","to":"dev24.out0"}, {"from":"dev5.in1","to":"dev25.out0"}, {"from":"dev6.in0","to":"dev25.out0"}, {"from":"dev6.in1","to":"dev26.out0"}, {"from":"dev7.in0","to":"dev5.out0"}, {"from":"dev7.in1","to":"dev22.out1"}, {"from":"dev8.in0","to":"dev7.out0"}, {"from":"dev9.in0","to":"dev23.out0"}, {"from":"dev10.in0","to":"dev15.out0"}, {"from":"dev10.in1","to":"dev14.out0"}, {"from":"dev11.in0","to":"dev20.out0"}, {"from":"dev11.in1","to":"dev10.out0"}, {"from":"dev12.in0","to":"dev10.out1"}, {"from":"dev12.in1","to":"dev20.out0"}, {"from":"dev13.in0","to":"dev27.out0"}, {"from":"dev14.in0","to":"dev9.out0"}, {"from":"dev14.in1","to":"dev13.out0"}, {"from":"dev15.in0","to":"dev8.out0"}, {"from":"dev15.in1","to":"dev27.out0"}, {"from":"dev16.in0","to":"dev27.out0"}, {"from":"dev17.in0","to":"dev12.out0"}, {"from":"dev17.in1","to":"dev16.out0"}, {"from":"dev18.in0","to":"dev10.out0"}, {"from":"dev19.in0","to":"dev22.out0"}, {"from":"dev20.in0","to":"dev25.out0"}, {"from":"dev21.in0","to":"dev11.out0"}, {"from":"dev21.in1","to":"dev27.out0"}, {"from":"dev22.in0","to":"dev21.out0"}, {"from":"dev22.in1","to":"dev17.out0"}, {"from":"dev23.in0","to":"dev22.out0"}, {"from":"dev23.in1","to":"dev6.out0"}, {"from":"dev24.in0","to":"dev1.out0"}, {"from":"dev25.in0","to":"dev2.out0"}, {"from":"dev26.in0","to":"dev4.out0"}, {"from":"dev27.in0","to":"dev3.out0"}, {"from":"dev28.in0","to":"dev22.out0"}, {"from":"dev29.in0","to":"dev22.out1"} ] } ); すると、ツールエリアのいちばん下に、「JK-FF-RST」が追加されています。 SimcirJSの画面例 ツールエリアに自作部品 JK-FF-RST が追加されている これで、リセット付きJKフリップフロップが使えるようになりました。 ちなみに、このJK-FF-RSTをダブルクリックすると、ちゃんと中身が確認できます。 自分で追加した回路を使って組み上げる 自分で追加した回路を使って、目的の「3進カウンタ」を組み上げていきましょう。 といっても、使い方はこれまでの操作と変わりません。他の回路と同じようにワークエリアにドラッグアンドドロップし、結線するだけです。 3進カウンタ 0→1→2→3→0→1→2→3→…となるところの「→3」の瞬間でリセットしたいので、 「3」の状態、すなわち両方のJK-FFが「1」(ON)のときにリセットを入れればよさそうです。 両方が1のときだけ1になればいいので、AND回路が使えそうです。両方のJK-FFの出力QをAND回路に入力し、そのAND回路出力をRST端子につなぎこめば よさそうです。 なのですが、実は、両方のJK-FFのRST端子にそのまま入れてしまうと、うまく動きません。 3進カウンタの回路例と動作例 うまく動かないケース 両方同じタイミングで入れてしまうと、両方のJK-FFが同時に 0 になった瞬間に、下位側のJK-FFの1→0の 立ち下がり信号で上位側JK-FFが再度 1 に遷移してしまうためです。 対策として、上位側にリセットを入れるタイミングを少し遅らせます。バッファ(BUF)を入れるか、 ロジック上は意味のない「NOT-NOT」を通して上位側のリセットに入れます。 3進カウンタの回路例と動作例 うまく動くケース これで、思っていた通り動くようになりました。 動作例 ということで3進カウンタができたので、4進カウンタと合わせて、野球のカウンタ(BSO)のようにしてみました。 ついでに「4bit7seg」という便利な回路もあるので、あわせて組み込んでみました。LEDの点灯数と数字で ボールカウント・アウトカウントを表示してくれます。B/S/Oのそれぞれのボタンを押すごとに、B/S/Oが ひとつずつカウントされていきます。 SimcirJSで作成した野球カウンタ(BSO)の例 この回路も示しておきます。 野球のBSOカウンタの回路図 さいごに 本物の野球のカウンタのように利用するのであれば、次のような機能もあるとよいのか、と思います。 Bが3→0に戻るとき(フォアボール)、Sも0に戻す、Oはそのまま Sが2→0に戻るとき(三振)、Bも0に戻す。Oを増やしたい気がするが、「振り逃げ」のケースがあり得るので、Oはそのまま Oが2→0に戻るとき(チェンジ)、BとSも0に戻す どれも、リセット入力を利用することで実現可能です。その意味では、B用の4進カウンタも、「JK-FF」ではなく「JK-FF-RST」で 組んでおくべきでした。上記を満たすためには、どんな条件のときに、どのJK-FF-RSTにリセット信号を入れればよいか、 またそのときも、今回と同じようなタイミング調整(NOT-NOT回路)の必要があるか、興味のある方は、考えてみて、 SimcirJSで試してみてください。 まとめ SimcirJSを使うと、ディジタル回路のシミュレーションが簡単にできます すでにあるものを利用することもできますが、自分で立てたhttpd上へのインストールも、とても簡単にできます 自作の回路を登録するには、すこし手間はかかりますが、決して難しくはありません このよう簡単に試すことができるシミュレータで、ディジタル回路に興味を持っていただけるとありがたいです。 筆者自身はディジタル回路をさわるのはひさびさで、かなり勘が鈍ってしまっていました。たまにはさわっておかないとダメですね。 執筆者 ふるかわ やすゆき (古川 靖之) NTT西日本 バリューデザイン部 所属 ふだんは、情報機器開発に携わっています。以前はビジネスフォンの開発も行っていました。 前職では法人営業SEで、自治体様を担当していました。その前は安全帽装備で建設現場に入っていたこともあります。もっと前はアプリ開発をしていたこともあります。ハード(電気電子)・ソフト(情報)・筐体(機械)をひととおり経験している、弊社では少し珍しいタイプの人間です。 技術士(電気電子部門、情報工学部門、機械部門、経営工学部門、総合技術監理部門) 参考資料・出典 本記事の作成にあたり参考にしたもの、そもそも自身でSimcirJSを使うために参照したものを紹介します。 SimcirJSを利用できるサイト 作者さんのサイト : https://kazuhikoarase.github.io/simcirjs/ 作者さんのサイトです。ダウンロードもここからできますし、このサイト上でSimcirJSを利用することもできます。 論理回路シミュレータ SimcirJS の使い方 : https://lecture.ecc.u-tokyo.ac.jp/JOHZU/joho/Y2016/LogicSimulator/LogicSimulator/01.html SimcirJSの使い方の説明とともに、実際に利用できるページも用意されています。 ワークエリアが広くとってあります。 スク解ホーム : https://kaisaba.f5.si/html/simcirjs-master/index.html 赤色以外のLED(緑色・青色)や、3入力以上の論理ゲート回路が準備されています。 また、作成した回路のPCへの保存や、PCに保存したファイルからの読み出しができるようにされています。 ライセンス SimcirJSはMITライセンスで公開されています。本記事に、配布コードの一部を引用した部分があることから、 SimcirJSのライセンス全文を掲載します。 MIT License Copyright (c) 2014 Kazuhiko Arase Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
はじめに 株式会社ジャパン・インフラ・ウェイマーク(以下、JIW)の森田です。 JIWでは、ドライブレコーダーやドローンで撮影した動画・画像に対してAIを活用し、 道路のひび割れ・道路構造物・サビなど、インフラ点検の支援を行っています。 あるプロジェクトでは、約300TBのデータをAmazon S3に長期保管していました。 最大の論点は「 月額コストをどう圧縮するか 」です。 この課題に向き合う中で、複数のストレージサービスやクラウド事業者のプログラムを調査しました。 本記事では、その過程で見えてきた 状況別の現実的な対応案 各サービスの特性を理解するうえで押さえておきたいポイント を共有します。 対象読者 本記事は、主に次のような方を想定しています。 Boxへのデータ移行を検討している方 数十〜数百TBクラスの長期保管データのコスト最適化を検討している方 DTO(Data Transfer Out)無料化の流れやEU Data Actの影響が気になっている方 背景・目的 データの特性 インフラ点検業務では、次のような特性を持つデータを大量に抱えることになります。 すぐには消せない(いつか使う可能性がある) 平常時のアクセス頻度は低い いざ使うとなったら、即時〜数分以内にはアクセスしたい 性質としては、 いわゆる「コールドストレージ」 に分類されるストレージ要件です。 調査した選択肢 この課題に取り組む中で、以下の選択肢を検討・調査しました。 Boxの「無制限ストレージ」への移行検討 欧州データ法(EU Data Act)を契機とした DTO(Data Transfer Out)無料化のトレンド [1] [2] [3] [4] AWSの中だけで S3ストレージコストを削減する方法 [8] AWS以外のストレージサービス を選択肢に含める方法 [10] [11] [12] 前提と用語整理 想定シナリオ 今回の検討対象となったデータの前提は以下です。 項目 内容 データ総量 約300TB 特性 削除できない/アクセス頻度は低い/アクセス時は即時性が必要 保存先 Amazon S3(複数バケット) 主な課題 月額ストレージコストの圧縮 制約 将来の参照可能性を維持すること この前提から、候補となるのは大きく次の3つです。 S3ストレージクラスの見直し(Glacier系など) [8] 他社クラウド/専用オブジェクトストレージへの退避 [10] [11] DTO無料/減額プログラムの活用 [1] [4] [5] [12] DTO(Data Transfer Out)とは DTOは、 クラウドからインターネットや他クラウド、オンプレ環境へデータを出すときに発生する転送料金 を指します。 AWSでは「リージョンからインターネットへの送信」に対してGBあたりの料金が設定されており、 これがいわゆる 「出口コスト」 としてスイッチングの障壁になりがちです。 [6] Box移行検討でわかった「帯域制限」の重要性 Boxの「Unlimited storage」を調査してわかったこと Boxのエンタープライズ系プランでは、「 Unlimited storage(ストレージ無制限) 」が提供されています。 300TBクラスのデータを抱える立場から見ると、非常に魅力的に見えます。 しかし、詳細を調べていく中で、 帯域(アップロード+ダウンロード)のFair Use制限 の存在が見えてきました。 [9] BoxのFair Use Policyでは、次のように定義されています。 [9] Each individual or User is limited to a total usage of 1 TB of Bandwidth per month . [9] つまり、 1ユーザーあたり月間1TBまで がFair Useの目安です。 単一アカウント(=1ユーザー)で300TBを移行しようとすると、 理論上300ヶ月(25年) かかる計算になります。 実際には、 複数ユーザーで並列にアップロードする Box側と個別に相談し、一時的な帯域増強や例外対応を打診する といった現実的な選択肢がありますが、今回のように 「短期間で300TB規模を一気に移行したい」 ケースでは、 ストレージ容量だけでなく帯域制限も設計上の制約になる 事前に移行計画をきちんと相談しておかないと、「終わらない移行」になり得る ということが分かりました。 大容量データ移行時の事前確認ポイント 今回の調査を通じて、大容量データの移行検討時には、少なくとも以下の観点を事前確認する必要があると感じました。 チェック項目 見るべきポイント ストレージ容量 「無制限」と書いてあっても、その単位(ユーザー単位/テナント単位など)を確認 帯域(Bandwidth) 月間アップロード+ダウンロードの上限。ユーザー単位/組織単位のFair Useの有無 ドキュメントの場所 日本語ページだけでなく、 英語の規約・Fair Use Policy本文 を確認する [9] 回避余地 契約オプションやサポート経由で帯域を増やせるか/一時的な緩和が可能か EU Data ActとDTO無料化の動き EU Data Actのクラウドスイッチング規定 欧州データ法(EU Data Act、Regulation (EU) 2023/2854)は、データ利活用の促進とともに、 クラウドロックインの緩和 を重要な目的の1つとして掲げています。 [1] [2] 特に「クラウドスイッチング」に関する条文(Chapter VI)では、 スイッチング手数料(Switching charges)やDTOを含むエグレス課金の扱い が段階的に規定されています。 [1] [3] [4] タイムラインをざっくり整理すると、以下のイメージです。 [1] [4] 日付 内容 2025年9月12日 Data Actの多くの規定が適用開始(クラウドスイッチング関連義務もここから適用) 〜2027年1月11日 スイッチング手数料は「コストベース」のみ許容(原価回収レベルまで) 2027年1月12日以降 スイッチング手数料の禁止(DTOを含むエグレス課金による 追加利益 は認められない方向性) この流れを受けて、主要クラウドベンダーは DTO無料化プログラム マルチクラウド間転送の無償化(例:Google CloudのData Transfer Essentials) [12] など、 「スイッチングしやすい」料金体系 を相次いで打ち出しています。 [5] [12] AWSのDTO無料プログラム(公式情報ベース) AWSは2024年3月5日の公式ブログで、 他クラウドやオンプレ環境へ移行する場合にDTOを無料とするプログラム を発表しています。 [5] 主なポイントを整理すると、以下の通りです。 対象 AWSリージョンからインターネットへのDTO(他クラウド/オンプレへの移行目的) [5] 基本ルール すべての顧客に対して、 月間100GBまでのDTO無料枠 が恒久的に提供されている(AWS Free Tierの一部) [6] [7] CloudFrontからのDTOも、 月間1TBまで無料 の枠がある(こちらも恒久) [6] [7] 追加で無料枠を拡大したい場合 「移行のための一時的なトラフィック」であること AWSサポートに連絡し、 移行計画(対象サービス・データ量・期間など)を共有したうえで申請 する [5] 承認された場合、 対象DTO分の料金がクレジットで相殺される [5] 2025年9月30日のアップデート時点の情報では: 移行に伴うDTO無料プログラムの利用は、 原則90日以内に移行を完了 させることが前提 [5] 90日を超える場合は、 AWSサポートへの事前連絡が必須 「月間100GBを超えるDTOでなければサポート申請できない」という条件は撤廃済み このプログラムは、 すべてのリージョンのAWS顧客を対象 としており、EU Data Actの方向性に沿った施策と説明されています。 [1] [5] まとめると、DTO無料プログラムを活用する際には、以下の点を意識する必要があります。 公式ブログやFAQに記載された共通条件を確認し、最新の情報を把握すること [5] [6] [7] 自社の移行計画(対象データ量・期間・移行先など)を明文化し、その前提で無理のないスケジュールを組むこと 疑問点があれば早めにAWSサポートや営業担当に相談し、適用可否や運用条件を確認すること また、これらを踏まえたうえで、 少し余裕のあるスケジュール で移行計画を立てておくことが重要です。 AWSの中でS3コストを減らす選択肢 DTO無料で「外に出る」前に、 「まずAWS内でどこまで最適化できるか」 を検討する価値は高いです。 300TBクラスでも効いてきそうな代表的な施策をピックアップします。 [8] ストレージクラスの見直し 代表的なS3ストレージクラスをざっくり整理すると、次のようなイメージです。 [8] クラス名 用途イメージ 特徴(ざっくり) S3 Standard 頻繁アクセス 高性能だが単価は最も高いクラス S3 Intelligent-Tiering アクセスパターンが読めない アクセス頻度に応じて自動で階層を切替、取り出し料金なし S3 Standard-IA / One Zone-IA たまにしか読まない 保存単価は安いが、取り出し料金あり S3 Glacier Instant / Flexible Retrieval 年に数回程度のアクセス 取り出しレイテンシあり。保存単価はさらに安価 S3 Glacier Deep Archive ほとんど読まない長期アーカイブ TB単価が最安クラス。取り出しに数時間+取り出し料金あり 特にS3 Glacier Deep Archiveは、S3 Standardと比べて GB単価が1/20程度 と、 オーダーが一つ以上違うレベル で安価です。 [8] そのため、 「消せないがほぼ読まない」データ については、 アクセス要件を満たす範囲でDeep Archiveに寄せるだけで、月額コストを大きく削減できるケースがあります。 [8] S3 Intelligent-Tieringの検討ポイント S3 Intelligent-Tieringは、アクセスパターンが読めないデータに対して便利な選択肢です。 S3が自動でアクセス頻度を監視し、適切なストレージ層に移動してくれるため、運用負荷を抑えつつコスト最適化ができます。 [8] 一方で、 大量の画像ファイルなど、オブジェクト数が非常に多い場合 は、次の点に注意が必要です。 Intelligent-Tieringでは、 128KB以上のオブジェクトに対して オブジェクト監視・自動階層化の料金が発生する オブジェクト数が極端に多い場合、この 監視・自動化料金 が無視できない金額になることがある 128KB未満のオブジェクトは自動階層化の対象外 で、常にFrequent Access相当の料金で課金される(監視料金はかからない) 今回のような「動画・画像データが大量にある」ケースでは、次のような判断基準を設けました。 アクセスパターンが明確なデータ ライフサイクルルールで明示的にGlacier系へ移行 アクセスパターンが不明確で、かつファイルサイズが大きめ(数MB以上) Intelligent-Tieringの利用を検討 小さなファイルが大量にあるデータ 後述の オブジェクト集約(s3tarなど) でまとめてからアーカイブする案を検討 Storage Lensとライフサイクルルール S3 Storage Lensを有効化すると、アカウント全体のストレージ利用状況を俯瞰できます。 [8] 代表的な使い方は次のフローです。 Storage Lensで「コストインパクトが大きいバケット」を特定 対象バケットに対して、ライフサイクルルールを設計・適用 例: 最終アクセスから90日経過 → Glacier 365日以上アクセスなし → Deep Archive 古いオブジェクトバージョンを一定期間で削除 未完了マルチパートアップロードを一定日数で破棄 「古いデータから順に安い階層へ落としていく仕組み」 を組み込んでおくことで、 将来のS3コストの暴騰を抑えやすくなります。 [8] オブジェクト集約(s3tarなど) 大量の小さなファイルをそのままS3に置いている場合、 PUT/LISTリクエスト回数 オブジェクトメタデータの管理コスト も無視できなくなってきます。 例えば、 s3tar でファイルをまとめて1オブジェクトにし、Glacierに移行するアーキテクチャ を採用する方法があります。 「ファイル単位でピンポイントに復旧したい」という要件が薄いアーカイブ用途であれば、 一定期間ごとにまとめてTAR化 → Glacier系へ退避 といったパターンも有力な選択肢になります。 AWSを使わない場合のストレージ選択肢 DTO無料プログラムやEU Data Actの影響により、 他社クラウド/専用オブジェクトストレージを候補に含める現実味 も増しています。 [1] [4] [5] [12] ここでは、「どのベンダーが良いか」ではなく、 カテゴリごとの選択肢の整理 にフォーカスします。 他メガクラウドのアーカイブ層 Microsoft AzureやGoogle Cloudなど、他のメガクラウドもS3 Glacierに相当するアーカイブ向けストレージを提供しています。 Azure Blob Storage : Hot / Cool / Cold / Archive など Google Cloud Storage : Standard / Nearline / Coldline / Archive など さらにGoogle Cloudは、 EU/UK向けに「Data Transfer Essentials」という無償のマルチクラウド転送サービス を提供開始しています。 [12] EU Data Actの原則(マルチクラウド/スイッチング容易性)に応える位置づけ EU/UKの顧客向けに、特定条件を満たすマルチクラウド間転送の エグレス料金を0円 にする [12] メリット 大手クラウドのコンプライアンス・認証を活用しやすい 既存システムとの連携資料・SDKが豊富 注意点 AWSからDTOを出す際は、 AWS側DTO無料プログラムとの組み合わせ を検討 [5] クラウドごとに料金・取り出し制約・リージョン制限が異なる [8] [12] 専用オブジェクトストレージ(Backblaze B2 / Wasabiなど) S3互換API+シンプルな料金体系 を特徴とする専用オブジェクトストレージも、有力な選択肢です。 Backblaze B2の例 Backblaze B2 Cloud Storageの価格表では、おおよそ以下の条件が提示されています。 [10] ストレージ: 約$6 / TB / 月 「Free egress up to 3x storage」 ルール 「平均月間ストレージ量の3倍までのダウンロードは無料」 それを超えた分は$0.01/GB Wasabiの例 Wasabi Hot Cloud Storageは、「 No fees for egress or API requests 」を打ち出しています。 [11] ストレージ料金はTBあたりの固定単価(例:$6.99/TB/月) egress・APIリクエストは無料 代わりに、最低保持期間(90日)や最低利用容量などの条件がある [11] ざっくり比較イメージ サービス egressポリシーの特徴 備考 AWS S3(通常利用) DTO課金あり(100GB/月の無料枠+DTO無料プログラムあり) DTO無料プログラムは「移行時向け」 [5] [6] [7] Backblaze B2 月間平均ストレージ量の3倍までegress無料 S3互換API・シンプルな従量課金 [10] Wasabi egress / APIリクエストともに無料 最低保持期間や最低容量などに注意 [11] メリット 料金モデルがシンプルで予測しやすい S3互換APIのため、既存ツール/SDKをそのまま流用しやすい 注意点 データレジデンシ(どの国・地域にデータが置かれるか) 自社のコンプライアンス・セキュリティ要件との整合 サービスの継続性、サポート体制、ベンダーの事業規模 [10] [11] まとめ:状況別の選択肢 ここまでの内容を踏まえ、データ容量とアクセスパターン別に、現実的なアプローチを整理します。 状況別の推奨アプローチ データ容量 アクセス頻度 必要なアクセス速度 推奨アプローチ 備考 〜1TB 低頻度 即時〜数分 Box移行を検討 帯域制限(1TB/月/ユーザー)内で移行可能。複数ユーザー並列も選択肢 [9] 〜1TB 低頻度 12時間以内でOK S3 Glacier Deep Archive AWS内で完結。TB単価は最安クラス [8] 1TB〜100TB ほぼアクセスなし 12〜48時間でOK S3 Glacier Deep Archive まずAWS内最適化を優先 [8] 1TB〜100TB 月数回程度 数分〜数時間 S3 Intelligent-Tiering または S3 Glacier Flexible Retrieval ファイルサイズが大きい(数MB以上)場合はIntelligent-Tieringも有力 [8] 100TB以上 ほぼアクセスなし 数日でもOK DTO無料プログラム+オンプレ(HDD/NAS) カスタマーサポートに相談。審査通過が前提 [5] 100TB以上 ほぼアクセスなし 即時〜数時間 DTO無料プログラム+他クラウド B2(3倍egress無料)、Wasabi(egress無料)など [5] [10] [11] 100TB以上 月数回程度 数分〜数時間 S3 Glacier Flexible Retrieval AWS内での最適化を優先。Expedited/Standard/Bulk取得を使い分け [8] 小容量データ(〜1TB)の場合の追加オプション 1TB未満のデータであれば、より柔軟な選択肢もとりやすくなります。 Box移行 帯域制限内で移行しやすく、Unlimited storageプランなら追加ストレージ費用無しで収容可能 [9] DTO無料プログラムの活用 月間100GBのDTO無料枠と組み合わせれば、 数ヶ月に分けて段階的に退避 することも現実的 [6] [7] オンプレ保存(HDD/NAS) DTO無料プログラムが承認されれば、ローカル保存に切り替えたうえで、バックアップ戦略を自前で設計することも可能 [5] 各アプローチの重要ポイント 1. AWS内での最適化(第一優先) Storage Lensで現状分析 して、コストインパクトの大きいバケットを特定 [8] ライフサイクルルール で自動的にGlacier系へ移行 オブジェクト集約(s3tar) で小さなファイルをまとめてからアーカイブ まずは「 AWS内でやり切る 」ことで、DTOコストや移行リスクを最小化 [5] [8] 2. Box移行を検討する場合 帯域制限(1TB/月/ユーザー) を事前に把握 [9] データ量に応じて、 複数ユーザーでの並列化や分割移行 を設計 数十TB〜の移行では、 移行期間がボトルネック になる可能性が高い 3. DTO無料プログラムを利用する場合 早い段階で AWSカスタマーサポートに相談 [5] 移行先(他クラウド/オンプレ)、データ量、期間を含む 移行計画を明文化 公開情報はアップデートされるため、 最新の公式ドキュメントを随時確認 する [5] [6] [7] 国内での適用事例は、現時点では多くないと考えられるため、 検証的に小さな案件から試す のも選択肢 4. 他社ストレージを選択する場合 データレジデンシ (どの国・地域にデータが置かれるか) コンプライアンス要件(業法・顧客契約・社内規程) との整合性 ベンダーの サービス継続性・サポート体制・事業規模 [10] [11] [12] 共通して重要なポイント 「無制限ストレージ」には帯域制限が存在する可能性が高い 容量だけでなく、 どれだけの速度/期間で移行できるか を必ず確認する [9] S3 Intelligent-Tieringは万能ではない 小さいオブジェクトが大量にある場合、監視料金や128KB未満オブジェクトの扱いに注意 [8] DTO無料プログラムは「事前相談」が前提 公式条件に加え、自社のケースに関する運用条件を確認し、 書面レベルで認識合わせ しておく [5] [6] [7] まずはAWS内での最適化をやり切る Storage Lens/ライフサイクル/Glacier系/s3tarといったベーシックな施策でも、 TB単価を桁レベルで落とせる ケースがある [8] 執筆者について 森田 賢徳 株式会社ジャパン・インフラ・ウェイマーク 開発部 開発担当 ソフトウェアチーム 担当業務 Waymark Noteのフルスタック開発(iOS/Swift) Raspberry Piを用いたドローン連携制御によるリアルタイムAI開発 道路等のひび割れ・パッチ等検出のAI開発 その他、インフラ点検に関する多様な開発業務 免責事項 本記事に記載された情報は、 2025年11月時点 での公開情報および筆者の検証・ヒアリング結果に基づくものです。 各サービスの料金体系、機能、制限事項等は予告なく変更される場合があります 本記事の内容を実践される際は、必ず各サービスの 最新の公式ドキュメント をご確認ください [1] [5] [8] [9] [10] [11] [12] 特にAWS DTO無料プログラムの適用条件は、 個別の状況・審査・時期によって異なる可能性 があります [5] 本記事の情報に基づいて行われた意思決定や実装により生じた損害について、筆者および所属組織は一切の責任を負いかねます 商標について 本記事で言及されている製品名・サービス名は、各社の商標または登録商標です。 Amazon Web Services、AWS、Amazon S3、Amazon S3 Glacier、Amazon CloudFront、AWS Direct Connectは、Amazon.com, Inc.またはその関連会社の商標です Microsoft、Azureは、米国Microsoft Corporationの米国およびその他の国における登録商標または商標です Google Cloud、Google Cloud Storageは、Google LLCの商標です Boxは、Box, Inc.の登録商標です Backblaze、Backblaze B2は、Backblaze, Inc.の商標です Wasabiは、Wasabi Technologies, Inc.の商標です Raspberry Piは、Raspberry Pi Foundationの商標です その他、本文中に記載されている会社名、製品名、サービス名等は、各社の商標または登録商標です 本記事は特定の製品やサービスを推奨するものではなく、 技術的な調査結果・設計観点の共有 を目的としています。 参考リンク 本文中で触れた主な公開情報へのリンクです(いずれも2025年11月時点で参照)。 EU Data Act関連 EU Data Act 公式テキスト(Regulation (EU) 2023/2854) https://eur-lex.europa.eu/eli/reg/2023/2854/oj/eng European Commission「Data Act」概要ページ https://digital-strategy.ec.europa.eu/en/policies/data-act Taylor Wessing「EU Data Act FAQs」 https://www.taylorwessing.com/de/global-data-hub/2025/eu-data-act---understanding-the-issues/gdh---eu-data-act-faqs Deloitte「Cloud switching under the EU Data Act」 https://www.deloitte.com/dl/en/services/legal/perspectives/cloud-switching-eu-data-act.html AWS DTO関連 AWS DTO無料プログラム(Free data transfer out to internet when moving out of AWS) https://aws.amazon.com/blogs/aws/free-data-transfer-out-to-internet-when-moving-out-of-aws/ AWS Global Network FAQs(DTO 100GB無料枠 等) https://aws.amazon.com/about-aws/global-infrastructure/global-network/faqs/ AWS Free Tier における DTO 100GB 無料拡張 https://aws.amazon.com/blogs/aws/aws-free-tier-data-transfer-expansion-100-gb-from-regions-and-1-tb-from-amazon-cloudfront-per-month/ Amazon S3 Pricing https://aws.amazon.com/s3/pricing/ Box関連 Box Fair Use Policy https://www.box.com/legal/fairusepolicy その他ストレージサービス Backblaze B2 Cloud Storage Pricing https://www.backblaze.com/cloud-storage/pricing Wasabi Hot Cloud Storage Pricing https://wasabi.com/pricing Google Cloud「Data Transfer Essentials」 https://cloud.google.com/blog/products/networking/new-for-the-uk-and-eu-no-cost-multicloud-data-transfer-essentials
はじめに NTT西日本の吉田・﨑野・杉本です。 本記事では、先日開催されたアジアクエスト株式会社との共催イベントに参加したので、 そのイベント内容、登壇を通じて得られた学びや交流について報告します。 対象読者 AWSのAIサービス(Amazon Q Developer、Amazon Bedrock AgentCoreなど)の実践的な活用例を知りたい方 NTT西日本やアジアクエスト社のエンジニアの取り組みに興味がある方 若手エンジニアの技術的なチャレンジや成長事例に興味がある方 社外との共催イベントやLT登壇の経験談を知りたい方 背景・目的 生成AIの分野では、日々新しいサービスや機能がリリースされており、 それらの実用性を確かめるため、社内では検証が活発に行われています。 そして今回、アジアクエスト社との共催によるLT大会に登壇する機会を得て、 若手エンジニアによるAWSのAIサービスの技術検証の成果を発表しました。 イベント概要 イベント名 【NTT西日本共催】若手エンジニアによるLT会~AWSのAIサービスを使ったチャレンジ~ 開催日時 2025/10/28(火) 19:00 ~ 20:30 場所 オンライン イベントURL asiaquest.connpass.com イベント詳細 body { padding: 20px; } h1 { margin-bottom: 30px; } table { width: 800px; border-collapse: collapse; margin-bottom: 30px; } th, td { border: 1px solid #000; padding: 10px; } th { width: 150px; text-align: center; } td { width: 650px; text-align: left; } タイトル Amazon Qでできる限界とは? 発表者 NTT西日本 吉田 泰隆 概要 Amazon Q Developerがエンジニアの実務でどこまで活用できるのかを明らかにするため、「リソース操作」「セキュリティ遵守」「トラブルシューティング」の3つの評価軸で検証を実施しました。具体的には、Amazon CloudWatchアラーム作成やVPCエンドポイント構築などの実践的なシナリオを通じて、Amazon Q Developerの能力と限界、そしてエンジニアが担うべき役割について明らかにしました。その結果、問題の初期診断・ベストプラクティス提案は生成AI(Amazon Q Developer)に任せる一方で、設計方針の決定・リスク評価・承認判断・最終責任は我々エンジニアが担うべきということがわかりました。 タイトル Q Developerで実現するAWSインフラ構築の自動化 発表者 NTT西日本 﨑野 風音 概要 インフラ構築から運用に至るまでのプロセスにおいて、Amazon Q Developerの活用の幅について検証しました。具体的には、一般的な Web アプリケーション構成の構築から、構築後の運用フェーズにおけるセキュリティ強化(WAF に適用されたルールの見直し・最適化)までの一連の作業を、Amazon Q Developer との対話を通じて実施できるかを試みました。特にログの分析においては人間が時間をかけて実施する内容を瞬時にアウトプットしてくれるので、活用の幅も広いのではないかと感じています。逆に構築フェーズにおいては、各種パラメータを詳細に指定しなければAmazon Q Developerが勝手に判断する範囲も増えてしまうこともあるように、まだまだ実案件で活用するのは難しいように感じました。 タイトル Amazon Bedrock AgentCoreとは? 発表者 NTT西日本 杉本 脩 概要 2025年10月に正式公開されたAmazon Bedrock AgentCoreについて、プレビュー版を活用して機能調査と技術検証を実施しました。具体的には、AWSが提供する他の生成AIサービスとの比較検討や、スターターツールキットを用いたAIエージェントの作成・デプロイに挑戦しました。これらの検証から、Amazon Bedrock AgentCoreは生成AIアプリケーションを作りたい開発者向けのサービスであり、Amazon Bedrock Agentに比べてコーディングを必要とする反面、自由度が高く、Pythonコード数行でAIエージェントのロジックとインフラ設定をデプロイ・管理できるという優位性を確認できました。 タイトル Kiroのハッカソンに参加した話 発表者 アジアクエスト社 秋山 直輝 概要 Kiroのハッカソンに参加した体験談をメインに、Kiroの紹介、ハッカソンの紹介やKiroを使った開発の流れ、Kiroを使ってみた感想としてよかったところ(context機能やSteering機能など)、微妙だったところについて発表しました。また、ハッカソン参加に当たってのライセンス対応や動画作成の体験談の紹介なども行いました。 タイトル Amazon Q Developer CLIでインフラ+アプリ開発にチャレンジ 発表者 アジアクエスト社 安藤 遼河 概要 Amazon Q Developer CLI を使って取り組んだインフラ構築とWebアプリケーション開発について登壇しました。登壇者自らは直接開発作業を行わずに、Amazon Q Developer CLI に与える指示のみでどこまで開発が可能であるか挑戦しました。生成AIに対する指示の出し方や開発の進め方など、実際に直面した失敗談を交えながら、その解決策として取り入れたドキュメント整備、段階的なレビューの工夫のナレッジ共有を行いました。 印象に残った内容・学び 吉田 検証については、生成AI(Amazon Q Developer)のスピード感と正確性に驚きました。 その一方で、エンジニアが果たすべき役割も見えたので、これからも成長していきたいなと思いました。 また他の皆さんの発表を聞くことで、多くの刺激を受けました。今回の発表で満足することなく、これからもインプットとアウトプットのサイクルは続けていきたいです。 あと、オンラインだと参加者のみなさんのリアクションが少しわかりにくかったので、次回は対面イベントにも参加・企画したいなと思います。 﨑野 今回、LT大会への参加は初めての経験でしたが、とても良い機会となりました。 登壇を通じて、聞き手に伝わりやすい構成の重要性を改めて実感しました。 また、質疑応答の時間では多くの方から質問をいただき、発表内容に興味を持って聞いていただけたことを実感できて嬉しかったです。 杉本 今回の技術検証を通して感じたことは、AIエージェント開発の手軽さです。AIエージェント開発と聞くと、 「AWSコンソールで複雑な設定が必要で、デプロイが大変そう…」というイメージがありました。 しかし、Amazon Bedrock AgentCoreを使うことで、数行のコマンドと5分程度のコーディングでAIエージェントを作成できました。 また、コーディングの際に使用したStrands Agentは、開発者が書いたPython関数をそのままツールとして利用できます。 どの質問に対して、どのツールを呼び出し、その結果をどう解釈して最終回答を生成するか、という一連の流れがコードを通じて追えるため、ブラックボックス感が薄れました。 交流 今回の勉強会は、普段の業務で関わる機会の少ないメンバーと一緒に登壇しました。 発表を進める中で、AWSの設計や構築に取り組む際にそれぞれが抱えている課題や悩みに共感し、 それらの課題をどのようにAIで支援できるかについて共有したことで、新たな視点や学びを得ることができました。 特に、Amazon Q Developerの検証結果を共有した場面では、 「自分はこういう動きになりました!」 「このケースはどう対応しました?」 といった会話が生まれ、 互いの知見や工夫をその場で交換できたことが印象に残っています。 同じテーマに向き合う仲間として、実践的なノウハウを共有できた時間はとても楽しく、刺激的でした。 まとめ 今回のLT大会では「AWSのAIサービスを使ったチャレンジ」というテーマのもと、アプリ開発やインフラ構築など、登壇者それぞれが独自の視点でAIを活用しており、非常に多様性に富んだ興味深い発表が続きました。 今後、AIは単なるツールとしてではなく、開発や運用のパートナーとして活用していくことが重要です。 AWSのAIサービスは、アイデアをすばやく形にする力を持っており、これからの時代のイノベーションを加速させる鍵になると感じました。 今回のLT大会を通じて、AIの可能性を再確認するとともに、私たち自身がその可能性をどう引き出していくかが問われていると強く感じました。 執筆者 吉田泰隆 2023年に新卒でNTT西日本に入社 AWSを中心とした詳細設計·構築案件や生成AIに関する技術検証を担当 﨑野 風音 2023年に新卒でNTT西日本に入社 自治体様向けのMicrosoft365設計·構築やDX推進案件に従事 杉本 脩 2024年に新卒でNTT西日本に入社 AWSを中心としたインフラの提案·設計·構築案件に従事 商標 「AWS、Amazon Q Developer、Amazon Bedrock AgentCore、Kiro」は、Amazon Web Services, Inc.またはその関連会社の商標もしくは登録商標です。
はじめに 対象読者 背景 前提条件・動作環境 Amazon Q Developerとは? 検証内容 1. Amazon Q Developer for CLIによるWebアプリケーション構成の開発 2. Amazon Q Developer for CLIによる構成のチェックとAWS CloudFormationテンプレート作成 3. Amazon Q Developer for CLIによるAWS WAFログの分析とWeb ACLの作成 苦労したポイント まとめ 執筆者 商標  参考資料・出典 はじめに NTT西日本の﨑野 風音です。 本記事では、AWSの生成AIサービス「Amazon Q Developer for CLI」を使って、どこまでインフラ構築を自動化できるのかを検証しました。 実際に試した結果や、うまくいった点・苦労した点をまとめています。 本記事は2025年10月時点の情報に基づきます。 対象読者 本記事が想定する対象読者は以下の通りです。 AWS、生成AIサービスを勉強している人 生成AIの活用方法に困っている人 生成AIを活用したAWSインフラ構築について知りたい人 背景 本検証はアジアクエスト社共催の外部登壇(AWSの生成AIを活用した取組)に向けて実施しました。 登壇の模様は後日別の記事として公開予定ですので、あわせて読んでいただけるとありがたいです。 また、テーマとしてAmazon Q Developer for CLIを選んだ背景としては、 以下にあげるような課題をAmazon Q Developer for CLIを活用することで解決できると感じたためです。 インフラ構築の手順は個人依存で標準化が難しい AWSサービスは多岐に渡り、学習コストが高い 構築時にヒューマンエラーによるリスクが高い 手作業による構築に時間がかかる 運用におけるリソース最適化に割く時間がない 前提条件・動作環境 本検証はWindows環境で実施しています。 Windows環境におけるAmazon Q Developer for CLIのインストールについては以下の記事を参考に実施しております。 1 Amazon Q Developer for CLIを使って、AWSのリソースをAIで作成⇒調査⇒構成図作成までやってみて、構築作業を楽にしよう | コラム | クラウドソリューション|サービス|法人のお客さま|NTT東日本 記事中のIPアドレス、FQDN、ID等はマスクしています。Amazon Q Developerの実際の応答では左記情報含め出力されます。 Amazon Q Developerとは? Amazon Q Developerとは、AWSが提供する開発者向けに設計された生成AIアシスタントです。 AWSの開発作業を効率化するためのツールになります。 AWSのサービスを使ったコードの自動生成やAWSの公式ドキュメントやベストプラクティスの検索、トラブルシューティング支援等をチャット形式で質問することができます。 aws.amazon.com Amazon Q Developerは以下3つの方法で利用可能です。 Amazon Q Developer for CLIとして利用 コマンドラインで自然言語を使ってAWS操作やコード生成をしたい際に便利です。 AWSマネジメントコンソールから利用 AWSマネジメントコンソール右側に表示されるQアイコンから利用できます。画面のコンテキストを理解して最適な回答や操作方法を提案してくれます。 IDEプラグインとして利用 Visual Studio CodeのようなIDEにプラグインを追加することでコード補完やリファクタリング等をAmazon Q Developerがサポートしてくれます。 今回は一つ目のAmazon Q Developer for CLIをご紹介します。 ※現在、Amazon Q DeveloperはKiro CLIに統合されています。 詳細はこちらの記事をご覧ください。 aws.amazon.com 検証内容 本検証は大きく分けて以下の3つを実施しました。 Amazon Q Developer for CLIによるWebアプリケーション構成の開発 Amazon Q Developer for CLIによる構成のチェックとCloudFormationテンプレート作成 Amazon Q Developer for CLIによるAWS WAFログの分析とWeb ACLの作成 全体の流れは以下のようになります。 手順1~3が「1. Amazon Q Developer for CLIによるWebアプリケーション構成の開発」 手順4~6が「2. Amazon Q Developer for CLIによる構成のチェックとCloudFormationテンプレート作成」 手順7,8が「3. Amazon Q Developer for CLIによるAWS WAFログの分析とWeb ACLの作成」に対応しています。 1. Amazon Q Developer for CLIによるWebアプリケーション構成の開発 このセクションでは、Webアプリケーション構成をAmazon Q Developer for CLIとの対話によって構築していく手順を紹介します。 始めに、以下のような命令を実施しました。 ※EC2インスタンス:Amazon EC2 インスタンス 「 EC2インスタンスを1台パブリックサブネットに起動してください。簡単なゲームアプリを構築してください。」 ※VPC等の作成もAmazon Q Developer for CLIを活用しましたが、ここでは割愛しています。 Amazon Q Developer for CLIの応答はこちら。 ちなみに、指定しなかった設定項目はAmazon Q Developer for CLIが自動で設定します。 また、同一アカウント内にAmazon Virtual Private Cloud(以下、VPC)が複数ある場合は、どのVPC(指定がある場合はサブネットまで)でインスタンスを起動するかを指定してあげてください。 アクセスも確認できたので、次は以下の命令を実施しました。 ※ALB:Application Load Balancer 「ALBをパブリックサブネットに配置し、EC2インスタンスはマルチAZ配置で、かつプライベートサブネットで起動してください。」 Amazon Q Developer for CLIの応答はこちら。 こちらも問題なくアクセスを確認できました。 2. Amazon Q Developer for CLIによる構成のチェックとAWS CloudFormationテンプレート作成 セクション1の操作を進め、以下の構成を構築しました。 使用されているAWSリソース自体はこちらの意図した通りとなったので、ベストプラクティスと照らし合わせて構成評価を実施しました。 応答はこちら。 ご覧の通り、エンタープライズレベルで求められる要件と比較すると改善が求められる結果となりました。 構築時に詳細なパラメーターを指定することである程度の改善は見込めるかもしれません。 また、以下の通り、Amazon Q Developer for CLIを活用することでAWS CloudFormationテンプレートの作成も確認できました。 もちろん、そのまま本番運用せず、セキュリティ・コスト・可用性等の観点でのレビューが必須です。 ここまでを振り返っての個人的な感想です。 厳密な構築が求められない検証(触ってみた程度)であればAmazon Q Developer for CLIは有効です。 実案件に応用する場合は、「Amazon Q Developer for CLIで簡易構築→AWS CloudFormationテンプレート作成→手動チェック」が必須だと感じました。 3. Amazon Q Developer for CLIによるAWS WAFログの分析とWeb ACLの作成 ここからは構築後のフェーズにおけるリソース最適化へのAmazon Q Developer for CLI活用事例になります。 今回はAWS WAFログの分析から設定ルールをブラッシュアップできないかを検証しました。 ※事前にAWS WAFのログ記録機能を有効化し、Amazon Kinesis Data Firehose経由でAmazon S3に保存する必要があります。 始めに、以下のような命令を実施しました。 「過去1か月間のトラフィックを分析し、AWS WAFに追加すべきルールを提案してください。 分析の際には部分サンプルから判断せず、完全なデータを活用してください。 」 左上がAWS WAFダッシュボードの表示、左下がAmazon Athenaでのクエリ結果(過去一か月間のブロックイベント数の多い上位10個のIPアドレスを表示)、右側がAmazon Q Developer for CLIによる応答結果です。 ご覧の通り、分析結果が一致していることが確認できます。 ※ちなみに、Amazon Athenaで用いたSQLもAmazon Q Developer for CLIで作成しました。 上記結果から、実際のトラフィック状況とAmazon Q Developer for CLIの分析結果に認識齟齬がないことが確認できたので、AWS WAFルールのブラッシュアップを依頼した結果がこちら。 ルールの自動作成と、作成理由の説明まで実施してくれました。 問題なければルールのアタッチまで実施可能です。 苦労したポイント ここまで、「Amazon Q Developer for CLIは便利ですよ!なんでもできますよ!」といったような紹介に見えるかもしれませんが、私が検証を実施する中で苦労したポイントも多々ありました。 そちらを以下に紹介します。 出力の揺らぎ 抽象的な指示では意図しない出力結果が出てしまうことも 詳細なパラメーターの指定や、分析対象期間を明確化することが大切です。 エラーハンドリング 権限不足等のエラーが発生しやすいです。対応方針を事前に明確化しておくと開発がスムーズに進みます。(エラー時に停止するか、必要な権限は取得させて続行するか) エラーハンドリングを指定しないと動作しないアプリが誕生したり、なんてこともありました。 サンプリング 「3. Amazon Q Developer for CLIによるAWS WAFログの分析とWeb ACLの作成」セクションで紹介したトラフィック状況の分析ですが、分析当初はAmazon Q Developer for CLIの応答結果と実際のトラフィック状況に大きな差異が見られていました。 対話を繰り返す中で、 「Amazon Q Developer for CLIがサンプリングを実施したうえで応答を出力していた」 ことが判明しました。 そこで、 サンプリングを実施せず、完全なデータを活用するように 命令をしたところ、正しい結果が出力されました。 まとめ Amazon Q Developer for CLIは、AWS構築のスピードを大幅に向上させるツールです。 特に、検証やPoCでは非常に有効ですが、本番環境では生成結果のレビューとベストプラクティス適用が必須です。 また、構築後のレビューや運用改善にも活用できる可能性があります。 今後は、より高度な構成やCI/CDとの連携、セキュリティ強化の自動化など、さらに実践的な活用方法を検証していきます。 執筆者 﨑野 風音 (NTT西日本 ビジネス営業部所属) M365案件の提案、設計、構築、運用に携わっています。 また、社内向けのAWS勉強会や資格取得支援施策等を実施しています。 商標  「AWS」「Amazon Q Developer」「Amazon Q Developer for CLI」「Kiro CLI」「Amazon EC2」「ALB」「AWS CloudFormation」「AWS WAF」「Amazon Kinesis Data Firehose」「Amazon S3」は、Amazon Web Services,Inc.またはその関連会社の商標もしくは登録商標です。 その他、記載されている会社名、製品名は、各社の登録商標または商標です。 参考資料・出典 本記事を執筆するにあたり、以下のサイトを参考にしました。 Amazon Q Developer for CLIを使って、AWSのリソースをAIで作成⇒調査⇒構成図作成までやってみて、構築作業を楽にしよう | コラム | クラウドソリューション|サービス|法人のお客さま|NTT東日本 ↩
はじめに NTTビジネスソリューションズの衣川です。 2025年度のハードニング競技会『 Hardening 2025 Invisible Divide 』に参加したので、体験記を書きたいと思います。 ハードニング競技会は、ECサイトなどのビジネスシステムに潜む脆弱性への堅牢化能力を総合的に競うコンペティションで、Hardening Projectが毎年開催しています。 具体的には、応募した人の中からチームを組み、約20台の脆弱な設定がされたサーバーをサイバー攻撃から守りつつ、ECサイトを正常稼働させ得られた売上や、ミッションというお題をクリアすることで得られるポイントなどで最終的な順位が決まります。 今回参加してきた2025年度版『Hardening 2025 Invisible Divide』の開催概要は以下の公式ページに記載されています。 開催概要/募集要項 – Hardening 2025 Invisible Divide | Hardening Project 対象読者 本記事が想定する対象読者は以下の通りです。 ハードニング競技会を聞いたことはあり興味もあるが、具体的にどんなことをするのかイメージできない方 ハードニング競技会に参加予定で、準備やイベント中の段取りの情報収集したい方 背景 以下2つが、今回参加しようと思った動機になります。 社内で開催されたMini Hardeningに参加し、得られる学びが多かったことから、より大規模な競技会に興味がわいた テクニカルだけでなくビジネス(売上確保や顧客対応など)への対応も求められることが業務にも活かせると考えた スケジュール 競技会に参加するにあたり、実施したことを以下に記載します。 日付 実施内容 詳細 8/18 申し込み締め切り 応募動機などを記載 8/22 応募結果発表 当選連絡とチームメンバー発表 8/22 - 10/7 準備期間 チームメンバーで準備を進める 10/5 競技会資料の公開  資料は100ページ越え  10/7 沖縄現地入りし、最終調整 メンバー全員が対面で集合 10/8 Hardening Day 競技会 本番! 10/9 Analysis Day 発生したインシデントを整理 10/10 Softening Day 準備期間からHardening Dayまでの取り組みを各チームで発表 チームメンバー 全8人のチームメンバーはほぼ全員初対面で、インフラ企業や法律事務所など様々な業界の方に加え、学生の方もおられるなど多様なバックグラウンドをもったチーム構成になりました。 私は普段、IT環境を健全で安全な状態に保つための「衛生管理」であるサイバーハイジーンの実現にむけたお客様の支援をしています。 他のメンバーも基本的にITに関わりのあるメンバーがそろっていましたが、競技経験としては、約10年前のハードニング競技会に参加された方が1名で小規模なハードニング競技会への参加経験者が私を含めて2名という構成でした。 経験者が少なく競技会の準備という観点では大変でしたが、その分フラットな関係で話し合えたことはよかったと感じています。 まず最初にメンバーのやりたいことをもとに準備と当日の役割分担のためにビジネスチームとテクニカルチームに分け、私はテクニカルチームに所属しました。 準備 毎週定例会を実施して、チームメンバーで分担して準備を進めました。 (約1か月半の準備期間で打ち合わせや演習を9回実施していました) 全部で70個以上のタスクをこなしたのですが、以下にビジネスチームとテクニカルチームのそれぞれについて3つ抜粋しています。 ■ビジネスチーム ECサイトの販売戦略(在庫補充のタイミングなどをチーム内で検討) 個人情報漏洩時の対応整理(競技会中に個人情報が漏洩してしまうことを想定) 特定商取引法による表記の作成(ECサイトを利用するので) Market Placeの製品選定 社内規程類の作成 ※ Market Place(以下、MP)とは、ハードニング競技会で参加チームがスポンサー企業の製品やサービスを利用できる仕組みです。 MarketPlaceで診断ツールや支援サービスを購入することで、チームは不足する技術やリソースを補えます。 ■テクニカルチーム 初期パスワードから変更するパスワードの検討(複雑だけれど、すべて同じにしてしまわないように工夫) コマンドチートシートの作成(後ほど詳細を説明) インシデント対応フロー整理と模擬演習での改善(後ほど詳細を説明) ファイアウォールのポリシー検討(ホワイトリストで通すべき通信を選定) 脆弱な設定の洗い出し(競技会資料が公開されてから実施) この中から私がメインで担当した以下の2つを紹介したいと思います。 コマンドチートシートの作成 インシデント対応フロー整理と模擬演習での改善 コマンドチートシートの作成 Linuxユーザーのパスワード変更やデータベースバックアップなどのコマンド自体は生成AIで出すことはできるものの、それが正しく動作するか検証し、整理していました。 この検証をしていく中で、Linux・データベース・WordPressなどさまざまなツールのセキュリティ対策を経験でき、良い経験になるとともに、セキュリティは幅広い知識が求められることも再認識しました。 また、「ハードニングファン★リファクタ」に記載されていたLL改ざん検知※も動作確認してみました。 (※LL改ざん検知:Linuxで利用されるLLコマンド(ls -l のエイリアス)を活用したファイルの改ざん検知をする手法) 改ざん検知ができるOSSは導入ミスを考慮して利用せずに、LL改ざん検知を本番で利用させていただきました。 ハードニングファン★リファクタ インシデント対応フロー整理と模擬演習での改善 インシデントが起きた時の対応を、メンバーの役割分担から整理しました。 しかし、対応時間が限られていることと、複数のインシデントの同時発生が想定されることから、厳密なフローの整理と迅速で柔軟なインシデント対応の間のトレードオフに悩まされました。 そこで、以下2つの演習を実施して、作成したフローが実運用に使えるかどうかを検証しました。 自作したHardening競技環境を活用したチーム内での演習 インシデント対応のシナリオを作成し、机上演習 自作したHardening競技環境は、WordPressがインストールされたWebサーバー1つを守るハードニング競技で、詳細については本ブログにて後日掲載予定です。 実際に演習を実施していくと、複数のツールを使う余裕がないことや、複数のインシデントが同時に発生した時に全体の状況を確認しづらくなることなどがわかり、フローや報告方法など具体的な手順を改善していきました。 前日 チームメンバー全員が前日入りして最後のミーティングをしました。 特に、競技資料が公開されたのが数日前ということもあり、資料の読み込みや設定値の最終確認などを実施していました また、当日の段取りや気を付けるべきことなど「経験者でないとわからないこと」を相談員の方に相談していました。 「相談員」は競技参加者をサポートしてくださる方々で、以下に詳細が記載されています。 NECセキュリティブログ - Hardening 2025 Invisible Divide 参加記 Hardening Day この日が本番の競技会の日で、沖縄空手会館で9時から実施されました。 事前説明のあとに競技が開始されたのですが、競技会中はインシデントの連続でした。 以下に2つ抜粋して紹介したいと思います。 ECサイトが稼働していない まず、ECサイトが稼働していない時間が多かったです。 下図はすべてのECサイトが起動していない時の画像です。 (Took a Nap(昼寝中)はECサイトが稼働していないことを表現しています) 全てのECサイトが稼働していない時のダッシュボード(主催者から写真掲載の許可をいただいております) 他のインシデント対応で人手が不足しており対応が遅くなりましたが、振り返ると売上に直結するショップの対応を優先しておくべきでした。 事前にインシデント対応の優先順位づけのルールを決め、お客様影響があるインシデントを最優先しようと決めていたのですが、いざインシデントが起きると十分に意識できなくなってしまいました。 個人情報の漏洩 競技の中盤に、対応が漏れていたサーバーからディレクトリリスティングによって個人情報が漏洩してしまいました。 チームのメンバーの中で対象のサーバーOSに慣れている人がおらず、対応に苦慮しました。 (設定変更をいくつも試したのですが、どれも上手くいきませんでした) 最終的には、WAFで当該ディレクトリへのアクセスを禁止することで何とか対応できましたが、もし現実で起きたら、と思うと恐ろしかったです。 上層部からの呼び出し 競技会の設定として、ある架空の企業の社員として競技会に臨むのですが、その企業の上層部にインシデントの対応状況を聞かれる(詰められる)場面がありました。 私は直接対応しなかったのですが、対応したリーダーのテンションが下がっており、なかなか厳しい状況だったようです。   MP利用時の不手際 MPでWAFの購入権を獲得できたので、さっそく購入しようと思ったのですが、競技会環境への接続に手間取り、結果として導入できたのは11時ごろになってしまいました しかし、この後に一部メンバーがWordPressなどのCMSの管理画面にアクセスできなくなりました。 最終的には管理画面への通信をWAFでブロックしてしまっていたのですが、WAFの導入前後で正常性確認をすることで、攻撃をうけたのか、自分たちの設定ミスなのか、切り分けできる状態を事前に作るべきでした。 普段の業務なら注意できていることも慌てている時にはおろそかになってしまうことを身をもって体感しました。 ちなみに、別のネットワークからならアクセスできることをチーム内で共有したことで解決の糸口が見つかり、些細な事でも共有する密なコミュニケーションの重要性を再認識させられました。 Analysis Day この日はHardening Dayで受けた攻撃や自分たちの取り組みを振り返る日として設けられていました。 競技会当日は時間がなく共有できなかった個人の取り組みの共有や、MPで購入したWAFを提供してくださったベンダーの方からどのような攻撃を受けていたのかをログをもとに説明など有意義な振り返りになりました。 Softening Day 最終日に行われたSoftening Dayでは、主に以下4つが行われました。 各チームの取り組みの発表 運営側からの競技会の説明 スポンサー賞 順位発表 私たちのチームは総合順位が12チーム中7位でしたが、技術点は1位でした。 (技術点が1位でしたが、総合順位が中位だったことは後述します) 自チームの結果発表(主催者から写真掲載の許可をいただいております) 技術点が1位だったことをチームメンバーと振り返りをした時に以下2つが挙がりました。 初動対応によるPWと権限変更 ファイアウォールの詳細な設定(ホワイトリストで制御) 特に2つ目のファイアウォールについては設定値の確認も入念に実施していたので、当日効果を発揮してくれていたのであれば嬉しいです。 振り返り 総括として、学んだことや今後に活かしたいことを記載します よかった点 チームビルディング ハードニング競技会で最も重要だと感じたのはチームビルディングです。 準備から当日の競技会、最後の振り返りまでチームメンバーとのコミュニケーションが本当に大切でした。 リーダーが率先してチームビルディングに取り組んでくれたことで、定例会でのコミュニケーションのしやすさに加え、チャットへはリアクションをすることや他のメンバーのタスクも一緒に考える、など風通しがよく、準備を進めやすかったです。 私個人としては、競技会中はチームは2つの場所に分かれて作業するのですが、お互いの現状を把握するために走って移動しており、歩数計が約1万歩になっていました。 演習の重要性の再認識 一度作成したインシデント対応フローやチーム内での報告方法を、模擬環境での演習や机上演習で利用することで、明らかになった改善点を多く修正できました。 それでも本番の競技会では、インシデント対応フローが上手く機能していないこともあったので、事前準備の段階で改善していたため本番でも一定の機能を果たせたのだと考えています。 インシデント対応や作業手順などは継続的にテストし、改善していくことが重要だと身をもって実感しました。 啓発点 ビジネスを考慮した判断 競技会では売上を増やすための対応が後手に回った結果、売上が増えず技術点は高いが順位は中位にとどまりました。 私含めてテクニカルチーム側が、インシデント対応のフローの優先順位に則って売上が上がっていないことへの対処を優先できていなかったことが原因だと考えています。 この反省は普段の業務に活かせると考えており、ビジネスとテクニカルが両方ともお互いのことを理解し、自分の取り組みが何につながるのかを把握することがチームの目標達成には重要だと感じました。 技術的スキルの不足 Softening Dayで他のチームの発表を聞いていると、OSSを活用したサーバー一括管理や複数サーバーをたてた模擬環境でのテストなど、技術的に高度な取り組みをしているチームもありました。 今の私ではそこまで手が回らなかった・技術的に本番で使えていたか怪しいと感じ、その差を痛感したことで自分も技術力を高めたいというモチベーションにもつながりました。 おわりに ここまで記載したとおり本当に多くの学びを得られたのは、実務で滅多に起こりえないセキュリティインシデントを(疑似的に)経験できるイベントだったからこそだと感じています。 今回、このような素晴らしい競技会を企画してくださった運営の皆様はじめ競技会に関わってくださった皆様、そしてチームメンバーに感謝申し上げます。 執筆者 衣川 琢磨(NTTビジネスソリューションズ株式会社 バリューデザイン部) セキュリティ分野の中でも特にサイバーハイジーンの実現にむけて支援するマネージドサービスの開発と運用に携わっています。 商標 WordPressは WordPress Foundation の登録商標です。 Linuxは Linus Torvalds 氏の登録商標です NECは 日本電気株式会社(NEC Corporation) の登録商標です。
1.はじめに 本記事では、LLM-as-a-Judge(AIによる要約評価手法)を紹介し、検証結果を共有します。 対象読者:AI活用や自然言語処理、要約評価に関心のある方 1.はじめに 2.背景・目的:LLMによる要約評価の課題と改善の可能性 3.評価手法の解説:BLEU/ROUGEとLLM-as-a-Judgeの違い BLEU/ROUGE(単語一致ベース) LLM-as-a-Judge(意味理解ベース) 4.検証の概要:LLMモデルと要約評価の実験条件 5.評価算定方法:LLM-as-a-Judgeによるスコアリング手法 評価指標 評価スコア 6.検証結果と考察:AI評価の精度比較 評価の平均スコア 人の目とLLM-as-a-Judgeの評価結果比較 誤りのある要約5件 個別の評価結果 考察ポイント 7.まとめ:LLM-as-a-Judgeで要約評価を効率化する未来 執筆者 商標 2.背景・目的:LLMによる要約評価の課題と改善の可能性 私の業務では、AI技術を活用して社内外のビジネス課題を解決しています。特にニーズが高いのが LLMによる文章要約 で、要約業務の効率化や要約データ活用へのニーズが増えています。 しかし、従来の評価手法(BLEUやROUGE)は単語一致ベースで、人間の評価と乖離が大きく、結局は人手評価が主体でした。複数人で評価する場合、主観によるばらつきが避けられません。 そこで、 LLMに評価を委ねる「LLM-as-a-Judge」 に注目し、人に近い評価ができるか検証しました。 3.評価手法の解説:BLEU/ROUGEとLLM-as-a-Judgeの違い 従来の評価手法BLEU/ROUGEの限界と、より人間に近い判断を目指すLLM-as-a-Judgeの特徴を解説します。 BLEU/ROUGE(単語一致ベース) 参照文とどれだけ似ているかをチェックする、シンプルな評価方法です。 単語やフレーズの一致率を数値化 メリット:定量評価が可能 デメリット: 言い換えを正しく評価できない 文脈や自然さを無視 参照文が必須 LLM-as-a-Judge(意味理解ベース) AIが文章の文脈・論理・自然さを判断し、参照文なしで評価できる新手法です。 LLMが文章の意味・文脈・自然さを総合判断 メリット: 「自然さ」「論理性」など複数観点で評価 人間の評価に近い傾向を示す可能性がある 参照文不要で創作やQAにも対応 デメリット: 評価基準の不透明性(評価の説明ができない場合が多い) モデル選定やプロンプト設計によって精度が変動 高性能LLMを使用する場合はコストがかかる 4.検証の概要:LLMモデルと要約評価の実験条件 コールセンターの会話データを用いて、以下の条件でLLM-as-a-Judgeの評価精度を検証します。 元データ:コールセンター会話のダミーデータ 評価対象:元データをLLMで要約したデータ5件(誤りのある要約5件) 評価LLM:オンプレミス対応OSSモデル(gpt-oss-120b/20b) 5.評価算定方法:LLM-as-a-Judgeによるスコアリング手法 論文に基づく指標で、AIが要約の誤りと重大度を判定し、減点方式で品質を評価します。 評価指標 LLM-as-a-Judge関連論文 *1 を参考に、以下の指標を設定します。 Issue Type (誤り種別)  Syntactic Label (文法的ラベル) Severity (重大度)  [補足事項] ・ 誤り種別の具体的な項目と重大度の重みづけ点数は論文で明記されていないため、本検証で独自に設定 ・ 文法的ラベルは論文に記載されている指標で設定 評価スコア 評価スコアは、論文に記載されている次の算出式により、100点を基準に減点方式で計算します。 スコアの算出式 スコア = (1 - (減点合計 ÷ 単語数)) × 100 [補足事項] ・ スコアは 0~100 点の範囲で評価し、負の値は 0 点として扱います。 ・ 要約の長さによる影響を調整するため、減点合計を単語数で割って正規化しています。 ・ 減点合計が非常に大きく、減点合計 ÷ 単語数 が 1 を超える場合、スコアは負となり 0 点で算出されます。この場合、全スコアの正規化には該当しません。 スコア算出の例 CRITICAL(致命的)数:3件 MAJOR(重要)数:1件 MINOR(軽微)数:0件 単語数:70 減点合計: CRITICAL:3 × 10点 = 30点 MAJOR:1 × 5点 = 5点 MINOR:0 × 1点 = 0点 合計:35点 スコア:(1 - 35÷70)× 100 =50点 6.検証結果と考察:AI評価の精度比較 gpt-oss-120bとgpt-oss-20bを用いて検証を行い、誤りのある要約の評価結果を比較しました。 評価の平均スコア gpt-oss-120bとgpt-oss-20bの平均スコアを比較した結果、gpt-oss-120bは人間の評価に近い傾向を示しましたが、gpt-oss-20bは要約の誤りを検出できませんでした。 LLM-as-a-Judgeで評価した平均スコア ※100点より低い(誤りを判別して減点している)ほど人の判断に近い LLM 誤りありの要約 gpt-oss-120b 68点 gpt-oss-20b 100点 gpt-oss-120b : 人間の評価と近い傾向があり、68点評価 gpt-oss-20b:誤りを検出できず、100点評価 以降は、誤りのある要約を適切に減点できた gpt-oss-120b の評価結果の例を紹介します。 人の目とLLM-as-a-Judgeの評価結果比較 誤りのある要約の判定結果は以下のとおりです。すべての要約で誤りが指摘され、そのうち3件は人の目で見た誤りと一致しました。総合的には、概ね人の目に近い評価結果となっています。 誤りのある要約5件 No 人の目で見た誤り判定 LLM-as-a-Judgeの誤り判定(抜粋) LLM-as-a-Judgeと人の目の判定比較 1 回答に欠損があるため ・画像の条件 原文では 「画像は文字や顔写真がはっきりと確認できること」が条件と明示されているが、要約ではこの条件が省略 されている。 LLM-as-a-Judgeは、人の目と 同じ観点を指摘 2 事実と異なる内容が含まれる ・電話の利便性を再確認 オペレーターが電話の利便性を再確認したという記述は元の文に存在せず 、事実と異なる。 同上 3 回答に欠損があるため ・mailの設定 確認 メールクライアントがGmailである旨が記載されておらず 、重要情報が欠落している。 同上 4 回答に欠損があるため ・連絡手順 ・返信時間の詳細 要約では「 返信時間を説明した」だけで数値情報が欠落 している。 LLM-as-a-Judgeは、人の目と 同じ観点の一部を指摘 5 回答に欠損があるため ・郵送先 ・通知方法 ・公式サイト活用案内 【概要】書類送付先「▲▲サービスセンター解約係」の 住所情報が欠落 しており、手続きに必要な重要情報が欠落しているため。 同上 誤りのある要約5件すべてで、LLM-as-a-Judgeも誤りを指摘。 3件(No1、2、3)は、人の目の指摘事項と一致。 残り2件(No4、5)は、人の目では複数の観点で指摘していたが、LLM-as-a-Judgeはその内の一部を指摘。 個別の評価結果 個別の評価結果の一つ(例:上記のNo2)を紹介します。No2-1では人間の評価と同じ指摘ができていますが、No2-2~2-4では、人間の評価では誤りとされなかった点をLLMが指摘しており、求める要約の粒度によっては、LLMへの追加指示などの対策が必要であることが分かりました。 LLM-as-a-Judgeの評価スコア:50点 * 要約文書 * 人の目で見た判定結果 * LLM-as-a-Judgeの評価結果 No Issue_type Syntactic_label Severity Applicable_parts Reason 2-1 Inaccuracy Intrinsic Predicate CRITICAL 【概要】…電話の利便性を再確認し… → 原文ではオペレーターが電話の利便性を再確認したという記述はなく、顧客が「電話が一番安心感がある」と述べただけであるため、内容が誤っている。 オペレーターが電話の利便性を再確認したという記述は元の文に存在せず 、事実と異なる。 2-2 Omission Number&Time MAJOR 【概要】…混雑時間帯やチャット・メール対応を案内… → 原文では「平日の午前10時~11時、午後2時~4時」と具体的な時間帯が示されているが、要約で省略されている。 重要な具体的情報(混雑しない時間帯)が欠落している。 2-3 Omission Attribute MAJOR 【概要】…混雑時間帯やチャット・メール対応を案内… → 原文では「AIチャットは公式サイト・▲▲サービスの問い合わせページから利用でき、FAQ等に即時対応できる」ことが説明されているが、要約に記載がない。 代替手段としてのAIチャットの利用方法・範囲が欠落している。 2-4 Omission Number&Time MAJOR 【概要】…チャット・メール対応を案内… → 原文では「メールは▲▲サービスの問い合わせフォームから送信し、1~3営業日以内に返信される」旨が示されているが、要約に抜けている。 メール問い合わせの手順と返信期限が欠落している。 Inaccuracy Intrinsic(内的不正確性)が1件判定されており(No2-1)、人の目と同じ誤りを指摘。 Omission(省略)が3件判定されているが(No2-2~2-4)、詳細レベルの情報不足を指摘しており、求める要約の粒度によって判断が異なる指摘。 考察ポイント 検証の結果、LLM-as-a-Judgeによる評価は人に近い判断が可能であり、評価を数値化することで公平性の向上が期待できることが分かりました。さらに、要約の粒度を明示することで判定誤差を減らせるほか、使用するLLMモデルの選定によって精度をさらに改善できる可能性があります。 LLM-as-a-Judgeは人間に近い評価を示す傾向がある 実務で導入する際には、評価観点を明確に定義し、基準を統一することで、より安定した評価が得られる可能性があります。   評価を数値化できるため、主観の排除により公平性の向上が期待される スコアリングをダッシュボード化(可視化)することで、改善ポイントを迅速に把握できる可能性があります。 要約粒度の指定(プロンプトチューニング)で精度改善の余地あり プロンプトチューニングで「要約の対象情報」「省略可能な情報」を明示的に指示し、ユースケースごとにテンプレート化することで、Omission(省略)判定の不要な誤差を減らせる可能性があります。 LLMの違いが評価精度に大きく影響 モデル選定時には、パラメータ数だけでなく、必要に応じて社内データで追加学習を行うことで、評価精度を改善できる可能性があります。 7.まとめ:LLM-as-a-Judgeで要約評価を効率化する未来 今回は、LLM-as-a-Judgeの検証結果をご紹介しました。LLM-as-a-Judgeは、人間の判断に近い結果を得られる可能性があり、要約評価の効率化と品質向上に有望な手法であることが示されました。今後は、プロンプトチューニングや高性能LLMの活用により、さらに精度を高め、文書評価業務全体の効率化を目指します。 執筆者 倉田裕紀(NTT西日本 技術革新部 AI技術担当) AIエンジニアとして、社内外のAIプロジェクトを技術支援 商標 「GPT」は、OpenAI OpCo, LLC の商標もしくは登録商標です。 *1 : A Survey on LLM-as-a-Judge
はじめに NTTビジネスソリューションズの平田です。 インターネットで安全に情報をやり取りするために欠かせない技術のひとつがTLS(Transport Layer Security)です。TLSでは、通信を暗号化するための共通鍵を安全に共有する仕組みとしてECDHE(Elliptic Curve Diffie-Hellman Ephemeral、楕円曲線暗号による鍵交換)が利用されています。本記事ではECDHEの仕組みをざっくりとしたイメージで解説します。 なお、この解説は直感的な理解を意図したものです。わかりやすさを優先したため、厳密さは不十分である点にご留意ください。 本記事は2025年11月時点の情報に基づきます。 対象読者 本記事が想定する対象読者は以下の通りです。 情報処理安全確保支援士の学習をされている方 ECDHEによる鍵交換の仕組みを知りたい方 背景 NTTグループでは 専門性を重視する人事制度 が導入され、NTT西日本グループにおいても社員個々人の専門性がこれまで以上に重視されるようになりました。社員の専門性向上のために、会社側から各種の研修、通信教育、オンライン学習プラットフォームのアカウント提供などの サポート があります(所属会社により多少の差異があります)。そのほかにも社内講師による勉強会やハンズオンなどが活発に開催されています。その一つとして情報処理安全確保支援士の対策講座を筆者が講師として開催し、約50名に参加いただきました。 講座の中で 2025年春試験(午後問2) に関連し、楕円曲線暗号(Elliptic Curve Cryptography, ECC)を利用した鍵交換(ECDHE)の説明がわかりやすかったと好評だったので、Engineers' Blogの記事として再編集して掲載します。 TLSによる暗号化 TLS(Transport Layer Security)では、通信データの暗号化に共通鍵暗号方式が用いられ、共通鍵(本記事ではトラフィック鍵と呼びます)は公開鍵暗号方式を用いて事前に安全に共有されます。 送信者から受信者に送られるデータは、送信者側で暗号化され、受信者側で復号されます。この暗号化と復号には、送信者と受信者が共有する同一のトラフィック鍵が使用されます。 トラフィック鍵による暗号化と復号 通信経路を流れるデータは暗号化されているため、第三者が通信を盗聴したとしても、データの内容を解読できません。しかし、第三者がトラフィック鍵を入手し通信を盗聴した場合にはデータを解読できてしまい、その結果情報漏えい(機密性の侵害)が発生する可能性があります。 そのため、トラフィック鍵は送信者と受信者以外には知られないよう、暗号化通信の開始前に安全な方法で共有する必要があります。その際に利用するのが鍵交換です。鍵交換の際には送信者と受信者の間で通信が行われますが、仮にこの通信が盗聴されたとしても、トラフィック鍵が漏えいすることはありません。この安全性は、楕円曲線暗号が基盤とする「楕円曲線上の離散対数問題の計算困難性」によって保証されます。 楕円曲線暗号の仕組み 楕円軌道上に既知の基準点Gがあります。この楕円軌道上でGをn回加算する(n倍)すると、2G、3G、…と楕円軌道上を進みます。図の2G~6Gがそれにあたり、2周目以降も楕円軌道上のどこかに位置します(7G以降も存在)。 楕円軌道 秘密鍵a(自然数)を決めGをa回加算した位置をAとすると、Aは楕円軌道上に存在します。このとき A = aG と表すことができ、Aが公開鍵になります。 a(秘密鍵)からA(公開鍵)は簡単に求めることができますが、A(公開鍵)からa(秘密鍵)を求める逆算( a = A/G )は非常に難しく、総当たり以外に効率的にaを見つける方法が知られていません。 この「逆算の難しさ」が楕円曲線暗号の安全性の根拠です。 楕円曲線暗号を利用した鍵交換 送信者αさんと、受信者βさんが鍵交換を行う手順を説明します。ここで交換する「鍵」とは、トラフィック鍵のもとになる値です。 ①基準点Gの決定 αさんとβさんは基準点Gを共有します。(実際にはプロトコルとしてGがあらかじめ決まっており、お互いGを知っています) ①基準点Gの決定 ②秘密鍵と公開鍵のペアを生成 楕円曲線暗号を使ってそれぞれ一時的な秘密鍵と公開鍵のペアを生成します。具体的には次の手順です。 αさんは秘密鍵aを決定します。aとGから公開鍵Aを生成します( A = aG )。 βさんは秘密鍵bを決定します。bとGから公開鍵Bを生成します( B = bG )。 ②秘密鍵と公開鍵のペアを生成 ③公開鍵の送信 αさんは自身の公開鍵Aをβさんに送信します。同様に、βさんは自身の公開鍵Bをαさんに送信します。 ③公開鍵の送信 ④共通の値Kを算出 αさんは受信したBと自身の秘密鍵aを掛け算し、Kを求めます。K = aB = a(bG) = abGです。 同様にβさんは受信したAと自身の秘密鍵を掛け算し、Kを求めます。K = Ab = (aG)b = abGです。 ④共通の値Kを算出 この計算によって双方が同じ値Kを算出でき、結果としてKを共有できます。このKをもとに、トラフィック鍵を生成します。 仮に第三者がこの鍵交換の通信(③)を盗聴しAまたはBを入手したとしても、Kを計算することはできません。前述の通り、公開鍵(AやB)から秘密鍵(aやb)を逆算することが難しいからです。 まとめ ECDHEの仕組みをざっくりとしたイメージとして解説しました。厳密な解説ではない点はご容赦ください。 通信相手と同じ値を算出できる仕組みを初めて理解した際は、そのシンプルさに驚いたものです。ブラウザでリンク先を気軽にクリックする度に、このような鍵交換が行われていることを思い出していただければ幸いです。 補足 直感的に理解いただけるよう楕円を利用して解説しましたが、楕円曲線と楕円は本質的に異なるものです。実際に利用される楕円曲線( y 2 = x 3 + ax + b )は閉じない曲線です(「Ω」に似た形状で https://ja.wikipedia.org/wiki/%E6%A5%95%E5%86%86%E6%9B%B2%E7%B7%9A#/media/%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB:ECClines-3.svg の右側の図です)。 曲線を用いた解説のため実数をイメージされるかもしれませんが、実際には自然数による離散的な値を利用するのでマス目上の点の集合です。具体的なイメージは https://graui.de/code/elliptic2/ で確認できます。G、nG、A、Bがこのマス目上の点にあたります。 G、2G、3G、…、と等間隔で楕円軌道上の位置が変化するような解説を行いましたが、実際の楕円曲線上では等間隔ではありません。 執筆者  平田賀一(NTTビジネスソリューションズ(株)バリューデザイン部 システム開発部門) PaaS/SaaSの開発・運用、社内案件のコンサル、エンジニア育成、NTT WEST Engineers' Blog運営などに携わっています。 技術士(情報工学部門)/CISSP/情報処理安全確保支援士 参考資料・出典 本記事を執筆するにあたり、以下のサイトを参考にしました。 ja.wikipedia.org gaiax-blockchain.com qiita.com graui.de
はじめに NTTビジネスソリューションズの山本です。 本記事では、Google Gemini 2.5 ProやGoogle Gemini 2.5 Flash Image(別名Nano Banana)におけるトークンと課金の考え方について学んだ内容を紹介します。 本記事は2025年10月時点の情報に基づきます。 対象読者 本記事が想定する対象読者は以下の通りです。 生成AIに興味を持っている人 生成AIにおけるトークンについて知りたい人 Google Gemini CLIとNano Bananaを使っている人 背景・目的 Google for Developersのブログで「最先端の画像処理モデル Gemini 2.5 Flash Image のご紹介」の記事が公開されており、興味を持ちました。 最先端の画像処理モデル Gemini 2.5 Flash Image のご紹介 - Google Developers Blog ちょうど、Google for Developersのコミュニティイベントが開催される直前で申し込みをし、PoC環境を構築しました。 その後無料試用期間が終了し、有料に替わるタイミングで、課金の概念(トークン)の理解を深めたいと考えました。 Google Gemini CLIの使用方法 前提条件・動作環境 Node.jsがインストールされていること。 今回はWindows環境上でWSL+VS Codeを使用します。筆者の環境は次の通りです。 ホストOS: Windows 11 Pro 25H2 使用したディストリビューション: Ubuntu 24.04.3 LTS VS Codeのバージョン: 1.105.1 Googleアカウントは個人名義で問題ありません。ただし、今回の検証を実施すると料金が発生します。その点ご留意下さい。 Node.jsがインストールされたら以下のコマンドでGemini CLIをインストールします。  # npm install -g @google/gemini-cli 以下のコマンドを利用し、Gemini CLIを起動します。  # gemini 認証 認証方法は、下記の3パターンあります。 Googleで認証 Gemini API Keyで認証 Vertex AIで認証 今回はGEMINI_API_KEYで認証しました。APIキーの取得方法は、 Gemini API キーを使用する  |  Google AI for Developers を参照してください。 Gemini CLIの使用 プロンプトを打ってみる:今日の大阪の天気は?->Google検索を利用します。 図1:Gemini CLIにプロンプトを入力 Geminiからの回答が表示される。 図2:Geminiからの回答を表示 終了する際は、Ctrl+Cキーを2回押してください。 トークンの確認 ここからトークンについて学んでいきます。詳細はこちらをご確認ください。 トークンを理解してカウントする  |  Gemini API  |  Google AI for Developers Gemini や他の生成 AI モデルは、トークンと呼ばれる粒度で入力と出力を処理します。 Gemini モデルの場合、1 個のトークンは約 4 文字に相当します。100 個のトークンは、約 60 ~ 80 ワード(英語)に相当します。 トークンは、z などの単一の文字、cat などの単語全体にすることができます。長い単語は複数のトークンに分割されます。モデルで使用されるすべてのトークンのセットを語彙と呼び、テキストをトークンに分割するプロセスをトークン化と呼びます。 課金が有効になっている場合、Gemini API の呼び出し費用は、入力トークンと出力トークンの数によって決まります。そのため、トークンのカウント方法を知っておくと便利です。 トークンについては、Colabの環境で対話型で学習することができます。 Google Colab 図3:トークン数を確認 プロンプトのトークン数は、7つと確認することができました。あとは Gemini 側で処理をし、結果を出力するだけです。 ここまで来て気になることを思い出しました! Geminiは質問を受け取ったあと、Google検索を使用して内容を調査し、確認してから回答していました。 ひょっとすると、この思考の過程もトークンとしてカウントしているのでは?と考えました。 Gemini モデルのトークン数をカウントする  |  Firebase AI Logic をもとに、Gemini モデルのトークン数をカウントする python スクリプトを作成します。 import google.generativeai as genai # APIキーを設定 genai.configure(api_key="YOUR_API_KEY") def count_tokens(prompt_text, model_name="gemini-2.5-pro"): """トークン数をカウントして詳細を出力""" model = genai.GenerativeModel(model_name) # トークン数をカウント token_count = model.count_tokens(prompt_text) # 結果を出力 print(f"prompt_token_counts: {token_count.total_tokens}") # レスポンス生成してトークン数を取得 response = model.generate_content(prompt_text) print(f"candidates_token_count: {response.usage_metadata.candidates_token_count}") print(f"prompt_token_count: {response.usage_metadata.prompt_token_count}") print(f"total_token_count: {response.usage_metadata.total_token_count}") return response # 使用例 if __name__ == "__main__": prompt = "今日の大阪の天気を教えて?" count_tokens(prompt) 図4:実行結果 トークンをカウントするオプション Gemini API の入力と出力はすべてトークン化されます。トークンのカウント方法には次のオプションがあります。 prompt_token_count: 入力のみのトークン数 candidates_token_count: 出力のトークン数(思考トークンは含まれません) total_token_count: 入力と出力の両方のトークンの合計数(思考トークンを含む) 上記のオプションについては、次の点に注意してください。 入力トークン数には、プロンプト(テキストと入力ファイル)だけでなく、システム指示とツールも含まれます。 出力トークン数には思考トークンは含まれません。思考トークンは別のフィールドで提供されます。 トークンの考え方について詳細調査 Google AI Studio では確認できなかったのですが、Vertex AI Studio でトークンの考え方イメージを視覚的に確認することができました。 プロンプト入力時のトークン数、処理後のトークン数がわかります。 図5:Vertex AI Studio 返答完了後、 381個のトークン と表示されています。Vertex AIも料金が発生します。検証される場合は、ご留意下さい。 まとめ トークンの考え方やカウント方法について理解を深めることができました。トークンの扱いはモデルによって異なり、特に料金に直結する要素であるため、継続的に情報をアップデートしながら学習する必要があると感じています。 今回のPoCでは従量課金でAPIを利用しましたが、実際のシステム導入時には、利用状況や予算に応じたコスト制御の仕組みを検討することが重要であると再認識しました。 以下は、チャットでのPoC実施時の請求結果です。 SKU サービス 使用料 使用費用 Generate content output token count Gemini 2.5 Pro short output text Gemini API 7,398 count ¥11 Generate content input token count Gemini 2.5 Pro short input text Gemini API 18,943 count ¥4 Generate content cached input token count gemini 2.5 pro short input Gemini API 32,442 count ¥1 執筆者 山本 寛(NTTビジネスソリューションズ エンタープライズビジネス営業部所属) 現在はMicrosoft 365やGoogle Workspaceを活用した設計、構築案件に携わっています。 技術士(情報工学部門)、PMI認定PMPなど取得。 参考資料・出典 最先端の画像処理モデル Gemini 2.5 Flash Image のご紹介 - Google Developers Blog Gemini API キーを使用する  |  Google AI for Developers トークンを理解してカウントする  |  Gemini API  |  Google AI for Developers Google Colab Gemini モデルのトークン数をカウントする  |  Firebase AI Logic 商標  「Google」「Gemini」「Vertex AI」「Google Workspace」は、Google LLCまたはその関連会社の商標もしくは登録商標です。 「Windows」「VS Code」「Microsoft 365」は、米国Microsoft Corporationの米国およびその他の国における商標もしくは登録商標です。 「PMI」「PMP」は 、米国Project Management Instituteの商標もしくは登録商標です。 「Node.js」は 、Joyent, Inc.の商標もしくは登録商標です。 「Python」は、Python Software Foundationの商標もしくは登録商標です。
はじめに NTT西日本エンタープライズビジネス営業部の吉田泰隆です。 本記事ではユーザ認証に用いられるRADIUSサーバ・クライアントをAWS上に構築し、CloudWatchによるアクセスログの可視化について紹介します。 本記事は2025年9月時点の情報に基づきます。 対象読者 本記事が想定する対象読者は以下の通りです。 AWSやネットワーク認証システムに興味を持っている人 AWS環境でサーバー構築経験を積みたい人 RADIUSサーバーの導入・設定方法を学びたい人 CloudWatchを使ったログ監視・可視化を実装したい人 背景・目的 担当案件でRADIUSサーバーを構築することになりました。その際、ドキュメントや資料を読んだだけでは、認証の仕組みや各設定のつながりが腑に落ちず、深く理解するためには実際に手を動かすしかないと感じました。 本記事は、RADIUSサーバーの構築手順を丁寧に解説するハンズオンです。私が構築中につまずいたポイントや、理解を深めるための補足情報も盛り込んでいます。この記事を通して、読者の皆さんがRADIUSの仕組みを実践的に学び、今後の業務に役立てていただければ幸いです。 全体構成図 同じ VPC 内に RADIUS サーバーとクライアントを配置し、クライアントからサーバーへ認証リクエストを送信するシンプルな構成です。 構築手順 ステップ1: AWS環境の準備 まず、サーバーとクライアントとして利用する2台のEC2インスタンスを準備します。 以下の設定で2台のEC2インスタンスを作成します。 設定項目 値 補足 名前 RADIUS-Server と RADIUS-Client それぞれの役割が分かるように命名します。 AMI Amazon Linux 2023 - インスタンスタイプ t2.micro デモ用途には十分なスペックです。 ネットワーク 同じVPC、同じパブリックサブネット 2台のインスタンスが相互に通信できるようにします。 パブリックIPの自動割り当て 有効化 SSH接続用 次にRADIUS-SG という名前で新しいセキュリティグループを作成し、2台のインスタンスにアタッチします。以下のインバウンドルールを設定してください。 タイプ プロトコル ポート範囲 ソース 説明 SSH TCP 22 マイIP(コンソールにアクセスしているユーザーのパブリックIPアドレス) ユーザからのSSH接続 カスタムUDP UDP 1812 RADIUS-SG のID RADIUS認証通信 カスタムUDP UDP 1813 RADIUS-SG のID RADIUSアカウンティング通信 プライベートIPアドレスの確認 後ほどの設定で利用するため、作成した2台のインスタンスのプライベートIPアドレスを控えておきます。 ステップ2: RADIUSサーバーの構築 1. RADIUS-ServerインスタンスへのSSH接続 以下2種類の方法でRADIUS-Serverへ接続します。 ・EC2 Instance Connect ・SSH クライアント ※手順はコマンドともにコンソールに記載されておりますので、そちら(下記画像)をご参照ください。 2. FreeRADIUSのインストール FreeRADIUS をインストール・設定します。 sudo dnf update -y sudo dnf install -y freeradius freeradius-utils タイムゾーンを日本時間 (Asia/Tokyo) に設定します。 sudo timedatectl set-timezone Asia/Tokyo 3. クライアント情報の登録 (clients.conf) RADIUS サーバーがどのクライアントからのリクエストを受け付けるかを設定します。 sudo vi /etc/raddb/clients.conf を開き、ファイルの末尾に RADIUS-Client の情報を追記します。 <RADIUS-ClientのプライベートIP> は控えておいたIPアドレスに置き換えてください。 # /etc/raddb/clients.conf # (...ファイルのもともとの内容...) # 自前のRADIUSクライアントを追加 client radius_client { ipaddr = <RADIUS-ClientのプライベートIP> secret = hands-on # サーバーとクライアント間の合い言葉 } この secret (共有シークレット) は非常に重要です。 !注意!本記事では構成を理解する目的で簡単化のため平文でパスワードを使用しています。実運用では絶対に使わないでください。 4. ユーザー情報の登録 ( users ) 認証に利用するユーザーを登録します。 sudo vi /etc/raddb/users を開き、ファイルの先頭にテストユーザーの情報を追記します。 # /etc/raddb/users # テストユーザーを追加 (ユーザー名: testuser, パスワード: testpassword) testuser Cleartext-Password := "testpassword" # 複数人登録する場合は同様に追記する hanako.yamada Cleartext-Password := "P@ssword_Yamada123" taro.suzuki Cleartext-Password := "P@ssword_Suzuki456" # (...ファイルのもともとの内容...) ステップ3: EAP無効化 FreeRADIUS は、インストール直後の状態では高度な認証方式 (EAP) が有効になっています。しかし、これらの機能はSSL/TLS証明書などを必要とするため、シンプルなID/パスワード認証を行う際には、これが原因で起動エラーが発生します。 今回のデモでは、より簡単にするためにあらかじめEAP(Extensible Authentication Protocol, 拡張認証プロトコル)を無効化しておきます。 ※EAP:IEEE 802.1X認証フレームワークの1つ。ユーザーID/パスワードや電子証明書を用いた多様な認証方式(EAP-TLS、EAP-PEAPなど)を柔軟に利用できるようにする仕組み。 !注意!本記事では構成を理解する目的で簡単化のためEAPを無効化しています。盗聴・中間者攻撃のリスク増大のため、実運用では絶対に使わないでください。 1. eap モジュールを無効化 EAP はセキュアな認証方式ですが、証明書がないと起動に失敗します。以下のコマンドで無効化します。 sudo rm /etc/raddb/mods-enabled/eap 2 inner-tunnel サイトを無効化 inner-tunnel は EAP のトンネル処理で使われる設定ですが、今回は不要なので無効化します。 sudo rm /etc/raddb/sites-enabled/inner-tunnel 3. default サイトの修正 モジュールを無効化しても、メインの設定ファイル ( `default` ) からの呼び出しが残っているため、それらもコメントアウトします。まず、下記コマンドで設定ファイルを開きます。 sudo vi /etc/raddb/sites-enabled/default その後、2箇所修正します。 authorize セクションの修正(419行目) ※eapだけでなく、{ }の部分もコメントアウトすることを忘れないでください。起動時に構文エラーとなります。 # 編集前 authorize { ... eap { ok = return # updated = return } } # 編集後 authorize { ... #eap { # ok = return # updated = return #} } authenticate セクションの修正(603行目) # 編集前 authenticate { ... eap ... } # 編集後 authenticate { ... # eap ... } Tips:編集する行を409, 603行目と記載しましたが、見つからない場合は以下のコマンドをお試しください。編集すべき行数を知ることができます。 sudo grep -n '^\s*eap' /etc/raddb/sites-enabled/default これで、シンプルなPAP認証(ID/パスワード認証)に必要な設定だけが残った状態になりました。 ステップ4: サーバーの起動とクライアントの準備 1. FreeRADIUSサービスの起動 RADIUS-Server で以下のコマンドを実行し、サービスを起動・自動起動設定します。 sudo systemctl start radiusd sudo systemctl enable radiusd 以下のコマンドで active (running) となっていれば成功です。 [ec2-user@ip-10-0-14-102 ~]# sudo systemctl status radiusd ● radiusd.service - FreeRADIUS high performance RADIUS server. Loaded: loaded (/usr/lib/systemd/system/radiusd.service; enabled; preset: disabled) Active: active (running) since Sun 2025-06-22 11:29:19 UTC; 12s ago Main PID: 31373 (radiusd) Tasks: 6 (limit: 1111) Memory: 40.5M CPU: 80ms CGroup: /system.slice/radiusd.service └─31373 /usr/sbin/radiusd -d /etc/raddb 2. クライアントツールのインストール RADIUS-Client インスタンスに SSH で接続し、テストツールをインストールします。 sudo dnf update -y sudo dnf install -y freeradius-utils ステップ5: 認証テスト RADIUS-Client から radtest コマンドを使い、認証テストを実行します。 1. 認証成功テスト 正しい共有シークレット ( hands-on ) を使ってテストします。 radtest testuser testpassword <RADIUS-ServerのプライベートIP>:1812 0 hands-on 以下のように Received Access-Accept と返ってくれば認証成功です! Sent Access-Request Id 95 from 0.0.0.0:55186 to 10.0.14.102:1812 length 78 User-Name = "testuser" User-Password = "testpassword" NAS-IP-Address = 10.0.8.100 NAS-Port = 0 Message-Authenticator = 0x00 Cleartext-Password = "testpassword" Received Access-Accept Id 95 from 10.0.14.102:1812 to 10.0.8.100:55186 length 38 Message-Authenticator = 0xf224b42683d891fa7fcf3193349935ad 2. 認証失敗テスト (共有シークレット不一致) わざと間違った共有シークレット ( hands-off ) を使ってみましょう。 radtest testuser testpassword <RADIUS-ServerのプライベートIP>:1812 0 hands-off 今度はサーバーから何の応答もなく、最終的にタイムアウトエラーになります。 Sent Access-Request Id 27 from 0.0.0.0:56334 to 10.0.14.102:1812 length 78 User-Name = "testuser" User-Password = "testpassword" NAS-IP-Address = 10.0.8.100 NAS-Port = 0 Message-Authenticator = 0x00 Cleartext-Password = "testpassword" Sent Access-Request Id 27 from 0.0.0.0:56334 to 10.0.14.102:1812 length 78 User-Name = "testuser" User-Password = "testpassword" NAS-IP-Address = 10.0.8.100 NAS-Port = 0 Message-Authenticator = 0x00 Cleartext-Password = "testpassword" Sent Access-Request Id 27 from 0.0.0.0:56334 to 10.0.14.102:1812 length 78 User-Name = "testuser" User-Password = "testpassword" NAS-IP-Address = 10.0.8.100 NAS-Port = 0 Message-Authenticator = 0x00 Cleartext-Password = "testpassword" (0) No reply from server for ID 27 socket 3. 登録されたクライアントからでも共有シークレットが違う場合、サーバーは不正なリクエストとみなし、パケットを破棄します。 【発展】AWSサービスのワンポイント:認証ログの可視化 ステップ6: FreeRADIUSの設定ファイル radiusd.conf を編集 設定ファイルをテキストエディタで開きます。 sudo vi /etc/raddb/radiusd.conf log セクション内の auth の設定(348行目)をnoからyesへ変更します。 #編集前 # Log all (accept and reject) authentication results to the log file. # # This is the same as setting "auth_accept = yes" and # "auth_reject = yes" # # allowed values: {no, yes} # auth = no #編集後 # Log all (accept and reject) authentication results to the log file. # # This is the same as setting "auth_accept = yes" and # "auth_reject = yes" # # allowed values: {no, yes} # auth = yes デフォルトの設定では取得できなかった成功時のログも吐き出し可能となりました。 変更を反映させるために、RADIUSサーバを再起動させてください。 sudo systemctl restart radiusd 再起動後、サービスが正常に稼働しているか確認します。 active (running) と表示されていれば、正常に再起動されています。 sudo systemctl status radiusd ステップ7: CloudWatch Agentのインストールと設定 1. IAMロールのアタッチ RADIUS-Server のEC2インスタンスに、CloudWatch Agentがログを送信するための権限が必要です。   1-1. IAMコンソールで新しいロールを作成します。   1-2. 信頼されたエンティティタイプ: AWSのサービス   1-3. ユースケース: EC2   1-4. 許可ポリシーとして CloudWatchAgentServerPolicy をアタッチします。   1-5. ロール名(例: EC2-CloudWatchAgent-Role )を付けて作成します。   1-6. EC2ダッシュボードに戻り、 RADIUS-Server インスタンスにこのIAMロールをアタッチします。 2. CloudWatch Agentのインストール RADIUS-Server にSSHで接続し、以下のコマンドでAgentをインストールします。 sudo dnf install -y amazon-cloudwatch-agent 3. Agent設定ファイルの作成 どのログファイルをCloudWatchに送信するかを定義する設定ファイルを作成します。FreeRADIUSは認証結果を /var/log/radius/radius.log に出力するので、これを対象とします。 sudo vi /opt/aws/amazon-cloudwatch-agent/etc/amazon-cloudwatch-agent.json を実行し、以下の内容を貼り付けます。 { "agent": { "metrics_collection_interval": 60, "run_as_user": "root", "debug": true }, "logs": { "logs_collected": { "files": { "collect_list": [ { "file_path": "/var/log/radius/radius.log", "log_group_class": "STANDARD", "log_group_name": "/aws/ec2/freeradius-logs", "log_stream_name": "{instance_id}", "retention_in_days": 7, "timestamp_format": "%a %b %d %H:%M:%S %Y", "timezone": "LOCAL" } ] } } }, "metrics": { "aggregation_dimensions": [ [ "InstanceId" ] ], "append_dimensions": { "AutoScalingGroupName": "${aws:AutoScalingGroupName}", "ImageId": "${aws:ImageId}", "InstanceId": "${aws:InstanceId}", "InstanceType": "${aws:InstanceType}" }, "metrics_collected": { "disk": { "measurement": [ "used_percent" ], "metrics_collection_interval": 60, "resources": [ "*" ] }, "mem": { "measurement": [ "mem_used_percent" ], "metrics_collection_interval": 60 }, "statsd": { "metrics_aggregation_interval": 60, "metrics_collection_interval": 10, "service_address": ":8125" } } } } log_group_name : CloudWatch Logs内でログを格納するグループ名です。分かりやすい名前をつけましょう。 参考までに上記jsonは以下の内容となっています。変更したいパラメータ等あれば、自由に調整してください。 CloudWatch Agent パラメータ設定 エージェント共通 (agent) パラメータ 設定値 説明 run_as_user root エージェントを実行するユーザー。rootで実行することでファイルアクセス権限の問題を回避します。 metrics_collection_interval 60 (デフォルト値) メトリクスを収集する基本間隔(秒)。 debug TRUE デバッグモードを有効化。詳細な動作ログが出力され、トラブルシューティングに役立ちます。本番環境では false を推奨します。 ログ収集 (logs) パラメータ 設定値 説明 file_path /var/log/radius/radius.log 収集対象のログファイルへのフルパス。 log_group_name /aws/ec2/freeradius-logs ログを格納するCloudWatch Logsのロググループ名。 log_stream_name {instance_id} ロググループ内のログストリーム名。 {instance_id} とすることで、実行したEC2インスタンスのIDが自動的に設定されます。 retention_in_days 7 CloudWatch Logsでのログ保持期間(日数)。7日経過後に自動で削除されます。 timestamp_format %a %b %d %H:%M:%S %Y ログファイル内のタイムスタンプを解釈するための書式。 timezone LOCAL ログのタイムスタンプに使用するタイムゾーン。LOCALはEC2インスタンスのOS設定に従います。 log_group_class STANDARD ロググループのストレージクラス。標準のアクセス頻度に適しています。 メトリクス共通 (metrics) パラメータ 設定値 説明 aggregation_dimensions InstanceId 収集したメトリクスをInstanceId単位で集約します。 append_dimensions.AutoScalingGroupName ${aws:AutoScalingGroupName} 全てのメトリクスにAuto Scalingグループ名のディメンション(タグ)を付与します。 append_dimensions.ImageId ${aws:ImageId} 全てのメトリクスにAMIのIDのディメンション(タグ)を付与します。 append_dimensions.InstanceId ${aws:InstanceId} 全てのメトリクスにインスタンスIDのディメンション(タグ)を付与します。 append_dimensions.InstanceType ${aws:InstanceType} 全てのメトリクスにインスタンスタイプのディメンション(タグ)を付与します。 収集メトリクス (ディスク・メモリ) パラメータ 設定値 説明 measurement used_percent 収集するディスクの指標。ディスク使用率(%)を収集します。 resources * 収集対象のリソース。 * は全てのマウント済みディスクパーティションを意味します。 metrics_collection_interval 60 このメトリクスの収集間隔(秒)。 measurement mem_used_percent 収集するメモリの指標。メモリ使用率(%)を収集します。 metrics_collection_interval 60 このメトリクスの収集間隔(秒)。 収集メトリクス (StatsD) パラメータ 設定値 説明 service_address :8125 アプリケーションからカスタムメトリクスを受け付けるStatsDリスナーのアドレスとポート。 metrics_collection_interval 10 StatsDプロトコルでデータを受け付ける間隔(秒)。 metrics_aggregation_interval 60 受け付けたデータを集約し、CloudWatchへ送信する間隔(秒)。 4. CloudWatch Agentの起動 以下のコマンドで設定ファイルを読み込み、Agentを起動します。 sudo /opt/aws/amazon-cloudwatch-agent/bin/amazon-cloudwatch-agent-ctl -a fetch-config -m ec2 -c file:/opt/aws/amazon-cloudwatch-agent/etc/amazon-cloudwatch-agent.json -s これで、 RADIUS-Server で認証が発生するたびに、そのログが自動でCloudWatch Logsに送信されるようになります。 左がCloudWatchエージェントが取得した情報で、右側がRADIUSサーバ内の radius.log  です。少し見にくいですが、きちんとログを収集できることがわかります。 ステップ8: CloudWatch Logs Insightsでのログ分析 radtest コマンドで何度か認証を成功・失敗させてログを生成した後、AWSコンソールのCloudWatch画面を開きます。 左側のメニューから「ログ」>「Logs Insights」を選択します。 「ロググループを選択」で、先ほど設定した RadiusServer/radius.log を選びます。 クエリエディタに、SQLライクなクエリを入力してログを分析できます。 クエリ 最新の認証ログ取得 fields @timestamp, @message | sort by @timestamp desc | limit 10 認証成功(Access-Accept)と失敗(Access-Reject)の件数を集計 fields @timestamp, @message | filter @message like /Login OK/ or @message like /error/ | stats count(*) as event_count by if(@message like /Login OK/, 'Login OK', 'Error') as event_type | sort by event_type asc 認証数の推移 fields @timestamp, @message | filter @message like /Login OK/ or @message like /error/ | stats sum(if(@message like /Login OK/, 1, 0)) as LoginOK_Count, sum(if(@message like /error/, 1, 0)) as Error_Count by bin(1m) as interval | sort by interval asc ステップ9: CloudWatch Dashboardでの可視化 Logs Insightsのクエリ結果は、そのままダッシュボードのウィジェットとして追加できます。 Logs Insightsで上記のクエリを実行した後、「アクション」>「ダッシュボードに追加」をクリックします。 「新しいダッシュボードを作成」を選び、ダッシュボード名(例: RADIUS-Monitoring )を入力します。 ウィジェットの種類(折れ線グラフ、円グラフ、数値など)を選択し、「ダッシュボードに追加」をクリックします。 これを繰り返すことで、以下のようなウィジェットを持つダッシュボードを作成できます。 みなさんもお好きなメトリクスを収集して、オリジナルを作ってみてください。 まとめ 今回は AWS 環境で RADIUS サーバーを構築し、認証テストを行うまでの一連の流れを解説しました。 ぜひ、みなさんもトライしてみてください。 執筆者 吉田 泰隆(NTT西日本 エンタープライズビジネス営業部所属) 好きなAWSサービス:Route53 所有資格:AWS Certified Solutions Architect – Professional 参考資料・出典 本記事を執筆するにあたり、以下のサイトを参考にしました。 qiita.com qiita.com https://www.hcnet.co.jp/column/detail23.html https://www.infraexpert.com/study/wireless14.html 商標 「AWS」は、Amazon Web Services,Inc.またはその関連会社の商標もしくは登録商標です。
1. はじめに 2. 対象読者 3. 背景・目的 4. 用語の解説 ◆ MCPとは? ◆ AWS Documentation MCP Serverとは? 5. 動作環境・前提条件 6. Windows環境での設定手順 ◆ Step 1: 必要なツールのインストール ◆ Step 2: Claude Desktop設定ファイルへのアクセス ◆ Step 3: Claude Desktopの設定 ◆ Step 4: Claude Desktopの再起動 ◆ Step 5: AWS Documentation MCP Serverの起動確認 7. 動作確認 ◆ ①AWS Documentation MCP Serverを無効にして質問 ◆ ②AWS Documentation MCP Serverを有効にして質問 8. まとめ 執筆者 商標 免責事項 1. はじめに こんにちは。NTT西日本の三浦です。 皆さまは、「特定のAWSサービスの情報を調べたいけど、適したAWS公式ドキュメントがすぐに見つからない...!」といったお悩みはありませんでしょうか? AWS公式ドキュメントの数は膨大な量になるので、その中からピンポイントに必要な情報を見つけることは大変です。 さらに、見つけた情報が最新かどうかの確認や、複数のドキュメントを横断した調査には多くの時間がかかってしまいます。 本記事では、そういった悩みを解決するアプローチとして、AWS Documentation MCP Serverをご紹介します。 生成AIとAWS Documentation MCP Serverを連携させることで、AWS公式ドキュメントの検索・参照が自動化され、従来の問い合わせ対応が劇的に効率化されます。 2. 対象読者 本記事が想定する対象読者は以下の通りです。 AWS公式ドキュメントへの効率的なアクセス方法を求めている人 MCPについて知りたい人 CCoE担当者や、または日常的にAWSなどの技術的な問合せを受けている人 3. 背景・目的 私は担当の業務として、日々多くのAWSの技術的な問い合わせを受けています。 「技術検証を行っているが、IAM権限エラーが出て困っている」「こんなイメージでネットワーク接続を実現したいが、設定方法がわからない」といった質問に対して、迅速かつ正確な回答を提供する必要があります。 従来はブラウザでAWS公式ドキュメント等を検索しながら回答していましたが、この方法では次の課題がありました。 膨大な情報の中から、ピンポイントに適した情報(特に、信頼性のある公式ドキュメントの情報)を見つけることが大変 見つけた情報を一つ一つ確認して、それが回答として適した情報かの解釈に30分~1時間程度の時間がかかる 質問者への回答作成に時間がかかる そこで、Model Context Protocol(MCP)を活用したClaude DesktopとAWS Documentation MCP Serverの連携を試したところ、問い合わせ対応の効率が改善されました。 この経験を共有し、同じような課題を抱える方々の参考になればと思い記事にしました。 4. 用語の解説 そもそも「MCPって何?」という方へ向けて、本記事で登場する重要な用語について解説します。 ◆ MCPとは? Model Context Protocol (MCP) とは、Anthropic社が2024年11月にオープンソース化した、生成AIが外部のデータやツールと連携するための新しい標準規格のことです。 www.anthropic.com 従来はAIアプリケーションから外部のデータやツールにアクセスするには、個別にカスタマイズする必要がありました。 これらの連携方法をMCPによって標準化することで、AIアプリケーションから様々なデータやツールと簡単に接続できるようになります。 ◆ AWS Documentation MCP Serverとは? AWS Documentation MCP Server とは、生成AIがAWSの公式ドキュメントにアクセスするためのMCPに対応したツールのことです。 github.com AWS Documentation MCP Serverは、主に次の機能を提供します。 ドキュメント読み取り:AWS公式ドキュメントをMarkdown形式で取得 ドキュメント検索:公式検索APIを使用したAWS公式ドキュメントの検索 関連ページ推奨:AWS公式ドキュメントに関連する推奨のページを取得 AWS Documentation MCP Serverの実態は、公式検索APIやドキュメント取得用のAPI等に対して問い合わせを行うラッパーサーバーです。 生成AIからドキュメント検索用に用意されたAPIを利用する際の橋渡しのような役割を担っています。 5. 動作環境・前提条件 AWS Documentation MCP Serverを利用するには、MCPクライアントとなる生成AIが必要です。 本記事では、例としてWindows版のClaude Desktopを利用して、AWS Documentation MCP Serverを利用するための設定手順を紹介します。 動作環境は次の通りです。 システム要件 OS:Windows 11 Claude Desktop バージョン:Windows版の最新バージョン(推奨) インストールがまだの方は、 公式サイト からダウンロードおよびインストール、ログインまで実施してください なお、本記事の構成は無償版のClaude Desktopでも動作します。 6. Windows環境での設定手順 実際にWindows環境で検証した結果を基に、手順を説明します。 手順はAWS Documentation MCP Serverの ドキュメント をベースに記載しておりますが、皆さまの環境によっては一部の手順が異なる場合があることにご注意ください。 ◆ Step 1: 必要なツールのインストール AWS Documentation MCP Serverの利用に必要な環境をインストールします。 コマンドプロンプトを開いて以下のコマンドを実行します。 実行後しばらく待つとインストールが完了します。 powershell -c "irm https://astral.sh/uv/install.ps1 | iex" インストールができたら、uv が適切にインストールされているか確認します。 uv --version 次に、Python 3.10以降がインストールされているか確認します。 python --version もしもPythonがインストールされていなければ、以下コマンドを実行してPython 3.10(またはより新しいバージョン)をインストールします。 uv python install 3.10 ◆ Step 2: Claude Desktop設定ファイルへのアクセス Windows環境でのClaude Desktopの設定ファイルを開きます。 設定ファイルへのアクセス方法: メニューもしくは画面左下のアイコンから、「設定」をクリックして設定メニューを表示する 設定メニューにて「開発者」、「設定を編集」の順にクリック 表示された「claude_desktop_config.json」を任意のエディタで開く ◆ Step 3: Claude Desktopの設定 claude_desktop_config.jsonファイルに以下のテキストを貼り付けて保存します。 { " mcpServers ": { " awslabs.aws-documentation-mcp-server ": { " disabled ": false , " timeout ": 60 , " type ": " stdio ", " command ": " uv ", " args ": [ " tool ", " run ", " --from ", " awslabs.aws-documentation-mcp-server@latest ", " awslabs.aws-documentation-mcp-server " ] , " env ": { " FASTMCP_LOG_LEVEL ": " ERROR ", " AWS_DOCUMENTATION_PARTITION ": " aws " } } } } 注意: JSONファイルの構文エラーがあるとClaude Desktopが正常に起動しません 編集前に設定ファイルのバックアップを取ることをお勧めします 他のMCPサーバーを既に設定している場合は、インデントやカンマの位置にご注意ください ◆ Step 4: Claude Desktopの再起動 設定ファイル保存後、Claude Desktopを再起動します。 Claude Desktopの左上のメニューから、[ファイル] > [終了] をクリックして終了します。 その後、改めてClaude Desktopを起動してください。 Claude Desktopの「✕ボタン」を押して閉じるだけでは再起動されないのでご注意ください。 ◆ Step 5: AWS Documentation MCP Serverの起動確認 Claude Desktop起動後エラーが表示されないことを確認します。 Claude Desktop画面左下の自身のアイコンから、[設定] > [開発者]の順に選択して、AWS Documentation MCP Serverのステータスが「running」になっていることを確認します。 新規チャットにてAWS Documentation MCP Serverが表示されていれば、設定は終わりです。 7. 動作確認 以下の質問で機能確認を行います。 精度の比較として、①AWS Documentation MCP Serverを無効にして質問した場合と、②AWS Documentation MCP Serverを有効にして質問した場合で対照実験を行います。 AWS Lambda SnapStartの対応ランタイムについて教えてください。 回答は対応ランタイムだけリストして答えてください。 なお、期待する回答は以下になります。 AWS Lambda SnapStartのPythonや.NETへの対応は2024年11月18日にリリースされた機能になるので、Claude Desktopの回答の精度に違いがでるかを検証します。 Java 11以降 Python 3.12以降 .NET 8以降 docs.aws.amazon.com ◆ ①AWS Documentation MCP Serverを無効にして質問 まずは、AWS Documentation MCP Serverを 無効にして 質問した結果を示します。 Claude Desktopが記憶している古い情報を元にした回答になっており、回答に誤りがあることがわかります。 AWS Lambda SnapStartの対応ランタイムとして、Javaしかリストされておらず、Pythonや.NETに関する記載はありません。 なお、回答内容はお手元の環境で実行した場合では異なる場合があります。 ◆ ②AWS Documentation MCP Serverを有効にして質問 次に、AWS Documentation MCP Serverを 有効にして 質問してみます。 実行時、「Claudeがこのツールを使用したいと思っています」とポップアップが表示された場合は、「一度だけ許可」もしくは「常に許可する」を選択してください。 ツール利用毎にClaudeからの確認が必要ないなら、「常に許可する」を選択してください。 AWS Documentation MCP Serverを利用して、公式ドキュメントを検索・参照します。 回答内容を確認すると、期待する回答と一致しており、最新の情報が取得できていることがわかります。 また、AWS Documentation MCP Serverのツールアクションの内容を確認すると、今回の質問に該当する公式ドキュメントを参照していることがわかります。 8. まとめ 今回の記事では、MCPの概要とAWS Documentation MCP Serverについて紹介いたしました。 CCoE担当者、テクニカルサポート、ソリューションアーキテクトなど、日常的にAWSドキュメントを参照する業務に従事する方に特に有効だと思います。 従来のブラウザ検索では、複数のAWSドキュメントページを手動で確認し、情報を横断的に確認する必要がありました。今回の動作確認は簡単なデモでしたが、実際の問い合わせ対応や技術調査では、AWS Documentation MCP Serverを活用することで以下の具体的な改善が実現できます。 検索精度の向上 曖昧な技術用語でも関連ドキュメントを包括的に抽出することができる 複数サービス間の依存関係も含めた情報収集が可能 作業時間の短縮 これまで30分程度かかっていたドキュメント調査が2~3分程度に短縮 情報品質の担保 AWS公式ドキュメントのみを参照するため、信頼性が高い AWS Documentation MCP Serverの他にも、AWS Labs では、 AWS MCP Collection としてAWS Knowledge MCP Server、AWS Pricing MCP Serverなどの様々な便利なMCPが提供されています。こちらに関しても今後ブログ記事を執筆していきたいと思います。 執筆者 三浦大輝 (NTT西日本 ビジネス営業本部 エンタープライズビジネス営業部所属) クラウドエンジニアとして、主にAWS導入プロジェクトや社内のクラウド人材育成を担当しています。 2024 Japan AWS Top Engineers 商標 Amazon Web Services、AWS、AWS Lambda、および本記事で言及されるその他のAWSサービス名は、Amazon.com, Inc.またはその関連会社の商標です。 Claude、Claude Desktop、およびAnthropic関連の名称は、Anthropic PBC の商標です。 Microsoft、Windows、Windows 11は、Microsoft Corporationの米国およびその他の国における登録商標または商標です。 Python は、Python Software Foundation の登録商標です。 その他、記載されている会社名、製品名は、各社の登録商標または商標です。 免責事項 本記事の内容は執筆時点(2025年9月)の情報に基づいており、サービスの仕様変更等により内容が変更される可能性があります。 本記事で紹介する設定手順や使用方法は、特定の環境での動作確認に基づくものであり、すべての環境での動作を保証するものではありません。 AWS Documentation MCP Server は AWS Labs によって提供されるオープンソースプロジェクトであり、AWSの公式サポート対象外です。 本記事では生成AIを活用した内容が含まれており、AIによる情報の生成過程でハルシネーション(事実に基づかない情報の生成)が発生する可能性があります。記載内容の正確性については、必ず公式ドキュメントや信頼できる情報源で検証してください。
はじめに NTT西日本の服部です。本記事はNTT WEST Engineers' Blog 開設にむけて投稿記事レビューのワークフローを爆速で構築した話の第6回の記事となります。 前回までの記事も読んでいただけるとありがたいです。 最終回の第6回となる本記事ではPower Automateによるレビューフロー後編として差戻による修正依頼と記事公開後の通知フローについてご紹介します。 本記事は2025年9月時点の情報に基づきます。 ①~概要編~ ②~Microsoft Forms/Microsoft Lists編~ ③~Power AutomateによるMicrosoft Listsへの自動登録編~ ④~Power Automateによるレビューフロー前編~ ⑤~Power Automateによるレビューフロー中編~ ⑥~Power Automateによるレビューフロー後編~ (本記事) 第1回の記事でご紹介したワークフローの全体像のうち、以下の図にあたる内容となります。 修正依頼フロー 投稿完了通知フロー 対象読者 本記事が想定する対象読者は以下の通りです。 自動化に興味がある人 繰り返しの定常的な作業に困っている人 Microsoft Forms/Microsoft Lists/Power Automateを使ってみたい人 背景 NTT WEST Engineers' Blog に向けて、ブログ記事のレビュープロセスを効率化したいという要望を受けて執筆者が検討・構築しました。 SaaSの新規サービスを導入する予算はありませんでしたが、幸い全社的にMicrosoft Forms、Microsoft Lists、Power Automateが利用できる環境だったため、これらを用いてブログ記事レビューのワークフローを構築しました。 本記事ではPower Automateを用いた1.差戻による修正依頼フローと2.記事公開後の通知フローについてご紹介します。 アダプティブカードについて 本記事でご紹介するフローにはアダプティブカードを使った処理が含まれています。 アダプティブカードの詳細については前回の記事で紹介しておりますのでぜひそちらの記事も読んでみてください。 1.修正依頼フロー 修正依頼フローの全体像は以下の通りです。 ここで冒頭でご紹介したフローのイメージ図ではレビュー結果通知および修正依頼から始まっているにも関わらず上記のフローでは アイテムが作成または変更されたとき から始まっている点が気になる方がいらっしゃるかもしれません。 元々構築したフローでは前回ご紹介したレビューフローと今回の修正依頼フローは一つのフローにまとめていたためイメージ図通りの処理内容でした。しかしブログ執筆にあたり分割したほうが読みやすい記事にできると判断しフローを二つに分けた結果、ここでは差分が発生しています。 以下で各ステップの詳細についてご紹介します。 1-1. アイテムが作成または変更されたとき このフローが実行されるトリガーです。 前回/前々回の記事でも紹介しましたがMicrosoft Listsにおける一行ごとのデータ(レコード)のことをアイテムといい、本記事においては1アイテム=1件分のレビュー依頼に相当します。 トリガーの条件として以下を指定しました。 @equals(triggerBody()['OData__x30b9__x30c6__x30fc__x30bf__x30/Value'],'差し戻し(修正待ち)') 上記は作成または更新されたアイテムのステータスが差し戻し(修正待ち)のときにこのフローが実行されることを意味しています。 前回ご紹介したレビューフローで差し戻しとなったときの処理としてステータスが 差し戻し(修正待ち) に更新されたことをトリガーとして本フローが実行されます。 トリガーの条件の書き方については第3回の記事で詳しく解説しているため、そちらを参照ください。 1-2. 変数を初期化する レビュアーコメントの一部を置換した内容をcommentという文字列変数に代入しています。 値の部分には以下の評価式が入っています。 replace(replace(triggerOutputs()?['body/OData__x30ec__x30d3__x30e5__x30fc__x30'],'"','”'),'\','¥') ここではレビュアーコメントの列の値について、半角のバックスラッシュ \ を全角の円マーク ¥ に置換するという処理と半角のダブルクォート " を全角のダブルクォート ” に置換するという処理を実行しています。 半角のダブルクォートやバックスラッシュが残っていると次のアダプティブカードの投稿処理でJSON形式が崩れることでエラーが発生してしまうため、それを回避するためにこのような処理を挟んでいます。 1-3. アダプティブ カードを投稿して応答を待機する(修正依頼) 投稿者宛に修正依頼のためのアダプティブカードを送る処理です。 省略されているメッセージ部分には以下のJSONが記載されています。 { " type ": " AdaptiveCard ", " body ": [ { " type ": " TextBlock ", " size ": " Medium ", " weight ": " Bolder ", " text ": " ブログ記事の修正依頼 " } , { " type ": " TextBlock ", " text ": " タイトル:@{triggerOutputs()?['body/Title']}の記事についてレビューの結果、差し戻しとなりました。 \n レビューコメントを参照して記事を修正してください。 \n\n レビューコメント: \n\n @{variables('comment')} ", " wrap ": true } , { " type ": " ActionSet ", " actions ": [ { " type ": " Action.OpenUrl ", " title ": " 下書きプレビューURL ", " url ": " @{triggerOutputs()?['body/OData__x4e0b__x66f8__x304d__x30d7__x30']} " } ] } , { " type ": " ActionSet ", " actions ": [ { " type ": " Action.Submit ", " title ": " 完了 ", " id ": " complete " } , { " type ": " Action.Submit ", " title ": " キャンセル ", " id ": " cancel " } ] , " horizontalAlignment ": " Center ", " spacing ": " Medium " } , { " type ": " TextBlock ", " text ": " ・完了:再度レビュー依頼をあげます。 \n ・キャンセル:投稿依頼を取り下げます。 ", " wrap ": true } ] , " $schema ": " http://adaptivecards.io/schemas/adaptive-card.json ", " version ": " 1.5 " } 上記のアダプティブカードが送信されるとMicrosoft TeamsでWorkflowsという対象から以下のようなメッセージがレビュアーの個人チャット宛に届きます。 このアダプティブカードの内容を参照して投稿者は記事の修正対応を実施し、再度レビュー依頼をあげるために完了をクリックするか、投稿依頼を取り下げるとしてキャンセルをクリックすることで次の処理に進めることができます。 こちらのアダプティブカードの処理はタイムアウトを7日間(P7D)に設定しています。 タイムアウト設定については前回の記事を参照ください。 1-4. スイッチ(修正対応の結果) アダプティブカードの結果によって処理が分岐します。 分岐処理の判定には以下の値を使用しています。 outputs('アダプティブ カードを投稿して応答を待機する(修正依頼)')?['body/submitActionId'] ここには直前に処理されたアダプティブカードでクリックされたボタンのIDが入ります。 つまりアダプティブカードのメッセージで定義された以下のボタンに割り当てられたIDである complete , cancel のいずれかが入ります。 " type ": " ActionSet ", " actions ": [ { " type ": " Action.Submit ", " title ": " 完了 ", " id ": " complete " } , { " type ": " Action.Submit ", " title ": " キャンセル ", " id ": " cancel " } ] , 1-4-1. ケース1(完了) アダプティブカードで完了がクリックされたときの処理です。 完了の場合はステータスをレビュー完了に変更する処理が実行されます。 ここの処理ではレビュアーの値は特に指定していないため、これまでに設定されたレビュアーの値が残ったままになっています。 これによって前回と同じレビュアー宛に再度レビュー依頼を送るフローが実行されます。 レビュー依頼のフローについては前回の記事を参照ください。 1-4-2. ケース2(キャンセル) アダプティブカードでキャンセルがクリックされたときの処理です。 キャンセルの場合はステータスを却下/消滅に変更する処理が実行されます。 ステータスが却下/消滅に変更された場合は他のフローは実行されないため、ここで処理が終了となります。 投稿者都合で修正対応をする時間が取れない場合等を想定しています。 1-5.項目の更新(タイムアウトに伴う消滅) アダプティブカードがタイムアウトしたときの処理です。 ここではレビュー依頼をクローズするためにステータスを 却下/消滅 に更新しています。 タイムアウト時の並列分岐の追加方法については前回の記事を参照ください。 2.記事公開後の通知フロー 事務局によって記事が公開された後、事務局の担当者はリストのステータスを投稿完了に手動で変更します。 ステータスが投稿完了になったことをトリガーとして投稿者に通知を送るためのフローの全体像は以下の通りです。 以下で各ステップの詳細についてご紹介します。 2-1. アイテムが作成または変更されたとき このフローが実行されるトリガーです。 トリガーの条件として以下を指定しました。 @equals(triggerBody()['OData__x30b9__x30c6__x30fc__x30bf__x30/Value'],'投稿完了') 上記は作成または更新されたアイテムのステータスが 投稿完了 のときにこのフローが実行されることを意味しています。 トリガーの条件の書き方については第3回の記事で詳しく解説しているため、そちらを参照ください。 2-2. チャットまたはチャネルでメッセージを投稿する 投稿者宛に記事が公開されたことを通知します。 上記の処理によってMicrosoft TeamsでWorkflowsという対象から投稿者の個人チャット宛にメッセージが投稿されます。 注意事項 今回ご紹介したPower Automateのフローは意図的にフローの実行結果から別のフローを呼び出すという設計にしていますが、設定値を誤ると無限ループが発生する可能性があります。 本記事の内容を流用される場合には無限ループが発生しないように十分に注意して設計/構築してください。 無限ループへの対処法については以下の日本マイクロソフトのブログ記事も参照ください。 Power Automate のフローで無限トリガーループが起きる際の対処法 | Japan Dynamics CRM & Power Platform Support Blog 最後に NTT WEST Engineers' Blog 開設にむけて投稿記事レビューのワークフローを爆速で構築した話と題して第6回までお送りしました。 本記事で紹介した内容の各要素は他のブログ等でも紹介されており、特別難しいことをしているわけではありません。 ただ私自身がこのフローを作る中で調べものをしているときに各要素を紹介したものはあるがこれらを組み合わせて構築してみたといった内容の記事は数が多くないように感じました。 なければ自分で作ればいいじゃないということで今回執筆してみましたがいかがでしたでしょうか。 需要がないから誰も書いていない可能性はあるかも・・・と思いつつ執筆しましたが少しでも参考になる部分があれば幸いです。 ここでご紹介したフロー自体は3,4日程度で執筆者自身が単独で構成検討/構築したもので運用も始まったばかりでこれから様々なブラッシュアップが入ることが想定されます。 ブラッシュアップしていく中で参考になりそうな内容が出てきた際には本ブログにて改めてご紹介できればと思います。 ここまで読んでいただきありがとうございます。 執筆者 服部 真智(NTT西日本 ビジネス営業本部所属) 普段はAWS案件の提案、設計、構築等の支援を行っています。 自業務の効率化のためにPython,Power Automate,生成AI等を使って日々試行錯誤しています。 2025 Japan AWS Top Engineers (Services) 商標 Microsoft (Microsoft Entra 、 Microsoft Teams 、 Power Automate 、 Microsoft Lists 、 Microsoft Forms)及び関連する名称並びにそれぞれのロゴは、米国 Microsoft Corporation の米国およびその他の国における商標または登録商標です。
はじめに NTT西日本の服部です。本記事はNTT WEST Engineers' Blog 開設にむけて投稿記事レビューのワークフローを爆速で構築した話の第5回の記事となります。 前回までの記事も読んでいただけるとありがたいです。 第5回となる本記事ではPower Automateによるレビューフロー中編としてレビュアーアサイン後のレビューフローについてご紹介します。 本記事は2025年9月時点の情報に基づきます。 ①~概要編~ ②~Microsoft Forms/Microsoft Lists編~ ③~Power AutomateによるMicrosoft Listsへの自動登録編~ ④~Power Automateによるレビューフロー前編~ ⑤~Power Automateによるレビューフロー中編~ (本記事) ⑥~Power Automateによるレビューフロー後編~ 第1回でご紹介したワークフローの全体像のうち、以下の図にあたる内容となります。 対象読者 本記事が想定する対象読者は以下の通りです。 自動化に興味がある人 繰り返しの定常的な作業に困っている人 Microsoft Forms/Microsoft Lists/Power Automateを使ってみたい人 背景 NTT WEST Engineers' Blog に向けて、ブログ記事のレビュープロセスを効率化したいという要望を受けて執筆者が検討・構築しました。 SaaSの新規サービスを導入する予算はありませんでしたが、幸い全社的にMicrosoft Forms、Microsoft Lists、Power Automateが利用できる環境だったため、これらを用いてブログ記事レビューのワークフローを構築しました。 本記事ではレビュアーアサイン後のレビューフローとして構築したPower Automateのフローについて紹介します。 補足:アダプティブカードについて 今回紹介するフローの中で利用されているアダプティブカードについて事前にご紹介します。 アダプティブカードとは、テキストや画像、ボタンなどを組み合わせたインタラクティブなメッセージカードです。 Microsoft Teamsで利用するアダプティブカードについての詳細は以下の公式ドキュメントを参照ください。 Teams 向けアダプティブ カードの概要 - Power Automate | Microsoft Learn アダプティブカードを設計する際には以下のデザイナーを利用することができます。 Designer | Adaptive Cards 上記のデザイナーを使ってMicrosoft Teamsに投稿するアダプティブカードをデザインする際には下図赤枠の Select host app で Microsoft Teams を選択するようにしてください。 引用元: https://adaptivecards.io/designer デフォルトで選択されている Bot Framework WebChat の場合、画面右上の Target Version が 1.6 となっておりこちらのバージョンはMicrosoft Teamsに対応していません。 非対応のバージョンで作成されたアダプティブカードをMicrosoft Teamsに投稿すると以下のメッセージが表示されます。 レビュアーアサイン後のレビューフロー アダプティブカードについてご紹介したところで本題のPower Automateのフローについてご紹介します。 今回レビューの処理用に構築したフローの全体像は以下の通りです。 以下で各ステップの詳細についてご紹介します。 1.アイテムが作成または変更されたとき このPower Automate のフローが実行される条件(トリガー)になります。 前回の記事でも紹介しましたがMicrosoft Listsにおける一行ごとのデータ(レコード)のことをアイテムといい、本記事においては1アイテム=1件分のレビュー依頼に相当します。 アイテムが新規に作成されたもしくは既存のアイテムの値が変更されたときにこのフローが実行されます。 トリガーの条件として以下を指定しました。 @equals(triggerBody()['OData__x30b9__x30c6__x30fc__x30bf__x30/Value'],'レビュアーアサイン待ち') @not(equals(triggerBody()['OData__x30ec__x30d3__x30e5__x30a2__x30/Value'],'未設定')) 上記は作成または更新されたアイテムのステータスが レビュアーアサイン待ち かつレビュアーが 未設定ではない (=誰かしらレビュアーがアサインされている)ときにこのフローが実行されることを意味しています。 トリガーの条件式の書き方については前回の記事で詳しく解説しているため、そちらを参照ください。 2.項目の更新(レビュー待ち) 実際のレビュー依頼をあげるまえにステータスをレビュー待ちに更新します。 ステータスをレビュー待ちに更新したとしても他のフローのトリガー条件にあてはまることはないため、他のフローは実行されません。 3.アダプティブ カードを投稿して応答を待機する(レビュー依頼) レビュアーとしてアサインされた担当者にアダプティブカードを送る処理です。 省略されているメッセージ部分には以下のJSONが記載されています。 { " type ": " AdaptiveCard ", " body ": [ { " type ": " TextBlock ", " size ": " Medium ", " weight ": " Bolder ", " text ": " ブログ記事のレビュー依頼 " } , { " type ": " TextBlock ", " text ": " タイトル:@{outputs('項目の更新(レビュー待ち)')?['body/Title']}の記事のレビュアーとして設定されました。 \n 以下の下書き記事を見てレビューコメントを入力してください。 \n コメントを入力後レビュー結果に相当するボタンをクリックしてください。 ", " wrap ": true } , { " type ": " ActionSet ", " actions ": [ { " type ": " Action.OpenUrl ", " title ": " 下書きプレビューURL ", " url ": " @{outputs('項目の更新(レビュー待ち)')?['body/OData__x4e0b__x66f8__x304d__x30d7__x30']} " } ] } , { " type ": " Input.Text ", " placeholder ": " Placeholder text ", " id ": " comment ", " isRequired ": true , " errorMessage ": " レビューコメントは必須項目です。 ", " label ": " レビューコメント ", " isMultiline ": true } , { " type ": " ActionSet ", " actions ": [ { " type ": " Action.Submit ", " title ": " 承認 ", " id ": " approval " } , { " type ": " Action.Submit ", " title ": " 差戻 ", " id ": " remand " } , { " type ": " Action.Submit ", " title ": " キャンセル ", " id ": " cancel " } , { " type ": " Action.Submit ", " title ": " 却下 ", " id ": " reject " } ] , " horizontalAlignment ": " Left " } , { " type ": " TextBlock ", " text ": " ・承認:レビューを完了します。 \n ・差戻:投稿者に修正を依頼します。 \n ・キャンセル:レビュアーの変更を依頼します。 \n ・却下:規定違反などを理由に却下します。 ", " wrap ": true } ] , " $schema ": " http://adaptivecards.io/schemas/adaptive-card.json ", " version ": " 1.5 " } 上記のアダプティブカードが送信されるとMicrosoft TeamsでWorkflowsという対象から以下のようなメッセージがレビュアーの個人チャット宛に届きます。 下書きプレビューURLのボタンはリンクとなっており、ブログ記事の下書きページを確認することができ、その内容についてレビューした結果をレビューコメントの枠に入力します。 レビューコメントを入力したらレビュー結果に相当するボタンをクリックすることで次の処理に進めることができます。   また、レビューコメントの属性として "isRequired": true, を指定することで必須の入力項目となり、空欄のままでは次の処理に進められないようにしています。 補足:アダプティブカードのタイムアウト設定について アダプティブカードは規定では30日でタイムアウトとなりますがこの期間は変更することが可能です。 変更する場合はアダプティブカードのステップの右側にある ・・・ から 設定 をクリックします。 設定をクリックすると以下の画面が表示されるため、タイムアウトを設定することが出来ます。 ここでは14日間経過するとタイムアウトするように設定しています。 タイムアウトの期間はISO 8601 形式で期間を指定します。 ISO 8601 形式の詳細については以下を参照ください。 ISO 8601 - Wikipedia ISO 8601-1:2019(en) 4.スイッチ(レビュー結果) アダプティブカードに対してレビュアーが操作した結果によって処理が分岐します。 分岐処理の判定には以下の値を使用しています。 outputs('アダプティブ カードを投稿して応答を待機する(レビュー依頼)')?['body/submitActionId'] ここには直前に処理されたアダプティブカードでクリックされたボタンのIDが入ります。 つまりアダプティブカードのメッセージで定義された以下のボタンに割り当てられたIDである approval , remand , cancel , reject のいずれかが入ります。 " type ": " ActionSet ", " actions ": [ { " type ": " Action.Submit ", " title ": " 承認 ", " id ": " approval " } , { " type ": " Action.Submit ", " title ": " 差戻 ", " id ": " remand " } , { " type ": " Action.Submit ", " title ": " キャンセル ", " id ": " cancel " } , { " type ": " Action.Submit ", " title ": " 却下 ", " id ": " reject " } ] , 4-1.ケース1(承認) アダプティブカードで 承認 がクリックされたときの処理です。 承認された場合には投稿者へのレビュー完了の通知処理とステータスをレビュー完了に変更する処理と事務局への記事公開依頼処理が含まれています。 本来は以下のステップの前に タグの @mention トークンを取得する のステップを追加するべきですが、ここでは割愛しています。 上記の処理によってMicrosoft Teamsで指定されたチャネルにメッセージが投稿されます。 上記の処理によってMicrosoft TeamsでWorkflowsという対象から投稿者の個人チャット宛にメッセージが投稿されます。 4-2.ケース2(差戻) アダプティブカードで 差戻 がクリックされたときの処理です。 ここではステータスを差し戻しに更新する処理のみを定義しています。 修正依頼のフローはここでは定義しておらず、別のフローとして定義されています。 修正依頼のフローの詳細については次回ご紹介します。 4-3.ケース3(キャンセル) アダプティブカードで キャンセル がクリックされたときの処理です。 レビュアーが業務都合などの理由から担当者を変更して欲しい場合に使うことを想定しています。 ここではステータスをレビュアーアサイン待ちに、レビュアーを未設定に更新する処理を実行します。 この処理によって前回ご紹介したレビュアーアサイン依頼のフローのトリガー条件を満たすことになり、レビュアーのアサインからやり直すことができます。 4-4.ケース4(却下) アダプティブカードで 却下 がクリックされたときの処理です。 記事の内容が規定に反する等の理由から投稿できないと判断されたときに使うことを想定しています。 ここではステータスを 却下/消滅 に更新する処理と投稿者へのレビュー結果通知の処理を定義しています。 上記の処理によってMicrosoft TeamsでWorkflowsという対象から投稿者の個人チャット宛にメッセージが投稿されます。 5.項目の更新(レビュータイムアウトに伴うレビュアーリセット) 本記事でアダプティブカードのタイムアウトについて解説しましたが、アダプティブカードがタイムアウトするとフローの処理としては失敗となりそこで処理が終了してしまいます。 そこで万が一タイムアウトが発生した場合の処理の定義が以下の内容になります。 ここではケース3(キャンセル)と同じでステータスを レビュアーアサイン待ち に、レビュアーを 未設定 に更新することでレビュアーのアサイン依頼のフローを呼び出せるようにしています。 タイムアウト用の処理を定義したい場合は分岐したいステップの直後(今回はアダプティブカードのステップの直後)で⊕ボタンをクリックして並列分岐の追加をクリックします。 分岐先で追加したステップ(今回は項目の更新)の右側の ・・・ から実行条件の構成をクリックします。 実行条件の構成をクリックすると以下の画面が表示され、直前のステップ(ここではアダプティブカードのステップ)の処理結果がどうなったときにこのステップを実行するかを選択することができます。ここではタイムアウトした場合に実行すると定義しています。 成功しました以外が選択された状態で完了をクリックすると該当のステップに繋がる矢印が赤の破線に変更されます。 注意事項 今回ご紹介したPower Automateのフローは意図的にフローの実行結果から別のフローを呼び出すという設計にしていますが、設定内容を誤ると無限ループが発生する可能性があります。 本記事の内容を流用される場合には無限ループが発生しないように十分に注意して設計/構築してください。 無限ループへの対処法については以下の日本マイクロソフトのブログ記事も参照ください。 Power Automate のフローで無限トリガーループが起きる際の対処法 | Japan Dynamics CRM & Power Platform Support Blog まとめ 今回は本シリーズの最も重要なレビューフローについてご紹介しました。 多くの処理が含まれるため非常に長い記事となりましたがここまで読んでいただきありがとうございます。 次回は本シリーズの最終回で修正依頼と投稿完了通知のフローのご紹介となります。 もしよろしければ最後までお付き合いください。 執筆者 服部 真智(NTT西日本 ビジネス営業本部所属) 普段はAWS案件の提案、設計、構築等の支援を行っています。 自業務の効率化のためにPython,Power Automate,生成AI等を使って日々試行錯誤しています。 2025 Japan AWS Top Engineers (Services) 商標 Microsoft (Microsoft Entra 、 Microsoft Teams 、 Power Automate 、 Microsoft Lists 、 Microsoft Forms)及び関連する名称並びにそれぞれのロゴは、米国 Microsoft Corporation の米国およびその他の国における商標または登録商標です。
はじめに NTT西日本の桂川です。 本記事では、クラウド運用自動化の実践として、「AWS Step Functions(以降、Step Functions)」を活用したワークフロー自動化について紹介します。 「Step Functions」は、AWS SDKサービス統合により、各種AWSサービスのAPIアクションを呼び出すことが可能であり、複数のAWSサービスを組み合わせたワークフローを構築することができます。 本記事では、運用自動化の一例として、IAMユーザーの自動作成に取り組んだ事例を解説します。 なお、本記事の内容は2025年9月時点の情報に基づいています。 対象読者 本記事の対象読者は、以下のような方々を想定しています。 AWS や 運用自動化に関心のある方 Step Functions の活用方法を知りたい方 IAMユーザー作成の自動化を検討している方 背景・目的 AWSアカウントに多数のIAMユーザーを作成する必要がある場面に直面し、手作業による対応では効率が悪いため、作業の自動化について検討を始めました。 IAMユーザー作成の自動化にあたり、以下の要件を満たす必要がありました。 前提条件 AWSアカウントは、管理アカウントとメンバーアカウントで構成されている 管理アカウントがメンバーアカウントのセキュリティ統制やコスト管理を行う 要件 メンバーアカウント利用開始時に初期セットアップとしてIAMユーザーを作成する IAMユーザの初期パスワードは、ランダムなパスワードを自動作成する 初回サインイン時にパスワードのリセットを要求する 制限事項 他のIAMユーザーのパスワードは閲覧不可とする メンバーアカウントのIAMユーザーは、IAM関連操作を禁止する これらの要件を満たすため「AWS Cloud Formation(以降、Cloud Formation)」で実現する方法と「Step Functions」で実現する方法の2つの方法を検討しました。 ■ 各サービスの比較結果 要件 Cloud Formation Step Functions IAMユーザ作成 〇 〇 パスワード自動作成 △ 〇 パスワードリセット 〇 〇 パスワード閲覧不可 △ 〇 IAM関連操作禁止 △ 〇 各サービスの実現方法を比較した結果、パスワードの自動作成などの要件を容易に満たせること、またアクセス権限に関する考慮が比較的少なくて済むことから、「Step Functions」を採用しました。 表について、要件の達成は可能だが、実装が複雑になる項目を「△」としています。「Cloud Formation」の採用を見送った主な理由は、以下の通りです。 パスワード自動作成 パスワードを自動作成する際、「AWS Secrets Manager(以降、Secrets Manager)」を使用してパスワードをシークレットとして保存し、IAMユーザー作成時にそのシークレットを参照する必要がありました。 パスワード閲覧不可 メンバーアカウント内の他のIAMユーザーがパスワードを閲覧ができないよう「Secrets Manager」に保存されたパスワードのアクセス権限を適切に設定する必要がありました。 IAM関連操作禁止 メンバーアカウントのIAMユーザーが展開済みの「Cloud Formation」を使用して、IAM関連の操作を実行できないよう考慮する必要がありました。 「Step Functions」は、AWS SDKサービス統合により、さまざまなAWSサービスのAPIアクションを呼び出すことが可能となっており、 複数のサービスを組み合わせたワークフローを容易に作成できます。 さらに、ノーコードで開発できるデザインツールも備えており、Cloud Formationのようにコードを書くことが苦手な方でも取り組みやすいという特長があります。 「Step Functions」は、各サービスとの柔軟な統合が可能で、幅広いユースケースに対応できるため、運用自動化を推進するうえで、皆様にとっても非常に有用なツールになると考えています。 本記事では、IAMユーザーの自動作成に取り組んだ事例を通じて、その活用方法についてご紹介したいと思います。 ソリューションの概要 このソリューションでは、AWSアカウントへIAMユーザーを自動作成するStep Functions ワークフローについて紹介します。 本事例では、管理アカウントからメンバーアカウントへIAMユーザを自動作成する構成について解説します。 管理アカウントがない場合は、対象アカウント上にStep Functionsワークフローを直接構築することも可能です。 ■ 構成図 前提条件 以下のIAMリソースを事前に作成してください。 アカウント IAMリソース 概要 管理アカウント Step Functions実行用IAMロール クロスアカウントアクセス用IAMロールに対するAssumeRole権限を許可 メンバーアカウント クロスアカウントアクセス用IAMロール IAMユーザー作成に必要な権限を許可 メンバーアカウント IAMグループ IAMユーザーが所属するIAMグループ 例)StepFunctions実行用IAMロール { " Version ": " 2012-10-17 ", " Statement ": [ { " Action ": [ " sts:assumeRole " ] , " Resource ": [ " arn:aws:iam::<メンバーアカウントID>:role/<クロスアカウントアクセス用IAMロール> " ] , " Effect ": " Allow " } ] } 例)クロスアカウントアクセス用IAMロール { " Version ": " 2012-10-17 ", " Statement ": [ { " Action ": [ " iam:CreateLoginProfile ", " iam:AddUserToGroup ", " iam:AttachUserPolicy ", " iam:ListAccountAliases ", " iam:CreateUser " ] , " Resource ": [ " * " ] , " Effect ": " Allow " } , { " Action ": [ " secretsmanager:GetRandomPassword " ] , " Resource ": [ " * " ] , " Effect ": " Allow " } ] } アカウントエイリアスを事前に設定してください。 今回は、サインインURLを自動作成する際にアカウントエイリアスを使用します。 以下の場合は、設定不要です。 サインインURLにアカウントIDを使用する場合 サインインURLを自動作成しない場合 考慮事項 クロスアカウントアクセス用IAMロールの信頼関係でAssumeRoleを許可するPrincipalは必要最小限としてください。 適切な信頼関係が設定されていない場合、メンバーアカウントのIAMユーザーがクロスアカウントアクセス用IAMロールにSwitchRoleすることで、意図せずアクセス権限が付与されてしまう可能性があります。 例)クロスアカウントアクセス用IAMロールの信頼関係 { " Version ": " 2008-10-17 ", " Statement ": [ { " Effect ": " Allow ", " Principal ": { " AWS ": " arn:aws:iam::<管理アカウントID>:<Step Functions実行用IAMロール> " } , " Action ": " sts:AssumeRole " } ] } 管理アカウントがなく対象アカウント上にStep Functionsワークフローを直接構築する場合、Step Functionsを実行することで、意図せずアクセス権限が付与されないよう注意してください。 例えば、対象アカウント上のIAMユーザーにおいてIAM関連操作を禁止している場合、IAMユーザがStep Functionsワークフローを実行することで、意図せずIAMユーザー作成が可能となってしまう可能性があります。 例)管理アカウントがなく対象アカウント上にStep Functionsワークフローを直接構築する場合 IAMユーザー自動作成ワークフローの作成 ■ 概要 メンバーアカウントにIAMユーザーを自動作成するStep Functions ワークフローを作成します。 AWSマネジメントコンソール上からIAMユーザーを作成する場合と同様に「ユーザー名」、「サインインURL」、「パスワード」を出力するワークフローを作成します。 「パスワード」は、ワークフローで自動作成し、次回のサインイン時に新しいパスワードを設定するよう要求します。 ■ Step Functions ワークフロー 「メンバーアカウントID」と「ユーザー名」をパラメータとして入力し、「ユーザー名」、「サインインURL」、「パスワード」を出力するワークフローを作成します。 ワークフロー 入力パラメータ { " AccountId ": " <メンバーアカウントID> ", " UserNames ": [ " <ユーザー名> ", " <ユーザー名> " ] } 出力パラメータ { " Users ": [ { " UserName ": " <ユーザー名> ", " LoginURL ": " <サインインURL> ", " Password ": " <パスワード> " } , { " UserName ": " <ユーザー名> ", " LoginURL ": " <サインインURL> ", " Password ": " <パスワード> " } ] } ■ 作成手順 1. Step Functions の [ステートマシンの作成] から ワークフローを作成します。 2. Step Functions Workflow Studio で ワークフローを編集します。 「デザイン」モード は、状態をキャンバスにドラッグアンドドロップすることでワークフローを作成することが可能です。 「コード」モード は、 Amazon States Language(ASL)を使用してワークフローを作成します。 デザインモード コードモード 実行したいアクションを選択し、[APIパラメータ] 、[次の状態] 、[入力] 、[出力] 、[エラー処理] などのパラメータを設定します。 クロスアカウントアクセスを行う場合、[クロスアカウントアクセスを有効にする] をチェックし、[ターゲットロール ARN] を設定します。 IAMユーザー自動作成ワークフローのASL定義を参考として記載します。エラー処理などは割愛しています。 IAMユーザー自動作成ワークフロー(ASL定義) { " Comment ": " Create multiple IAM users with random passwords ", " StartAt ": " ListAccountAliases ", " States ": { " ListAccountAliases ": { " Type ": " Task ", " Resource ": " arn:aws:states:::aws-sdk:iam:listAccountAliases ", " Parameters ": {} , " ResultPath ": " $.AccountAliasResult ", " Next ": " CreateUsersMap ", " Credentials ": { " RoleArn.$ ": " States.Format('arn:aws:iam::{}:role/<クロスアカウントアクセス用IAMロール>', $.AccountId) " } } , " CreateUsersMap ": { " Type ": " Map ", " ItemsPath ": " $.UserNames ", " Parameters ": { " AccountId.$ ": " $.AccountId ", " UserName.$ ": " $$.Map.Item.Value ", " AccountAlias.$ ": " $.AccountAliasResult.AccountAliases[0] " } , " ResultPath ": " $.UserResults ", " Iterator ": { " StartAt ": " GenerateRandomPassword ", " States ": { " GenerateRandomPassword ": { " Type ": " Task ", " Resource ": " arn:aws:states:::aws-sdk:secretsmanager:getRandomPassword ", " Parameters ": { " PasswordLength ": 13 , " RequireEachIncludedType ": true , " ExcludeCharacters ": " \"\\ ,./:;<>?`~. " } , " ResultPath ": " $.RandomPasswordResult ", " Next ": " CreateIAMUser ", " Credentials ": { " RoleArn.$ ": " States.Format('arn:aws:iam::{}:role/<クロスアカウントアクセス用IAMロール>', $.AccountId) " } } , " CreateIAMUser ": { " Type ": " Task ", " Resource ": " arn:aws:states:::aws-sdk:iam:createUser ", " Parameters ": { " UserName.$ ": " $.UserName " } , " ResultPath ": " $.TaskResult ", " Next ": " CreateLoginProfile ", " Credentials ": { " RoleArn.$ ": " States.Format('arn:aws:iam::{}:role/<クロスアカウントアクセス用IAMロール>', $.AccountId) " } } , " CreateLoginProfile ": { " Type ": " Task ", " Resource ": " arn:aws:states:::aws-sdk:iam:createLoginProfile ", " Parameters ": { " UserName.$ ": " $.UserName ", " Password.$ ": " $.RandomPasswordResult.RandomPassword ", " PasswordResetRequired ": true } , " ResultPath ": " $.TaskResult ", " Next ": " AttachUserPolicy ", " Credentials ": { " RoleArn.$ ": " States.Format('arn:aws:iam::{}:role/<クロスアカウントアクセス用IAMロール>', $.AccountId) " } } , " AttachUserPolicy ": { " Type ": " Task ", " Resource ": " arn:aws:states:::aws-sdk:iam:attachUserPolicy ", " Parameters ": { " UserName.$ ": " $.UserName ", " PolicyArn ": " arn:aws:iam::aws:policy/IAMUserChangePassword " } , " ResultPath ": " $.TaskResult ", " Next ": " AddUserToGroup ", " Credentials ": { " RoleArn.$ ": " States.Format('arn:aws:iam::{}:role/<クロスアカウントアクセス用IAMロール>', $.AccountId) " } } , " AddUserToGroup ": { " Type ": " Task ", " Resource ": " arn:aws:states:::aws-sdk:iam:addUserToGroup ", " Parameters ": { " UserName.$ ": " $.UserName ", " GroupName ": " <IAMグループ> " } , " ResultPath ": " $.TaskResult ", " Next ": " ReturnLoginInfo ", " Credentials ": { " RoleArn.$ ": " States.Format('arn:aws:iam::{}:role/<クロスアカウントアクセス用IAMロール>', $.AccountId) " } } , " ReturnLoginInfo ": { " Type ": " Pass ", " Parameters ": { " LoginURL.$ ": " States.Format('https://{}.signin.aws.amazon.com/console', $.AccountAlias) ", " UserName.$ ": " $.UserName ", " Password.$ ": " $.RandomPasswordResult.RandomPassword " } , " End ": true } } } , " Next ": " ReturnAllLoginInfo " } , " ReturnAllLoginInfo ": { " Type ": " Pass ", " Parameters ": { " Users.$ ": " $.UserResults " } , " End ": true } } } 3. Step Functions の 実行ロールを設定します。 Step Functions の 実行ロールを設定します。必要に応じて、ログ記録設定などを行い、[作成] をクリックします。 4. Step Functions の [実行を開始] から ワークフローを実行します。 Step Functions の 実行ステータス が [成功] となり、実行が完了していることを確認します。 5. メンバーアカウントにIAMユーザーが作成されていることを確認します。 メンバーアカウントにサインインして、IAMユーザーが作成されていることを確認します。 まとめ 本記事では、クラウド運用自動化の一例として、AWSの「Step Functions」を活用したIAMユーザーの自動作成に取り組んだ事例をご紹介しました。 「Step Functions」は、AWS SDKサービス統合により、各種AWSサービスのAPIアクションを呼び出すことが可能で、幅広いユースケースに対応することができます。 また、Workflow Studioを使用することでノーコード開発も可能となり、Cloud Formationのようにコードを書くことが苦手な方でも取り組みやすくなっています。 さらに、「AWS Lambda」を使用しない構成であれば、ランタイムバージョンのアップグレードなどの定期保守が不要となり、運用負荷の軽減にもつながります。 運用における定型作業や繰り返し作業を自動化することで、「作業時間の削減」や「手動操作によるヒューマンエラーの防止」、「作業の一貫性確保」といった多くのメリットが得られます。 まずは、運用自動化の第一歩として、身近な業務から取り組んでみてはいかがでしょうか。 本記事が、皆様の業務改善の一助となれば幸いです。 執筆者 桂川 裕幸(NTT西日本 ビジネス営業本部 エンタープライズビジネス営業部所属) AWSを活用したクラウドシステムの設計・構築に携わっています。 サーバーレスアーキテクチャが好きです。 2025 Japan AWS All Certifications Engineers に選出。 参考資料・出典 本記事を執筆するにあたり、以下のサイトを参考にさせていただきました。 docs.aws.amazon.com docs.aws.amazon.com docs.aws.amazon.com 商標  「AWS」「AWS Step Functions」「AWS Lambda」「AWS Secrets Manager」「AWS Cloud Formation」は、Amazon Web Services,Inc.またはその関連会社の商標もしくは登録商標です。 免責事項 本記事の内容には、IAMアクセス権限管理 や クロスアカウントアクセスなどのセキュリティに関する考慮事項があります。 本記事を参照する際は、ご自身の環境をよくご確認の上、適切な権限管理をお願いします。 なお、本記事の内容を実施した結果発生する損失・損害については一切の責任を負いかねます。
はじめに NTT西日本の服部です。本記事はNTT WEST Engineers' Blog 開設にむけて投稿記事レビューのワークフローを爆速で構築した話の第4回の記事となります。 前回までの記事も読んでいただけるとありがたいです。 第4回となる本記事ではPower Automateによるレビューフロー前編としてレビュアーのアサイン依頼のフローについてご紹介します。 本記事は2025年9月時点の情報に基づきます。 ①~概要編~ ②~Microsoft Forms/Microsoft Lists編~ ③~Power AutomateによるMicrosoft Listsへの自動登録編~ ④~Power Automateによるレビューフロー前編~ (本記事) ⑤~Power Automateによるレビューフロー中編~ ⑥~Power Automateによるレビューフロー後編~ 第1回でご紹介したワークフローの全体像のうち、以下の図にあたる内容となります。 対象読者 本記事が想定する対象読者は以下の通りです。 自動化に興味がある人 繰り返しの定常的な作業に困っている人 Microsoft Forms/Microsoft Lists/Power Automateを使ってみたい人 背景 NTT WEST Engineers' Blog に向けて、ブログ記事のレビュープロセスを効率化したいという要望を受けて執筆者が検討・構築しました。 SaaSの新規サービスを導入する予算はありませんでしたが、幸い全社的にMicrosoft Forms、Microsoft Lists、Power Automateが利用できる環境だったため、これらを用いてブログ記事レビューのワークフローを構築しました。 本記事ではPower Automateによるレビュアーのアサイン依頼フローについてご紹介します。 レビュアーのアサイン依頼フロー レビュアーのアサイン依頼フローとして構築したPower Automateのフローは以下の通りです。 各ステップの内容についてご紹介します。 1.アイテムが作成または変更されたとき 上記の設定はこのPower Automate のフローが実行される条件(トリガー)になります。 ここでアイテムというワードが唐突に登場しましたが、Microsoft Listsにおける一行ごとのデータ(レコード)のことをアイテムといいます。本記事においては1件分のレビュー依頼に相当します。 特定のSharepointサイトのリスト名を指定して、対象のリストでアイテムが作成または変更されたときにこのフローが実行されます。 初期設定のままではアイテムが新しく作成されたときにもこのフローが実行されてしまいますし、既存のアイテムについては何か一つでも列の値が変更されたときでもこのフローが実行されてしまいます。 そのため、このフローが実行される条件を限定する必要があります。 ステップの右上の ・・・ から設定をクリックします。 設定をクリックすると下図の画面が表示されます。 トリガーの条件の部分にこのフローが実行されるために満たすべき条件を指定します。 このフローのトリガーの条件は以下の内容が設定されています。 これはリストでアイテムが作成もしくは値が更新されたときに該当のアイテムについて ステータスがレビュアーアサイン待ち かつ レビュアーが未設定 であればフローが実行されることを意味します。 @equals(triggerBody()['OData__x30b9__x30c6__x30fc__x30bf__x30/Value'],'レビュアーアサイン待ち') @equals(triggerBody()['OData__x30ec__x30d3__x30e5__x30a2__x30/Value'],'未設定')` OData__x30b9__x30c6__x30fc__x30bf__x30 や OData__x30ec__x30d3__x30e5__x30a2__x30 は列の名前を指しています。 列の名前に ステータス や レビュアー というように全角文字を使用した場合、この値はMicrosoft Listsの設定画面から指定すべき文字列を確認する必要があります。 Sharepointサイトでリストを開き右上の歯車のマークから リストの設定 をクリックします。 以下の画面に遷移し、条件として使いたい列をクリックします。 今回はステータスとします。 遷移後の画面のURLを確認し Field= に続く値をコピーします。 OData_ とコピーした値を結合した文字列が特定の列を指す値となります。 条件として指定する列の種類が選択肢の場合は /Value を末尾に追加する必要があります。 今回の例では OData__x30b9__x30c6__x30fc__x30bf__x30/Value という文字列がステータスという列で選択されている選択肢を指すことになります。 条件式の書き方については以下の公式ドキュメントも参照ください。 Power Automate で条件式を使用する - Power Automate | Microsoft Learn 2.チャネルでメッセージを投稿する(レビュアーアサイン依頼) 今回作成したワークフローではレビュアーを設定する操作自体は運営担当者にて手動で設定するという設計にしているため、運営向けにMicrosoft Teamsで通知するという処理を設けています。 メッセージの編集画面の右上の </> をクリックするとhtmlのタグを使ってメッセージの内容を設定することが出来ます。 注意事項 今回ご紹介するPower Automateのフローは意図的にフローの実行結果から別のフローを呼び出すという設計にしていますが、設定値を誤ると無限ループが発生する可能性があります。 本記事の内容を流用される場合には無限ループが発生しないように十分に注意して設計/構築してください。 無限ループへの対処法については以下の日本マイクロソフトのブログ記事も参照ください。 Power Automate のフローで無限トリガーループが起きる際の対処法 | Japan Dynamics CRM & Power Platform Support Blog まとめ 今回はレビュアーのアサイン依頼フローとして構築したPower Automateついてご紹介しました。 次回はレビュアーアサイン後のレビューフローについてご紹介します。 執筆者 服部 真智(NTT西日本 ビジネス営業本部所属) 普段はAWS案件の提案、設計、構築等の支援を行っています。 自業務の効率化のためにPython,Power Automate,生成AI等を使って日々試行錯誤しています。 2025 Japan AWS Top Engineers (Services) 商標 Microsoft (Microsoft Entra 、 Microsoft Teams 、 Power Automate 、 Microsoft Lists 、 Microsoft Forms)及び関連する名称並びにそれぞれのロゴは、米国 Microsoft Corporation の米国およびその他の国における商標または登録商標です。
はじめに NTT西日本の坂下です。 本記事では、セキュリティに関心のある学生の皆さんに向けて、セキュリティ分野に特化したワークショップをご案内します。 ※2027年度卒業予定の学生の皆様を対象とした、NTT西日本インターンシップの1つとして開催いたします。 このワークショップは実践形式でセキュリティの業務内容を広く体感できる内容になっています。 「セキュリティ」というキーワードに少しでも興味を持った方は、ぜひ気軽にチェックしてみてください! 本記事は2025年10月時点の情報に基づきます。 対象読者 本記事が想定する対象読者は以下の通りです。 セキュリティ分野に興味がある2027年卒業予定の学生 背景・目的 「セキュリティに興味はあるけど、実際にどんな業務があるのかわからない」という声を学生の方々から多くいただいています。 実はセキュリティは"単に攻撃を防ぐ"だけではありません。どのように戦略を立て、情報資産を管理し、調査・対応をするか、そして、如何に攻撃を防御し、検知、対応復旧させるか。技術力に加え、思考力やチーム力もいかされる、とても奥深く面白い分野です。 当社では、社内にSOCを設置しており、近年注目されているオフェンシブセキュリティの視点から検証するREDチームを編成しています。単なる “守り” にとどまらない、まさに攻撃と防御の両輪で思考力やチーム力をいかした、幅広くも奥深い業務を展開しています。 この面白さを皆さんに知ってもらいたい。 その想いで今回、実際の現場に近い体験を通して “セキュリティのリアル” を体感してもらえる二日間のワークショップを企画し、本投稿を執筆しています。 セキュリティワークショップとは 今回企画しているセキュリティワークショップの内容を以下に記載します。 ワークショップ概要 開催日:2025年11月6日(木)〜11月7日(金)※ 第4回 応募締切:2025年10月30日(木)17:00 開催形式:オンライン 【応募方法】 以下①②の手順で応募を受け付けています。 ① NTT西日本 採用マイページ に登録 ② 応募フォーム に必要事項を入力して回答 ※必ずこのリンクからマイページへの登録、フォームへの回答をお願いします。 ※参加の可否については11/3までにマイページ上でご連絡させていただきます。 ※第1回から第3回までの開催分につきましては、すでに受付を終了しております。 今回の第4回が、「INTERNSHIP 2027 セキュリティワークショップ」へのご参加の最後の機会となります。 ワークショップ詳細 幅広く弊社のセキュリティ業務の現場感を、ワークを通して体感することができます。 内容の一部をご紹介すると システムに対する調査内容を考えるワーク 攻撃者視点に立って考えるワーク インシデントに対する対応判断ワーク などを予定しています。 また、実際にセキュリティ業務に携わっている社員との座談会も予定しており、「どんなキャリアを描いているのか」「どんな働き方をしているのか」といったリアルな話も聞くことができます。 セキュリティの考え方 さて、もしかしたらご存じの方もいるかもしれません。先ほどお伝えしたセキュリティの面白さの内容につながる、現代におけるセキュリティ対策を考えるためのフレームワークが存在します。 それが、米国国立標準技術研究所(NIST)の提供する「サイバーセキュリティフレームワーク2.0(NIST CSF 2.0)」です。 NIST CSF 2.0とは、統治(Govern)、識別(Identify)、防御(Protect)、検知(Detect)、対応(Respond)、復旧(Recover)の6つの機能を軸に、サイバーセキュリティ対策を改善する、世界的にも広く使われている枠組みです。 私たちもこういったフレームワークを取り入れながら、日々の業務でサイバーセキュリティを考え、実践しています。 今回のワークショップでは、このようなフレームワークの考え方も踏まえ、全方位的なセキュリティ対策を体験することで、実際の業務でいかされている幅広いスキルやその業務分野を肌で感じていただけるはずです。 まとめ 「セキュリティに興味はあるけど、どんな仕事かわからない」 そんなあなたにこそ、このワークショップがぴったりです。 もちろん、既にサイバーセキュリティに精通している方も大歓迎! 2日間という短い期間ですが、セキュリティのリアルを体感することで、新しい学びや気づきが得られるはずです。 迷っている方もぜひ気軽にエントリーしてみてください! 用語解説 SOC(Security Operation Center) システムやサービスを監視し、サイバー攻撃や情報漏洩などのセキュリティインシデントをいち早く発見・対応する専門チームです。「セキュリティの最前線」とも言える重要な役割を担っています。 オフェンシブセキュリティ(Offensive Security) 攻撃者視点でシステムの弱点を探し、攻撃される前に対策を立てるセキュリティ手法です。「守るために攻める」考え方で、実践的なスキルが身につく分野です。 REDチーム(Red Team) オフェンシブセキュリティを実践するために、模擬的な攻撃を仕掛け、脆弱性やセキュリティ上の問題点を洗い出す専門チームです。 フレームワーク(Framework) 複雑な物事を整理して捉えるための「考え方の枠組み」です。 執筆者 坂下 晴哉(NTT西日本 セキュリティ&トラスト部所属) NTT西日本Gのセキュリティ戦略、および人材育成業務に従事し、セキュリティ人材育成計画や育成方針を日々考えています。 参考資料・出典 本記事を執筆するにあたり、以下のサイトを参考にしました。 【Web】 IPA 独立行政法人 情報処理推進機構: The NIST Cybersecurity Framework (CSF) 2.0 https://www.ipa.go.jp/security/reports/oversea/nist/ug65p90000019cp4-att/begoj9000000d400.pdf 【Web】 NIST 米国国立標準技術研究所: Cybersecurity Framework | NIST https://www.nist.gov/cyberframework 商標  記載の会社名・製品名・団体名はそれぞれの会社の商標もしくは登録商標です。
はじめに NTT西日本 ミライ事業共創室の西村です。 今回は業務とは関係なく、 趣味として取り組んだ技術チャレンジ についてご紹介します。 私はプログラミングが得意ではなく、コードを見ると「暗号かな??」と思ってしまうほどでした(´;ω;`) そんな自分でも、生成AIに助けてもらいながら 2024年6月ごろ、わずか3日でリアルタイム翻訳ツールを完成させることができました 。 なお、 今回の取組みは業務とは切り離した個人プロジェクト です。 この記事では、その誕生からOSS公開・デモ公開までの歩みをまとめ、さらに読んだ方が持ち帰れる「開発プロセスの工夫」や「現時点でのベストプラクティス」を共有させていただきたいと思います。 開発したツールをイベント利用した際の写真。翻訳がスムーズに表示され、会場の参加者にも安心して楽しんでいただけました。@ QUINTBRIDGE 対象読者 この記事はこんな方に向けています: プログラミングが苦手でも、AIと一緒にモノづくりをしてみたい人 業務外で技術チャレンジをしてみたい社会人・学生 AIを活用して最小構成のプロトタイプ開発に挑戦したいエンジニア まず動くものを作るスタイル(Vibecoding)に共感する人 背景:通訳がいない!? きっかけは、あるイベントでの課題でした。 日本語を話せないゲストが登壇する予定でしたが、同時通訳ができるメンバーはおらず、予算的にも通訳を依頼することは難しい状況でした。 「ゲストの話が伝わらないのは困る。でも通訳なしでどうすればいいの?」 悩んでいたときに思いついたのが、 生成AIを使ったリアルタイム翻訳 でした。 開発プロセスと工夫 アイデアの共有と仕様の壁打ち まずは自分のやりたいこと・必須要件を明確にしてAIに伝えました。 私の場合は: 大画面スクリーンに投影したい PCで動かしたい 翻訳はリアルタイムで表示したい これをChatGPTに壁打ちすると、 Python + Whisper + GPT-4o + OBS Studio という構成に落ち着きました。 この「仕様を固める工程」が一番大事だと実感しました。 下記のような構成で実装しました。 構成 コード生成 ChatGPTにコードを書いてもらい、そのままコピーペースト。 翻訳の品質が安定しないときは、 「録音時間を少し延ばしたい」「表示を短く区切りたい」 と自然言語で指示してチューニングしました。 ※補足 当時はGPT-4oがリリースされたばかりで、長いコードを生成させると出力が途中で切れ、省略されることもしばしばありました。 そのため、動くように調整するのに時間がかかったのも事実です。 今では CursorやClaudeCode等 があり、長いコードも安定して出力できるので、これから試す方にはこちらをおすすめします。 エラー対応 エラーが出たときは「ここが動きません」と伝えるだけで修正コードを提示してくれるので、ひたすらトライ! 改善 操作方法やレスポンスを調整し、イベント本番で使えるレベルにブラッシュアップしました。 成果と反響 2024年6月、わずか3日で初期版が完成。(業務後に徹夜💪) イベント本番では、ゲストのスピーチをリアルタイムで翻訳しスクリーンに表示。参加者は言語の壁を感じることなく楽しむことができました。 ゲスト様:「スピーチが伝わって嬉しい!」 参加者:「翻訳が自然でわかりやすい!」 社内:「こんなツールを作った社員がいる」と紹介され話題に 自分としても 「AIがあればプログラムができなくても本当に使えるものが作れるんだ」 という大きな自信になりました。 なお、初期版では英語→日本語の翻訳にのみ対応していました。 完成後、このツールはパッケージ化して他のイベントでも使える形に進化させました。 手順書を整備して社内に共有し、これまでに3回以上の大きなイベントで活用されています。 (ちなみにパッケージ化の方法もChatGPTに相談して学びました) さらに 2025年7月には双方向対応(日⇄英)を実現させました 。 当時最新だったClaude Codeを活用することにチャレンジし、そちらで修正を実施。 結果、 わずか1時間程度でアップデートに対応できた のは大きな学びでした。  ちなみに  ClaudeCodeはProプラン(現時点で月17ドル)でも十分に動作し、この規模の改善は簡単にできてしまいました。 200ドルの上位プランも試しましたが、日⇄英対応などはProで十分でしたので、参考にしていただければと思います。 ClaudeCodeでの開発風景です。個人環境(WSL)で実施しており、社内情報・個人情報は一切含まれていません。 OSS公開への挑戦 最終的にはこの翻訳ツールを OSSとして公開しました 。 GitHubを本格的に使ったのは初めてでしたが、ClaudeCodeに教えてもらいながらPushまで実装。 ユーザ名の記載や不要ファイル削除といった細かい点は社外の有識者様からアドバイスいただきましたが、 基本的な部分はClaudeCodeに任せて問題なく進められ、 初心者でもAIを頼れば一人でOSS公開できる ことを実感しました。  #ご協力いただいた有識者様に感謝🙏 ClaudeCodeはMCPでGitHub操作までやってくれるので非常に便利でしたが、 Windowsユーザの場合はWSLの設定が少しハードルでした。 ここはGPTに壁打ちしながら調整し、無事に環境を整えることができました。 「最初は動かなくてもAIに聞けば解決できる」という安心感 を強く感じました。 また、OSS版ではバッチファイルを整備し、コマンド操作に慣れていない人でも簡単に起動できるよう工夫しています。 実際に触っていただいて、環境構築から起動まで短時間で体験していただけたら嬉しいなと思います。 github.com さらに、このOSSをベースに 翻訳UIをClaudeCodeのみで実装したデモ も公開しています。 精度はOSSをそのまま動かすより低いのが課題ですが、イメージは掴んでいただけると思います。 利用にはOpenAIのAPIキーが必要です。 デモページ: https://translate.mintan.org/   使い方イメージ動画: youtu.be  ⚠️ 注意事項   デモページはあくまで個人で試験的に公開しているものです。 精度や安定性はOSSそのままの利用よりも低く、動作保証はしていません。 ご利用は自己責任でお願いします。 私自身も、英語話者とミーティングをするときにこのツールを個人で動かして、 英語を日本語にリアルタイム翻訳しながら理解を深めるのによく活用しています。 イベントだけでなく日常の学びやコミュニケーションにも役立つので、ぜひ試してみてください✨ 動かす→課題→改善:Vibecoding的な実践知 まず動かして課題を明確化する 実際に作ってみて初めて「翻訳の区切り方」や「表示のしやすさ」が課題になることが分かりました。 さらにイベント利用や他者からのフィードバックを通じて、 日⇄英対応 や 専門用語への対応 、 他PCでの導入のしやすさ といった具体的な改善ニーズが見えてきました。 このサイクルが改善を重ねる大きな原動力になっていて、振り返ると デザイン思考やアジャイルの実践に近い進め方 そのものだったなと感じています。 Vibecodingと組み合わせると相性が良く、とても気に入っているやり方です。 誰でも触れるようにする工夫 改善の過程で、コマンド操作に慣れていない人でも使えるように バッチファイルを整備 したり、 OSSとして公開 したり、 ブラウザから試せるデモUI を用意するなど、「触りやすさ」を意識して工夫を重ねました。 現時点の課題と今後の挑戦 現状は openai==0.28.1 に依存しており、最新バージョンだとうまく動作しないという制約があります。 また、 Mac対応が未完了 のため、今後はここを重点的に改善していきたいと考えています。 現時点での個人的ベストプラクティス 今回の開発を通じて、自分なりに見えてきた「AI開発の進め方」を整理しました。 課題から入ること 何かをAIで作ろうとすると、あれもこれもと機能を盛り込みすぎてしまい、結果的に使いにくいものになることが多い。 まず「解決したい課題」を起点にし、 必要最小限の機能に絞って実装する(MVP的に) ことが大切だと感じました。 仕様検討はGPTで壁打ちする 要件を伝えると、構成・技術選定を精度高く返してくれる。 ClaudeやGeminiも試しましたが、仕様整理はGPTが最も的確に感じました。 実装・テストはClaude Codeで進める 仕様を伝えて実装する際は現時点ではClaude Codeが使いやすく、特に改善やデバッグのやりとりがスムーズでした。 改善 → 他者に見せる → (できれば)OSS化 最小構成で作り、改善しながら他の人に使ってもらう。 フィードバックを取り入れ、必要に応じてOSSとして公開できるとより広がりやすいかと思います。 まとめ 今回の経験を通じて、私は 「プログラミングができなくても、AIを頼れば作れる」 ことを強く実感しました。 そして、作ったものをOSSとして公開することで、自分の課題解決が他の誰かの役にも立つ可能性が広がることも学びました。 今までは分厚い技術書を読んで「何をしているか分からないけどとりあえず進める」学習スタイルでした。 しかし今は分からないところをAIに聞きながら、周辺知識も自然に身につけられるようになり、学習が格段にやりやすくなりました。 これは特に初学者やノンプログラマにとって大きな助けになると感じています。 小さな不便を起点にしたチャレンジが、思いがけず大きな広がりにつながる。 この記事が、誰かの 「やってみよう!」 の一歩につながれば嬉しいです。 もしこの記事を読んで「自分も試してみたい」と思った方は、ぜひ感想をシェアしていただけると励みになります 🙌 最後まで読んでいただき、ありがとうございました! 商標 「GPT™」「ChatGPT™」「Whisper™」は、OpenAI社の商標または登録商標です。 「Claude™」は、Anthropic社の商標または登録商標です。 「Cursor™」は、Cursor社の商標または登録商標です。 「OBS Studio™」は、OBS Projectの商標または登録商標です。 「Python®」は、Python Software Foundationの登録商標です。 「Linux®」は、Linus Torvalds氏の米国およびその他の国における登録商標です。 「Windows®」は、米国 Microsoft Corporation の米国およびその他の国における登録商標です。 「Mac®」および「macOS®」は、Apple Inc. の米国およびその他の国における登録商標です。 「GitHub®」は、GitHub, Inc. の米国およびその他の国における登録商標です。 「YouTube™」は、Google LLC の商標または登録商標です。 執筆者 西村奈々(NTT西日本 経営企画部 ミライ事業共創室) R&D組織での経験を活かしつつ、技術起点での事業開発に取り組んでいます。 現在はブロックチェーンとVerifiable Credentialsを活用したデジタルコンテンツの真正性強化と、そのビジネス適用に挑戦中です。 QUINTBRIDGE
はじめに NTT西日本の服部です。本記事はNTT WEST Engineers' Blog 開設にむけて投稿記事レビューのワークフローを爆速で構築した話の第3回の記事となります。 第1回、第2回の記事も読んでいただけるとありがたいです。 第3回となる本記事ではMicrosoft Formsの回答送信を検知してMicrosoft Listsに登録するためのPower Automateついてご紹介します。 本記事は2025年9月時点の情報に基づきます。 ①~概要編~ ②~Microsoft Lists/Microsoft Forms~ ③~Power AutomateによるMicrosoft Listsへの自動登録編~ (本記事) ④~Power Automateによるレビューフロー前編~ ⑤~Power Automateによるレビューフロー中編~ ⑥~Power Automateによるレビューフロー後編~ 第1回でご紹介したワークフローの全体像のうち、以下の図にあたる内容となります。 対象読者 本記事が想定する対象読者は以下の通りです。 自動化に興味がある人 繰り返しの定常的な作業に困っている人 Microsoft Forms/Microsoft Lists/Power Automateを使ってみたい人 背景 NTT WEST Engineers' Blog に向けて、ブログ記事のレビュープロセスを効率化したいという要望を受けて執筆者が検討・構築しました。 SaaSの新規サービスを導入する予算はありませんでしたが、幸い全社的にMicrosoft Forms、Microsoft Lists、Power Automateが利用できる環境だったため、これらを用いてブログ記事レビューのワークフローを構築しました。 前回の記事では投稿者がレビュー依頼をするための以下のフォームについてご紹介しました。 今回はこのフォームの回答内容をMicrosoft Listsに自動登録するためのPower Automateについてご紹介します。 Microsoft Listsに自動登録するためのPower Automate Microsoft Formsの回答内容をMicrosoft Listsに自動登録するためにPower Automateで作成したフローは以下の通りです。 各ステップの内容についてご紹介します。 1.新しい応答が送信されるとき トリガー(フローが実行される条件)として、特定のフォームに新しい応答が送信されるときを指定しています。 ドロップダウンで対象となるフォームを選択することができますが、出てこない場合はForm Idを直接指定することも可能です。 Form IdはフォームのURLから確認することが可能です。 フォームの編集画面から確認する場合は 回答を収集 をクリックするとURLを確認することが可能です。 URLを短縮のオプションを有効にしているとForm Idは記載されないため注意してください。 URLは以下のような形式で <Form Id> にあたる箇所にForm Idが記載されています。 https://forms.office.com/Pages/ResponsePage.aspx?id=<Form Id> 2.応答の詳細を取得する 具体的な回答内容を取得するために必要な処理です。 Form Idの指定方法は新しい応答が送信されるときと同じです。 Response Idは具体的にどの応答内容を取得するか指定します。 コンソールで候補が表示されるため、新しい応答が送信されるときの Response Id を選択すると新しい応答の回答内容を取得することができます。 万が一候補が出てこない場合は以下の評価式を使うことで取得することも可能です。 triggerOutputs()?['body/resourceData/responseId'] 3.項目の作成 ステップ2で回答内容を取得することができたため、その内容を基にMicrosoft Listsに新しいアイテムを追加します。 3-1.サイトのアドレス/リスト名 サイトのアドレス はアイテムを追加したいリストが作成されているSharepointサイトを選択します。 リスト名 は上記で指定したサイトに作成されているリストが表示されます。 3-2.フォームの回答内容を利用する項目 以下のように入力候補としてトリガーに指定したフォームの質問文が出てくるため、対応する質問文が表示されている項目を選択することでその質問に対する回答内容を利用することが出来ます。 3-3.投稿者 Claims 投稿者 Claimsには Responders' Email ( 投稿者 Email と表示されることもあります。)を指定します。 これはフォームの設定で 名前を記録 というオプションを有効にしていると利用でき、Entra IDに紐づいたメールアドレスを取得することが可能です。 Microsoft Formsの設定についての詳細は 前回の記事 を参照ください。 3-4.ステータスValue/レビュアーValue 列の種類が選択肢の場合は <列名>Value と表示されます。 他のPower Automateで処理するために初期値としてステータスは レビュアーアサイン待ち 、レビュアーは 未設定 としています。 詳細は次回ご紹介します。 4.チャットでメッセージを投稿する この処理は必須ではありませんが、回答を受け付けて処理待ちであることを投稿者にMicrosoft Teamsのチャットで通知します。 投稿者: フローボット 、投稿先: フローボットとチャットをする とすると、下図のように Workflows という対象からMicrosoft Teamsのチャットが投稿者宛に届きます。 Recipient は宛先指定で今回はMicrosoft Formsの回答者(投稿者)とするため、 Responders' Email ( 投稿者 Email )としています。 まとめ 今回はMicrosoft Formsの回答送信を検知してMicrosoft Listsに登録するためのPower Automateついてご紹介しました。 次回はレビュアーのアサイン依頼フローについてご紹介します。 執筆者 服部 真智(NTT西日本 ビジネス営業本部所属) 普段はAWS案件の提案、設計、構築等の支援を行っています。 自業務の効率化のためにPython,Power Automate,生成AI等を使って日々試行錯誤しています。 2025 Japan AWS Top Engineers (Services) 商標 Microsoft (Microsoft Entra 、 Microsoft Teams 、 Power Automate 、 Microsoft Lists 、 Microsoft Forms)及び関連する名称並びにそれぞれのロゴは、米国 Microsoft Corporation の米国およびその他の国における商標または登録商標です。
はじめに  NTTビジネスソリューションズの平田です。  API開発の現場では、多数、迅速かつ正確な試験が求められます。しかし、手作業による試験は時間がかかり、ヒューマンエラーのリスクも伴います。本記事では、API試験の自動化ツールであるrunn(らんえぬ)を活用した、API試験の効率化の一例を紹介します。runnは、YAMLを用いた直感的なテストシナリオの記述と、柔軟な自動化機能を持つオープンソースのツールです。  本記事は2025年8月時点の情報に基づきます。 対象読者  本記事が想定する対象読者は以下の通りです。 API開発に携われる方 CI/CDを実装される方 ソフトウェアの試験を実施される方 Amazon Cognitoを利用した開発に携われる方 背景・課題  私が所属するバリューデザイン部システム開発部門で、あるサービスで利用するAPI群の開発・試験を実施しています。このAPI群はAmazon Cognitoから取得したトークンで認可制御を行う機能を持ち、リソース毎(API毎)に利用可能メソッドを設定できるという機能を持ちます。例えば、AというAPIに対し、ユーザXはGETのみ許可、ユーザYはGET/POST/PUT/PATCH/DELETEを許可、といった認可制御を行います。  そのため、認証認可機能は試験の網羅性を高めて品質を担保する必要があり、多くの試験項目が必要です。具体的には、APIが呼び出された時の認可が想定通り(200 OK、403 forbiddenなど)であることを確認しますが、APIが多数あり権限パターンも複数あることから試験の数は膨大になります。  開発当初はPythonのrequestsライブラリを利用したテストコードを作成したり、curlコマンドを使った手作業で試験を実施していました。ただ、テストコードの作成にPythonのスキルが必要だったり、試験にかかる工数が大きいなどの課題を抱えていました。そこで、API試験を効率化するために、runnの評価・導入を行いました。 ツール(runn)の簡単な紹介  runnは、オープンソースで提供されているAPI試験ツールです。シナリオ試験に強みがあります。基本的な利用方法を開発者の方が提供してくださっています。 runnチュートリアル runnクックブック  さくらインターネット株式会社やフリー株式会社のような大手のサービスプロバイダでも活用されています。 さくらのクラウドのAPIにrunnを導入してみた runnを用いたバックエンドテストの試行錯誤の変遷とこれから yamlでテストシナリオを書いてそのまま実行までできるAPIテストツールの新星 “runn” を試してみた  runnの特徴や基本的な使い方は他の記事や本家の記事におまかせすることとし、本記事では具体的な適用例を紹介します。 適用例① Amazon CognitoからIDtokenを取得する  本サービスでAPI経由でにデータを登録する際の基本的なフローは以下です。 Amazon CognitoからIDtokenを取得する APIを呼び出す際に、リクエストヘッダにIDtokenを付与する  このフローをrunnで試験できるよう実装してみました。以下の3ファイルを準備し、コマンドラインから実行します。 runn run .\scenario.yml --verbose  ファイルを3つに分割したのは、再利用のためです。cognito.ymlはAmazon CognitoからIDtokenを取得する関数的なYAML、call_api.ymlはAPIを呼び出すための関数的なYAML、scenario.ymlに実際のシナリオを記述します。 scenario.yml secrets : # --debugオプション指定時に、以下の項目の出力を抑制する - PASSWORD - IdToken vars : # 試験で利用する各種情報 # インラインでパラメータ設定しましたが、実際には外部ファイルに切り出し、 # または環境変数での引き渡しを推奨します COGNITO_URL : "https://cognito-idp.ap-northeast-1.amazonaws.com" COGNITO_CLIENTID : "<CognitoのClientID>" USERNAME : "<CognitoのユーザID>" PASSWORD : "<Cognitoのパスワード>" API_URL : "<試験対象のAPIのBaseURL>" API_KEY : "<試験対象のAPI呼び出しに必要なAPIキー>" steps : # シナリオ get_Cognito_IdToken : desc : Amazon CognitoからIDtokenを取得する include : # 外部ファイルの呼び出し path : cognito.yml bind : IdToken : current.IdToken # Cognitoから取得したIdTokenの参照方法: # - このyamlファイル内で参照:IdToken # - include先のYAMLから参照:parents.IdToken scenario1 : desc : 試験シナリオ1 include : # 外部ファイルの呼び出し path : call_api.yml vars : # 外部ファイル(call_api.yml)に引き渡すパラメータ(引数相当) # 利用するMethod method : "GET" # 試験対象のAPI Path ApiPath : "/v2/entities?type=testdata" # 期待するステータスコード expectedReturnStatuscode : 200 cognito.yml desc : CognitoからIdToken取得 if : included runners : req : '{{ parent.vars.COGNITO_URL }}' steps : GetToken : desc : CognitoからIDトークンを取得する req : / : post : headers : # リクエストヘッダを設定 X-Amz-Target : 'AWSCognitoIdentityProviderService.InitiateAuth' Content-Type : 'application/x-amz-json-1.1' body : # Cognitoの認証に必要なパラメータは、呼び出し元であるscenario.ymlの変数を # parent.vars.変数名 として参照しています。 application/json : { 'ClientId' : '{{parent.vars.COGNITO_CLIENTID}}' , 'AuthFlow' : 'USER_PASSWORD_AUTH' , 'AuthParameters' : { 'USERNAME' : '{{parent.vars.USERNAME}}' , 'PASSWORD' : '{{parent.vars.PASSWORD}}' } } test : current.res.status == 200 bind : IdToken : current.res.body.AuthenticationResult.IdToken call_api.yml desc : APIを呼び出すYAML if : included runners : req : '{{ parent.vars.API_URL }}' steps : call_api_with_Idtoken : req : '{{ vars.ApiPath }}' : '{{ vars.method }}' : headers : # リクエストヘッダを設定 Accept : 'application/json' x-api-key : '{{ parent.vars.API_KEY }}' # Cognitoから取得したTokenを送信 TOKEN : '{{ parent.IdToken }}' User-Agent : 'runn' # 期待するステータスコードと比較 test : current.res.status == vars.expectedReturnStatuscode 実行結果は以下のようになりました。 === [No Description] (.\scenario.yml) --- Amazon CognitoからIDtokenを取得する (get_Cognito_IdToken) ... ok === CognitoからIdToken取得 (cognito.yml) --- CognitoからIDトークンを取得する (GetToken) ... ok --- 試験シナリオ1 (scenario1) ... ok === APIを呼び出すYAML (call_api.yml) --- (call_api_with_Idtoken) ... ok 1 scenario, 0 skipped, 0 failures 適用例② データの加工  シナリオの中で、あるAPIで取得したデータを後続のAPIに引数として渡したいケースがあります。このとき、取得したデータを加工して後続のAPIに渡せると便利です。このようなニーズに対して、runnは expr lang によるデータの加工が可能です。  例えば、あるAPIの応答に含まれるLocationヘッダの一部を切り出してSubscriprionId変数に代入したい場合、以下のように記述します。 SubscriptionId: 'trimPrefix(current.res.headers["Location"][0],"/v2/subscriptions/")'   具体的には、Locationヘッダが以下のような結果の場合、 /v2/subscriptions/ を削除して(trimして)、 ABCD だけをSubscriptionId変数に代入できます。 Location: /v2/subscriptions/ABCD デメリット  大変便利なrunnですが、実際に利用してみて気になる点もあります。(もしかしたら私たちがまだrunnを使いこなせてないだけかもしれません) 条件分岐機能がない  例えば、ある条件を満たしたらリクエストに特定のヘッダを追加する、といった条件分岐の機能が見つかりませんでした。goからの利用であれば条件分岐を利用できるようですが、YAMLのみでは難しいようです。 YAMLの書き方がシビア、構文エラーの原因が特定しづらい  YAMLにインデントずれや必須項目の漏れがあるとエラーになりますが、どこで間違ったのか、何が足りないのかを特定がしにくい点があります。また、予約語(steps:、req:などの命令)なのか識別子(例:ステップの名前)がわかりづらい点もあります。慣れるまでに時間がかかるかもしれません。 まとめ  本記事では、runnを利用したAPI試験の実装例を紹介しました。  当初は構文エラーと原因調査に悩まされ、シンプルな試験が動くようになるまで時間を要しました。しかし、その後は出来上がったYAMLを型紙にして、コピペ+修正で試験項目をどんどん増やせます。  最終的には約500項目の試験を実装し、シナリオ試験を約20分で一周できるようになり、試験効率が向上しました。また、リリース作業時の動作確認にも活用しており、リリース作業に伴う影響発生の早期検知にも役立っています。  runnにはそのほかにもあらかじめ準備されたJSONテンプレート内の値を変更してPOSTしたり、CI(継続的インテグレーション)に組み込んだりと便利な機能があります。まだまだ機能を使いこなせていませんが、もっと使い込んでみたいと思います。 執筆者  平田賀一(NTTビジネスソリューションズ(株) バリューデザイン部 システム開発部門) PaaS/SaaSの開発・運用、社内案件のコンサル、エンジニア育成、NTT西日本Engineers' Blogの運営などに携わっています。 技術士(情報工学部門)/2025 Japan All AWS Certifications Engineers 参考資料・出典 本記事を執筆するにあたり、以下のサイトを参考にしました。 runnチュートリアル runnクックブック さくらのクラウドのAPIにrunnを導入してみた runnを用いたバックエンドテストの試行錯誤の変遷とこれから yamlでテストシナリオを書いてそのまま実行までできるAPIテストツールの新星 “runn” を試してみた expr-langリファレンス 商標 「AWS」「Amazon Cognito」は、Amazon Web Services,Inc.またはその関連会社の商標です。 記載の会社名・製品名はそれぞれの会社の商標もしくは登録商標です。
はじめに NTT西日本の服部です。本記事はNTT WEST Engineers' Blog開設にむけて投稿記事レビューのワークフローを爆速で構築した話の第2回の記事となります。 概要は 第1回の記事 を読んでいただけるとありがたいです。 第2回となる本記事ではレビュー依頼をあげるためのMicrosoft Formsとレビューの進捗管理をするためのMicrosoft Listsについてご紹介します。 本記事は2025年9月時点の情報に基づきます。 ①~概要編~ ②~Microsoft Lists/Microsoft Forms~ (本記事) ③~Power AutomateによるMicrosoft Listsへの自動登録編~ ④~Power Automateによるレビューフロー前編~ ⑤~Power Automateによるレビューフロー中編~ ⑥~Power Automateによるレビューフロー後編~ 第1回でご紹介したワークフローの全体像のうち、以下の図にあたる内容となります。 対象読者 本記事が想定する対象読者は以下の通りです。 自動化に興味がある人 繰り返しの定常的な作業に困っている人 Microsoft Forms/Microsoft Lists/Power Automateを使ってみたい人 背景 NTT WEST Engineers' Blog に向けて、ブログ記事のレビュープロセスを効率化したいという要望を受けて執筆者が検討・構築しました。 SaaSの新規サービスを導入する予算はありませんでしたが、幸い全社的にMicrosoft Forms、Microsoft Lists、Power Automateが利用できる環境だったため、これらを用いてブログ記事レビューのワークフローを構築しました。 本記事では1.レビュー依頼をあげるためのMicrosoft Formsと2.レビューの進捗管理をするためのMicrosoft Listsについてご紹介します。 1.レビュー依頼をあげるためのMicrosoft Forms 投稿者がレビューを申し込む用に以下のフォームを作成しました。 特別変わったことをしているわけではありませんが、フォーム作成の上で工夫したポイントをご紹介します。 1-1.回答者の情報を自動で収集する 今回のフォームは社内向けに公開されるフォームになるため、回答できるユーザーをEntraIDのテナントに参加しているユーザーに限定します。 また、後の処理でメールアドレス等を利用したいので回答者の情報も自動的に収集します。 作成しているFormsの 設定 から <テナント名>内のユーザーのみが回答できます。 と 名前を記録 のオプションを有効化することで実装できます。 1-2.規約への同意などを求める 規約への同意などの意思確認をするための質問を実装したい場合は、質問の種類を 選択肢 にした上で 複数回答 と 必須 のオプションを有効にした上で選択肢を同意するなど1つにすることで簡単に実装出来ます。 1-3.お礼のメッセージをカスタマイズ Formsの回答が送信された後に表示される画面で案内したいことがあるなどの場合には下図における赤枠部分のテキストを編集することが可能です。 設定 → お礼のメッセージをカスタマイズ を有効にすると回答後に表示されるテキストを編集できるようになります。 2.レビューの進捗管理をするためのMicrosoft Lists レビューの進捗管理をするために以下のようなリストをSharepoint上に作成しました。 各列の詳細は以下の通りです。 列の名前 列の種類 概要 ID 数値 デフォルトで作成されている列 タイトル 1 行テキスト 記事のタイトル/デフォルトで作成されている列 概要 複数行テキスト 記事の概要 投稿者 ユーザーまたはグループ 投稿者のメールアドレス 下書きプレビューURL 複数行テキスト ブログ記事の下書きを共有するためのURL 自由記述 複数行テキスト 備考欄 レビュアー 選択肢 レビュー担当者のメールアドレス ・未設定 ・レビュアー1のメールアドレス ・レビュアー2のメールアドレス 以下略 ステータス 選択肢 レビューの進捗状況 ・レビュアーアサイン待ち ・レビュー待ち ・差し戻し(修正待ち) ・レビュー完了 ・投稿完了 ・却下/消滅 更新日時 日付と時刻 デフォルトで作成されている列 登録日時 日付と時刻 デフォルトで作成されている列 リストについても作成の上で工夫したポイントをご紹介します。 2-1.投稿者 / レビュアー 投稿者についてはMicrosoft Formsで回答者の情報を自動で収集するようにしており、この項目ではUPN(メールアドレス)を登録しています。 次回解説予定のため、そうなんだくらいの認識で大丈夫です。 レビュアーについてもワークフローの中でメールアドレスを利用するため、列の種類をユーザーまたはグループとしても問題ありません。 しかし今回構築したワークフローではレビュアーの指定は運営者が手動で設定する設計としており、入力ミスで関係がないユーザーがレビュアーに設定されてしまう可能性があったため、レビュアーについては選択肢としました。 2-2.下書きプレビューURL Microsoft ListsにはURLという列の種類が元々存在していますが、URLには255文字の文字数制限があります。 万が一256文字以上になったとしてもエラーを回避できるように複数行テキストとしています。 通常の複数行テキストの場合はリンクとして機能しませんが、列の書式設定を以下のようにすることでリンクとして機能させることができるようになります。 { " $schema ": " https://developer.microsoft.com/json-schemas/sp/v2/column-formatting.schema.json ", " elmType ": " a ", " txtContent ": " @currentField ", " attributes ": { " target ": " _blank ", " href ": " = @currentField " } } 列の書式設定の変更は設定したい列をクリックし、 列の設定 → この列の書式設定 → 詳細モード を選択することでJSON形式で書式設定をすることができるようになります。 設定欄に上記のJSONをコピー&ペーストして保存をクリックすることで該当列の文字列はURLリンクとして機能するようになります。 2-3.ステータスでグループ化 レビュー依頼リストを見やすくするためにステータスでグループ化することで表示方法を変更しています。 下図はステータスの値でグループ化されている状態です。 2-4.ID/更新日時/登録日時 これらの列はデフォルトで作成されている列ですが、初期設定では表示されていない列です。 列の表示/非表示や順番を変更したい場合は、 すべてのアイテム → 現在のビューの編集 をクリックします。 以下の画面の 列 の項目で表示/非表示や順番を変更することが可能です。 まとめ 今回は本ブログ開設にむけて構築した投稿記事レビューのワークフローのうち、レビュー依頼用のMicrosoft Formsと進捗管理のMicrosoft Listsをご紹介しました。 次回はFormsの回答内容をListsに自動登録するためのPower Automateについてご紹介します。 執筆者 服部 真智(NTT西日本 ビジネス営業本部所属) 普段はAWS案件の提案、設計、構築等の支援を行っています。 自業務の効率化のためにPython,Power Automate,生成AI等を使って日々試行錯誤しています。 2025 Japan AWS Top Engineers (Services) 商標 Microsoft (Microsoft Entra 、 Microsoft Teams 、 Power Automate 、 Microsoft Lists 、 Microsoft Forms)及び関連する名称並びにそれぞれのロゴは、米国 Microsoft Corporation の米国およびその他の国における商標または登録商標です。
はじめに 2025年現在、AI駆動によるアプリケーション開発のパラダイムシフトが進行しています。 今後、エンタープライズ組織においてAIを活用したアプリの内製化が一層進むと考えられます。 本記事では、チーム開発を行う際に必要性の高い「Dev Containers」を解説し、AIコーディング環境も含めた開発環境のセットアップ手順をご紹介します。 また、1台のローカルPC内で、ローカルOSと「Dev Container」がどのように連携して動作するのかも解説します。 用語補足 Dev Containers は、Visual Studio Code の拡張機能名を指します Dev Container は、その拡張機能で利用する開発用のコンテナ単体を指します 対象読者 本記事の対象読者として下記の方々を想定します。 アプリケーション開発、チーム開発を行う AIエージェントによるコーディングでDev Containerを使ってみたい Dev Containerのセットアップ手順や仕組みを知りたい 背景・課題 アプリケーションの開発環境には、開発ツールや依存ソフトウェアの複雑なバージョンの組み合わせが存在し、プロジェクト固有の構成で環境構築することが求められます。同じプロジェクトのメンバー間ではバージョン構成を統一する必要があり、異なるプロジェクトであれば環境の分離が必要です。 チーム開発の場合、複数メンバーで開発環境を統一しておかないと、動作差異や不具合発生につながります。 仮に1人で複数プロジェクトの開発を行う場合でも、1台のPC環境の中でプロジェクトごとの環境分離が必要です。   それから、AI駆動開発で用いられるClaude CodeやGemini CLIなどのAIエージェントは便利な一方で、rmコマンドの自動実行により重要ファイルが削除されてしまう危険性があります。 また、AIエージェントがソフトウェアやライブラリを自動インストール・自動バージョンアップすることもあり、意図せず環境を破壊してしまう危険性があります。このため、隔離された環境の中でAIエージェントを動作させることが求められます。   チーム開発やAI駆動開発の際に求められる開発環境の分離は、Dev Containersで実現できます。 Dev Containersとは Dev Containersは、Visual Studio Codeで利用できる拡張機能で、Dockerコンテナを活用して開発環境を分離できます。開発に必要な環境(Node.js、Python、データベースなど)を設定ファイルに記述することで自動構築できます。 Dev Containersにより、同じ環境が自動構築されるため、環境差異によるトラブルを防げます。開発環境はコンテナ内にインストールされるためローカルOSを汚さず、プロジェクトごとにDev Containerを分けられます。これにより、異なるバージョン構成の環境を手元に複数保持できます。 現場でよくある問題 アプリケーション開発の現場で、こんな経験はありませんか? 1. 「私の環境では動くのに...」問題 # 開発者A: Node.js 16.x + npm 7 # 開発者B: Node.js 18.x + npm 9 # 本番環境: Node.js 14.x + npm 6 2. ローカル環境の汚染問題 # プロジェクトAのために npm install -g create-react-app@4.0.0 # プロジェクトBは古いバージョンが必要... npm install -g create-react-app@3.0.0 # 衝突! 3. 新メンバーの環境構築地獄 「環境構築の手順書通りやったけど動きません」 「あ、それPostgreSQLのバージョンが...」 「Redisも入れないと...」 「環境変数の設定が...」 → 丸2日かかる 実践的なメリット 1. 開発効率の向上 環境構築 : 2日 → 10分 (私の経験によるケース。状況により時間は変化) トラブルシューティング : 環境起因の問題がほぼゼロに 実験的な変更 : 壊れてもDev Containerのリビルドで即復旧 2. チーム開発の改善 # 新メンバー参加時 git clone [repository] code . # VS Code起動 # 「コンテナで開きますか?」→ Yes # 10分後には開発開始! 3. 本番環境との一致 # Dockerfile(本番用)とdevcontainer.json(開発用)で # 同じベースイメージを使用 FROM node:22-alpine Dev Containersを使うべきシーン AI駆動開発 AIエージェントの試行錯誤を隔離し、ローカル環境の破壊を防ぐ チーム開発 同一環境を即時再現し、動作差異と初期構築時間を削減 複数プロジェクトの並行開発 依存関係とバージョンをプロジェクト単位で分離 特定バージョンの言語/DBが必要 任意のバージョンを固定し、安全に切替可能 技術検証・試行錯誤 互換性を無視した変更を行ってもリビルドで元に戻せる Dev Containerの構築手順 解説用にシンプルな環境を例に、以下をセットアップします。 Node.js TypeScript React Vite Claude Code 1. 事前準備 以下をローカルPCにインストールしてください Docker Desktop または Rancher Desktop などのDocker動作環境 Visual Studio Code(VS Code) VS Codeでプロジェクトフォルダを開いておく 2. Dev Container構成ファイルを作成 プロジェクトフォルダに .devcontainer フォルダを作成 .devcontainer フォルダ内に devcontainer.json ファイルを作成 以下、devcontainer.json { "name": "Node.js & TypeScript & React & Vite with Claude Code", "image": "mcr.microsoft.com/devcontainers/typescript-node:22", "features": { "ghcr.io/anthropics/devcontainer-features/claude-code:1": {} }, "postCreateCommand": "npm create vite@7.1 . -- --template react-ts && npm install" }   devcontainer.jsonの設定解説 項目 値 解説 name "Node.js & TypeScript & React & Vite with Claude Code" Dev Containerの名前を記載 image "mcr.microsoft.com/devcontainers/typescript-node:22" 使用するDockerイメージを指定しています。Microsoft Container Registry(mcr)から提供される公式のTypeScript/Node.js開発用イメージで、Node.js 22系がプリインストールされています。TypeScriptの開発に必要なツールが含まれた環境です。 features "ghcr.io/anthropics/devcontainer-features/claude-code:1": {} Dev Container Featuresを使って追加機能をインストールしています。ここではGitHub Container Registry(ghcr)からAnthropic社のClaude Code バージョン1を追加します。 postCreateCommand "npm create vite@7.1 . -- --template react-ts && npm install" コンテナ作成後に自動実行されるコマンドです。Vite 7.1を使ってReact+TypeScriptテンプレートのプロジェクトを現在のディレクトリ( . )に作成し、その後 npm install で依存関係をインストールします。 3. Dev Container の起動 開発コンテナー: コンテナーでリビルドして再度開く F1 または Ctrl+Shift+P (Mac: Cmd+Shift+P ) 「Dev Containers: Rebuild and Reopen in Container」を選択 コンテナのビルドと起動を待つ 以下の処理が自動実行されます: Dockerイメージがダウンロードされます コンテナが起動します Claude Codeがインストールされます Viteプロジェクトの作成( postCreateCommand の実行) 以下が表示されたら y を入力してください 以下が表示されたら、.devcontainerを保持するため「Ignore files and continue」を選択してください npm依存関係がインストールされます 以下が表示されたら任意のキーを押してください   4. 開発ツール:Viteの起動 VS Code内でターミナルを開く 開発ツール:Viteの起動 npm run dev -- --host 3. 起動メッセージの確認 5. ブラウザで接続 アプリケーションへのアクセス ポートフォワーディングの確認 VS Codeが自動的にポート5173をフォワーディングします 「ポート」タブで確認可能(VS Codeの下部パネル) ブラウザでアクセス 方法1: ターミナルのURLをCtrl+クリック(Cmd+クリック) 方法2: ブラウザで直接 http://localhost:5173 を開く 方法3: VS Codeの「ポート」タブから ポート5173の行を右クリック 「Open in Browser」を選択 React + Viteアプリの確認 Vite + Reactのデフォルトページが表示されます   トラブルシューティング よくある問題と解決方法 問題 解決方法 コンテナが起動しない Docker Desktopなど、コンテナエンジンが起動しているか確認 ポート5173にアクセスできない VS Codeの「ポート」タブでポートが開いているか確認 ブラウザが自動で開かない 手動で http://localhost:5173 にアクセス 6. AIコーディングエージェント:Claude Codeを起動 VS Code内でターミナルを開く Claude Codeの起動 claude 好みのテキストスタイルを選ぶ Claude Codeが起動しました Dev Container環境の動作フロー 本記事のDev Containerについて、動作の流れを説明します ① git clone GitHubリポジトリからソースコードと .devcontainer/devcontainer.json をローカルPCにクローンします。(git cloneの解説は割愛) 統一されたリモートリポジトリをチームメンバーがクローンすることで、メンバー全員が同じ開発環境に統一されます。 ② Dev Container起動時の自動マウント ①でクローンしたプロジェクトフォルダ(マウント元)が、Dev Container環境内に自動マウントされます。 ③ コンテナ自動構築 ②のマウント先の .devcontainer/devcontainer.json に基づき、コンテナレジストリからコンテナイメージがダウンロードされ、Dev Container環境が自動構築されます。 また、Node.jsやVite、Claude Codeなど、開発に必要なツール・依存関係が自動インストールされます。 ④ 開発ツール起動 Dev Containerに接続されたターミナルで、 npm run dev -- --host コマンドを実行し、開発サーバー(Vite)を起動します。 ⑤ ポートフォワーディング コンテナ内でViteのデフォルトポート5173が自動検出され、ローカルPCのポート5173に自動的にフォワーディングされます。 ⑥ アプリ動作確認 ローカルPCのWebブラウザ から、ポートフォワーディング経由でアプリ動作確認ができます。   おわりに 本記事では、Dev Containersによる開発環境の分離と再現性の確保、AIエージェントを安全に活用するためのシンプルな構成と構築手順を紹介しました。また、ローカルPC内でDev Containerがどのように動作するか図解で解説しました。ぜひ、記事のdevcontainer.jsonをコピーして動かし、Viteを起動するところまで試してみてください。チームで共有し、必要な機能を小さく追加しながら、運用しやすいプロジェクト標準へと整備していきましょう。 執筆者 三島 映人 NTT西日本グループのサービス開発におけるテックリードやプロジェクトマネジメント、アプリケーション開発組織の技術統括、エンジニア育成を行っています。 PMP、MBA等を保有。趣味は自作キーボードの設計。 参考資料・出典 本記事を執筆するにあたり、以下のサイトを参考にしました。 code.visualstudio.com github.com 商標 Windows / Visual Studio Code は、Microsoft Corporationの商標もしくは登録商標です Mac は、Apple Inc.の商標もしくは登録商標です GitHub は、GitHub Inc.の商標もしくは登録商標です Docker / Docker Desktop は、Docker Inc.の商標もしくは登録商標です Rancher は、SUSE LLCの商標もしくは登録商標です Claude / Claude Code は、Anthropic PBCの商標もしくは登録商標です Gemini は、Google LLCの商標もしくは登録商標です Node.js は、OpenJS Foundationの商標もしくは登録商標です React は、Meta Platforms, Inc.の商標もしくは登録商標です PostgreSQL は、PostgreSQL の商標もしくは登録商標です Redis は、Redis Ltd.の商標もしくは登録商標です Python は、Python Software Foundationの商標もしくは登録商標です MySQL はOracle Corporationの商標もしくは登録商標です MongoDB はMongoDB Inc.の商標もしくは登録商標です PMP は、Project Management Institute, Inc. の商標もしくは登録商標です