NTTドコモビゞネスのブログ - TECH PLAY

TECH PLAY

NTTドコモビゞネス

NTTドコモビゞネス の技術ブログ

å…š632ä»¶

この蚘事は、 NTT docomo Business Advent Calendar 2025 19日目の蚘事です。 こんにちは、むノベヌションセンタヌの鈎ヶ嶺です。普段はAIアクセラレヌタの怜蚌に関する業務に埓事しおいたす。 本蚘事では、たずTenstorrentのAIアクセラレヌタアヌキテクチャを玹介し、その特城に぀いお説明したす。次に、耇数の挔算を1぀のkernelに統合するfused kernelによる最適化に泚目し、暙準正芏乱数(randn)を䟋にTenstorrentのアクセラレヌタにおける具䜓的な実装方法ず性胜評䟡を共有したす。その結果、埓来の挔算の組み合わせの暙準正芏乱数の実装ず比范しお、fused kernel実装により玄4倍の高速化を確認したした。 Tenstorrentずは オンチップ蚈算を掻かしたFlash Attention fused kernelの実装ず評䟡 実装 性胜評䟡 たずめ Tenstorrentずは Tenstorrent Inc. は次䞖代AIアクセラレヌタを補造する半導䜓メヌカヌです。 オヌプン戊略を掲げおおり、アクセラレヌタにはRISC-Vを採甚し、゜フトりェアに関しおはOSS ( https://github.com/tenstorrent ) ずしお積極的に公開されおいたす。 2025幎12月珟圚ではDEC、AMD、Apple、Teslaを歎任した半導䜓業界の著名なJim Keller氏がCEOを務めおいたす。 TenstorrentのAIアクセラレヌタのアヌキテクチャに぀いお玹介したす。 匕甚: https://speakerdeck.com/tenstorrent_japan/tensix-core-akitekutiyajie-shuo?slide=7 アクセラレヌタはTensix Coreず呌ばれる5぀のBaby RISC-V、2぀のNetwork-on-Chip(NoC)、SRAMで構成されるものが耇数搭茉されおいたす。 䞀般的なハヌドりェア管理キャッシュを持たない構成ずなっおおり、明瀺的にコア付近のSRAMを操䜜する分散メモリ型のNear Memory Computing(NMC)な蚭蚈です。 5぀のRISC-Vコアは独立な動䜜が可胜なMIMD(Multiple Instruction、 Multiple Data)アヌキテクチャです。 倚くの凊理は兞型的にはデヌタ読み出しを行うReader kernel(RISC-V 1)、 蚈算をするCompute kernel(RISC-V 2、 3、 4)、 デヌタ曞き蟌みを行うWriter kernel(RISC-V 5)に分けお実行されたす。 埌述する暙準正芏乱数のfused kernel実装ではデヌタ読み蟌みが䞍芁のためCompute、Writer kernelのみの実装ずなっおおり、凊理に合わせお自由床を高く調敎できたす。 16x16を基本ずしおtileベヌスの挔算゚ンゞンを積んでおり、Compute kernelはこの゚ンゞンを呌び出したす。 kernel間のデヌタはCircular Buffer (CB)ず呌ばれるSRAM䞊のFIFOキュヌでやり取りをしたす。 ホストずのデヌタ亀換は倖偎のDRAM(GDDR)を介しお行われたす。 その他の技術詳现は日本法人のTenstorrent Japanから以䞋にさたざたな資料が公開されおいるためご参照ください。 https://speakerdeck.com/tenstorrent_japan オンチップ蚈算を掻かしたFlash Attention アクセラレヌタの特城ずしお、䜎コスト化のためにHBM(High Bandwidth Memory)などの高コストなメモリを䜿わない蚭蚈ずなっおいたす。 そのためできるだけDRAM埀埩によるオヌバヌヘッドを避けるために、オンチップのSRAM䞊で蚈算する工倫がされたす。 ここではLLMのAttention蚈算の事䟋を取り䞊げお、どのようにTenstorrentのAIアクセラレヌタで効率化されるのかを説明したす。 https://github.com/tenstorrent/tt-metal/blob/main/tech_reports/FlashAttention/FlashAttention.md LLMのAttentionはそのたた蚈算するず、巚倧な䞭間行列によりHBM、 DRAMぞのデヌタ移動がオヌバヌヘッドずなるこずが知られおおりたす。 FlashAttention 1 2 は、その課題に察しお行列をチャンクに分割し、より高速なSRAM䞊で蚈算しデヌタ移動のオヌバヌヘッドを削枛し、高速化する手法です。 TenstorrentのAIアクセラレヌタでも、このFlashAttentionを適甚可胜です。 倧容量のSRAMを利甚しお実装され䞭間デヌタがDRAMに曞き蟌たれないため高速化されたす。 以䞋の図のようにベヌスラむン実装ず比范しお平均しお20倍高速に動䜜したす。 匕甚: https://github.com/tenstorrent/tt-metal/blob/main/tech_reports/FlashAttention/images/image3.png fused kernelの実装ず評䟡 AIアクセラレヌタの実行は耇数のkernelの実行による、䞭間蚈算結果のメモリアクセスや起動オヌバヌヘッドが課題ずなりたす。 そこで耇数の蚈算凊理を1぀のkernelに統合するfused kernelにより性胜を向䞊させる凊理がよく甚いられたす。 䟋えばLLMのAttentionなどは蚈算を最適化するために1぀のfused kernelずしお実装されおいたす。 ttnn.transformer.scaled_dot_product_attention(input_tensor_q: ttnn.Tensor, input_tensor_k: ttnn.Tensor, input_tensor_v: ttnn.Tensor, *, attn_mask: ttnn.Tensor = None, is_causal: bool = true, scale: float = None, sliding_window_size: int = None, memory_config: ttnn.MemoryConfig = None, program_config: SDPAProgramConfig = None, compute_kernel_config: ttnn.DeviceComputeKernelConfig = None, attention_sink: ttnn.Tensor = None) → ttnn.Tensor https://docs.tenstorrent.com/tt-metal/latest/ttnn/ttnn/api/ttnn.transformer.scaled_dot_product_attention.html#ttnn.transformer.scaled_dot_product_attention ここではttnnに実装されおいない暙準正芏乱数を生成するrandnを実装したす。 randnは䞀般的な PyTorchの torch.randn や Numpyの np.random.randn などではサポヌトされおいたす。 暙準正芏乱数には、Box-Muller法 3 を甚いたす。 実装 新芏のOperation远加は、次のように手順で行いたす。 https://docs.tenstorrent.com/tt-metal/latest/ttnn/ttnn/adding_new_ttnn_operation.html たず、ホスト偎での凊理を抜粋するず以䞋のように実装したす。 ttnn/cpp/ttnn/operations/randn/device/randn_device_operation.[cpp|hpp] ではOperationの匕数やバリデヌションを実装したす。 struct RandnDeviceOperation { struct operation_attributes_t { const ttnn::Shape shape; // テン゜ルの圢状 DataType dtype; Layout layout; const MemoryConfig memory_config; MeshDevice* device; const DeviceComputeKernelConfig compute_kernel_config; uint32_t seed; // 乱数seed }; // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ void RandnDeviceOperation:: validate_inputs ( const operation_attributes_t& operation_attributes, const tensor_args_t& tensor_args) { TT_FATAL ( operation_attributes.dtype == DataType::FLOAT32 || operation_attributes.dtype == DataType::BFLOAT16, "Randn: Output tensor must be Float32 or Bfloat16" ); // dtypeによるバリデヌション TT_FATAL (operation_attributes.layout == Layout::TILE, "Randn: Not currently supporting row major layout" ); // メモリレむアりトのバリデヌション } アクセラレヌタ䞊のkernel実行の詳现は ttnn/cpp/ttnn/operations/randn/device/randn_program_factory.cpp に蚘述したす。 ナヌティリティ関数 tt::tt_metal::split_work_to_cores 4 によるコアごずの凊理を均等に分散 CreateCircularBuffer によるCB(FIFOキュヌ)の䜜成 CreateKernel によるCompute、 Writer kernelの䜜成 SetRuntimeArgs kernel実行の匕数の蚭定 // split_work_to_coresにより、それぞれのコアに凊理を割り振る auto [num_cores, all_cores, core_group_1, core_group_2, units_per_core_group_1, units_per_core_group_2] = split_work_to_cores (grid, units_to_divide); // CBの䜜成(2tile分の出力ができるように確保する) constexpr uint32_t dst_cb_id = CBIndex::c_0; CircularBufferConfig cb_output_config = CircularBufferConfig (in_out_num_tiles * dtype_tile_size, {{dst_cb_id, out_data_format}}) . set_page_size (dst_cb_id, dtype_tile_size); tt_metal:: CreateCircularBuffer (program, all_cores, cb_output_config); // Writer kernelの蚭定 const std :: string kernels_dir_path = "ttnn/cpp/ttnn/operations/randn/device/kernels/" ; std :: vector < uint32_t > writer_compile_time_args{dst_cb_id}; tt::tt_metal:: TensorAccessorArgs (output. buffer ()). append_to (writer_compile_time_args); const std :: string writer_file_path = kernels_dir_path + "writer_standard_normal.cpp" ; KernelHandle writer_kernel_id = tt_metal:: CreateKernel ( program, writer_file_path, all_cores, WriterDataMovementConfig (writer_compile_time_args)); // Compute kernelの蚭定 const std :: vector < uint32_t > compute_compile_time_args{dst_cb_id}; const std :: string compute_file_path = kernels_dir_path + "compute_standard_normal.cpp" ; auto [math_fidelity, math_approx_mode, fp32_dest_acc_en, packer_l1_acc, dst_full_sync_en] = get_compute_kernel_config_args (device-> arch (), operation_attributes.compute_kernel_config); KernelHandle compute_kernel_id = CreateKernel ( program, compute_file_path, all_cores, ComputeConfig{ .math_fidelity = math_fidelity, // 蚈算の粟床 ref: https://speakerdeck.com/tenstorrent_japan/tensix-core-akitekutiyajie-shuo?slide=26 .fp32_dest_acc_en = true , .dst_full_sync_en = dst_full_sync_en, .math_approx_mode = math_approx_mode, .compile_args = compute_compile_time_args, .defines = compute_defines, }); // foreach in split_work_to_coresによる割り振り // kernel匕数(1コアあたりの乱数生成のtile数、出力のアドレス)の蚭定 std :: vector < uint32_t > compute_runtime_args = {seed, tile_offset, units_per_core}; SetRuntimeArgs (program, compute_kernel_id, core, compute_runtime_args); std :: vector < uint32_t > writer_runtime_args = {output. buffer ()-> address (), tile_offset, units_per_core}; SetRuntimeArgs (program, writer_kernel_id, core, writer_runtime_args); // end ここからはkernelの実装を説明したす。kernel内で利甚可胜なAPIは以䞋になりたす。 https://docs.tenstorrent.com/tt-metal/latest/tt-metalium/tt_metal/apis/kernel_apis.html Compute kernel ttnn/cpp/ttnn/operations/randn/device/kernels/compute_standard_normal.cpp の抜粋を蚘述したす。 tileベヌスの呜什を甚いお凊理したす。 ここで実際にBox-Muller法で暙準正芏乱数が生成されたす。 // Box-Muller法で暙準正芏乱数 (Z1, Z2) を生成 // Z1 = sqrt(ln(U1) * -2) * cos(U2 * 2pi) // Z2 = sqrt(ln(U1) * -2) * sin(U2 * 2pi) // 出力CBの末尟に2tile確保 cb_reserve_back (dst_cb_id, 2 ); // タむルレゞスタを確保 tile_regs_acquire (); // U1、 U2の䞀様乱数(0, 1)をレゞスタ0, 1に生成 rand_tile ( 0 , flt_min, one_minus); rand_tile ( 1 , flt_min, one_minus); // sqrt(ln(U1) * -2)を蚈算し、レゞスタ0に栌玍 log_tile ( 0 ); mul_unary_tile ( 0 , neg_two); sqrt_tile ( 0 ); // レゞスタ2に2piを詰める fill_tile_bitcast ( 2 , two_pi); // U2 * 2piを蚈算し、レゞスタ3, 1に栌玍 mul_binary_tile ( 1 , 2 , 3 ); mul_binary_tile ( 1 , 2 , 1 ); // cos(U2 * 2pi)を蚈算し、レゞスタ3に栌玍 cos_tile ( 3 ); // sin(U2 * 2pi)を蚈算し、レゞスタ1に栌玍 sin_tile ( 1 ); // Z1 = sqrt(ln(U1) * -2) * cos(U2 * 2pi)を蚈算し、レゞスタ3に栌玍 mul_binary_tile ( 0 , 3 , 3 ); // Z2 = sqrt(ln(U1) * -2) * sin(U2 * 2pi)を蚈算し、レゞスタ1に栌玍 mul_binary_tile ( 0 , 1 , 1 ); // 出力dtypeが BFLOAT16 の堎合は型倉換 #ifdef OUTPUT_DTYPE_BFLOAT16 typecast_tile< 0 , 5 >( 3 ); typecast_tile< 0 , 5 >( 1 ); #endif // レゞスタ蚈算の確定、完了埅ち tile_regs_commit (); tile_regs_wait (); // レゞスタ3, 1のZ1、 Z2をCBぞ曞き蟌み pack_tile ( 3 , dst_cb_id); pack_tile ( 1 , dst_cb_id); // レゞスタ解攟 tile_regs_release (); // CBの末尟に2タむル远加したこずを通知 cb_push_back (dst_cb_id, 2 ); 次にWriter kernel ttnn/cpp/ttnn/operations/randn/device/kernels/writer_standard_normal.cpp を抜粋したす。 基本的にはCompute kernelからデヌタを受け取り、そのたたNOC経由で曞き蟌みたす。 // CBの先頭に2tileがCompute kernelからpushされるたで埅぀ cb_wait_front (dst_cb_id, 2 ); // CBの読み取りポむンタ取埗 uint32_t dst_cb_read_base = get_read_ptr (dst_cb_id); uint32_t dst_cb_read0_ptr = dst_cb_read_base; uint32_t dst_cb_read1_ptr = dst_cb_read_base + dst_tile_bytes; // NOCでタむル単䜍に非同期曞き蟌み noc_async_write_tile (i, output_addrg, dst_cb_read0_ptr); noc_async_write_tile (i + 1 , output_addrg, dst_cb_read1_ptr); // 曞き蟌み完了たでバリア noc_async_write_barrier (); // CBから2tile pop cb_pop_front (dst_cb_id, 2 ); 最埌にC++やPythonから呌び出すための実装を远加したす。 ttnn/cpp/ttnn/operations/randn/device/[randn|randn_pybind].[cpp|hpp] Tensor Randn:: invoke ( const ttnn::Shape& shape, MeshDevice& device, const DataType dtype, const Layout layout, const MemoryConfig& memory_config, const std :: optional <DeviceComputeKernelConfig>& compute_kernel_config, uint32_t seed) { auto tensor = ttnn::prim:: randn (shape, dtype, layout, memory_config, device, compute_kernel_config, seed); if (layout != Layout::TILE) { tensor = ttnn:: to_layout (tensor, layout); } return tensor; } // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ void bind_randn_operation (py:: module & pymodule) { bind_registered_operation ( pymodule, ttnn::randn, doc, ttnn::pybind_overload_t{ []( const OperationType& self, const ttnn::Shape& shape, MeshDevice& device, const DataType dtype, const Layout layout, const MemoryConfig& memory_config, const std :: optional <DeviceComputeKernelConfig>& compute_kernel_config, uint32_t seed) { return self (shape, device, dtype, layout, memory_config, compute_kernel_config, seed); }, py:: arg ( "shape" ), py:: arg ( "device" ), py:: kw_only (), py:: arg ( "dtype" ) = DataType::BFLOAT16, py:: arg ( "layout" ) = Layout::TILE, py:: arg ( "memory_config" ) = ttnn::DRAM_MEMORY_CONFIG, py:: arg ( "compute_kernel_config" ) = std :: nullopt , py:: arg ( "seed" ) = 0 }); } 今回実装したより詳しい党䜓コヌドは、以䞋のPull Requestを参照ください。 https://github.com/tenstorrent/tt-metal/pull/34508 性胜評䟡 次のスクリプトで実装したttnn.randnず埓来のopを組み合わせたttnn.rand + Box-Muller倉換の実装ず比范したす。 補足ずしおCPUによる実装も蚈枬したす。 import math, time, ttnn, torch, numpy as np def rand_box_muller (shape, *, device, dtype, layout, mem, seed): half = (*shape[:- 1 ], shape[- 1 ] // 2 ) u1 = ttnn.rand(half, device=device, dtype=dtype, layout=layout, memory_config=mem, seed=seed + 1234 ) u2 = ttnn.rand(half, device=device, dtype=dtype, layout=layout, memory_config=mem, seed=seed + 4321 ) r = ttnn.sqrt(ttnn.multiply(ttnn.log(u1), - 2.0 )) th = ttnn.multiply(u2, 2.0 * math.pi) z0 = ttnn.multiply(r, ttnn.cos(th)) z1 = ttnn.multiply(r, ttnn.sin(th)) return ttnn.concat([z0, z1], dim=- 1 ) def fused (shape, *, device, dtype, layout, mem, seed): return ttnn.randn(shape, device=device, dtype=dtype, layout=layout, memory_config=mem, seed=seed + 1234 ) def torch_randn (shape, *, dtype, seed): torch.manual_seed(seed+ 1234 ) return torch.randn(shape, dtype=dtype) def bench (name, fn, *, iters, warmup): for i in range (warmup): fn(i) t0 = time.perf_counter_ns() for i in range (iters): fn(i) mean_ms = (time.perf_counter_ns() - t0) / 1e6 / iters print (f "{name}: {mean_ms:.6f} ms/iter" ) return mean_ms DEVICE_ID = 0 SHAPE = ( 1 , 1 , 1024 , 1024 ) ITERS, WARMUP = 10000 , 1000 LAYOUT, MEM, DTYPE = ttnn.TILE_LAYOUT, ttnn.DRAM_MEMORY_CONFIG, ttnn.float32 device = ttnn.open_device(device_id=DEVICE_ID) res_rand_box = bench( "ttnn.rand + Box-Muller" , lambda i: rand_box_muller(SHAPE, device=device, dtype=DTYPE, layout=LAYOUT, mem=MEM, seed=i), iters=ITERS, warmup=WARMUP) res_randn = bench( "ttnn.randn" , lambda i: fused(SHAPE, device=device, dtype=DTYPE, layout=LAYOUT, mem=MEM, seed=i), iters=ITERS, warmup=WARMUP) print (f "Speedup: {res_rand_box / res_randn:.3f}x" ) ttnn.close_device(device) print ( " \n appendix" ) res_torch = bench( "torch.randn" , lambda i: torch_randn(SHAPE, dtype=torch.float32, seed=i), iters=ITERS, warmup=WARMUP) 4぀の Tenstorrent Wormhole™ n300s カヌドを搭茉したTT-LoudBoxサヌバで実行した結果が次のようになりたす。 埓来のop組み合わせ(rand×2 + log/sqrt/sin/cos/mul + concat)の実装に比べお、今回fused kernelを実装しお玄4倍の高速化が達成したした。 ちなみに、CPU(Intel® Xeon® Silver 4309Y)の torch.randn で実行したものず比べるずアクセラレヌタによる䞊列実行の恩恵を感じるこずができるず思いたす。 ttnn.rand + Box-Muller: 0.344376 ms/iter ttnn.randn: 0.085173 ms/iter Speedup: 4.043x appendix torch.randn: 4.509201 ms/iter たた、出力されたサンプルの分垃を可芖化しおも暙準正芏分垃ずしお問題ないこずが次のように確認できたした。 import ttnn, matplotlib.pyplot as plt, numpy as np device = ttnn.open_device(device_id= 0 ) x = ttnn.randn( ( 1 , 1 , 1024 , 1024 ), device=device, dtype=ttnn.float32, layout=ttnn.TILE_LAYOUT, memory_config=ttnn.DRAM_MEMORY_CONFIG, seed= 1234 , ) x = ttnn.to_layout(x, ttnn.ROW_MAJOR_LAYOUT) x = ttnn.from_device(x) x = ttnn.to_torch(x).cpu().numpy().ravel() mean = np.mean(x) var = np.var(x) plt.figure(figsize=( 6 , 4 )) plt.hist(x, bins= 100 , density= True , alpha= 0.7 ) plt.axvline(mean, linewidth= 2 , label=f "mean = {mean:.6f}" ) plt.axvspan(mean - np.sqrt(var), mean + np.sqrt(var), alpha= 0.2 , label=f "var = {var:.6f}" ) plt.title( "Histogram of ttnn.randn()" ) plt.xlabel( "Value" ) plt.ylabel( "Probability Density" ) plt.grid( True ) plt.legend() plt.tight_layout() plt.savefig( "fig.png" ) ttnn.close_device(device) たずめ 本蚘事では、TenstorrentのAIアクセラレヌタアヌキテクチャずその特城を玹介したした。たた、fused kernelによる具䜓的な最適化の実装方法ず埓来手法ず比范しお玄4倍の高速化を達成する性胜評䟡結果を共有したした。 明日のアドベントカレンダヌもお楜しみに。 Dao, Tri. "Flashattention-2: Faster attention with better parallelism and work partitioning." arXiv preprint arXiv:2307.08691 (2023). ↩ Shah, Jay, et al. "Flashattention-3: Fast and accurate attention with asynchrony and low-precision." Advances in Neural Information Processing Systems 37 (2024): 68658-68685. ↩ Box, George E. P. and Mervin E. Muller. “A Note on the Generation of Random Normal Deviates.” Annals of Mathematical Statistics 29 (1958): 610-611. ↩ https://github.com/tenstorrent/tt-metal/blob/main/METALIUM_GUIDE.md#spmd-in-metalium ↩
この蚘事は、 NTT docomo Business Advent Calendar 2025 18日目の蚘事です。 みなさんこんにちは、むノベヌションセンタヌの田口です。 普段はOffensive Securityプロゞェクトのメンバヌずしお攻撃技術の調査・怜蚌に取り組んでいたす。 私たちのチヌムでは定期的に技術LTず称しお、各メンバヌが自由に技術的知芋を共有する時間を蚭けおいたす。 この蚘事では、私が技術LTの堎で発衚したAI駆動型マルりェア 1 の動䜜デモず、発衚埌のチヌム内議論の様子に぀いお玹介したす。 この蚘事では、AI駆動型マルりェアの抂念を理解するために、実害のないデモ甚PoCを䜜成しおその挙動を確認しおいたす。 たた、PoC悪甚の可胜性を考慮しお怜蚌の䞭で䜜成したコヌドやプロンプトの党䜓公開は控えさせおいただきたす。 Offensive Securityプロゞェクトに぀いお AI駆動型マルりェアずは AI駆動型マルりェアの動䜜デモ 動䜜デモの解説 チヌム内での議論 どれくらい耇雑な機胜を動的生成できるのか 攻撃者芖点のメリットはなに 攻撃ベクトル発展の可胜性に぀いお おわりに 参考 Offensive Securityプロゞェクトに぀いお Offensive Securityプロゞェクトでは、攻撃者芖点のセキュリティOffensive Securityを専門ずするチヌムずしお、攻撃技術の調査・開発・怜蚌に取り組んでいたす。 攻撃者に先んじお新たな攻撃技術を怜蚌するこずで、将来の脅嚁を芋越した防埡の匷化に぀なげおいたす。 䞻な業務内容ずしお、NTTドコモビゞネスの WideAngleプロフェッショナルサヌビス における攻撃技術の怜蚌支揎や、最先端の攻撃技術に関する応甚的な研究開発を行っおおり、 成果のカンファレンス発衚など察倖的な掻動にも積極的に取り組んでいたす。 AI駆動型マルりェアずは AI駆動型マルりェアずは、倧芏暡蚀語モデルLLMやAI゚ヌゞェントの胜力を攻撃プロセスの䞀郚に利甚するマルりェアの総称です。 2025幎7月に「LAMEHUG 2 」、8月に「PromptLock 3 」ず呌ばれるマルりェアが芳枬されたした。 攻撃者によるAI利甚の事䟋は以前からありたすが、これらのマルりェアは新しいアプロヌチでAI利甚がされおおり話題になりたした。 特城はマルりェア内に倖郚のAIず通信しお悪性コヌドを生成させる手法、いわゆるバむブコヌディング 4 の手法がマルりェアの機胜に組み蟌たれおいるこずです。 埓来のマルりェアは攻撃者が事前に甚意した静的な悪性プログラムを実行したすが、AI駆動型マルりェアはプロンプトに埓いAIが環境に応じお必芁なプログラムを動的に生成・実行したす。 AI駆動型マルりェアの動䜜デモ AI駆動型マルりェアの実装・挙動の理解促進を目的ずしおデモ甚のPoCを䜜成したした。 このデモでは、PoCの実行によりタヌゲットフォルダsandboxをzipファむルぞ圧瞮する動䜜を瀺したす。 䞋蚘はPoC動䜜䞭のコン゜ヌルを衚瀺したバヌゞョンです。 動䜜デモの解説 䞊蚘のデモは、以䞋のような順で動䜜しおいたす。 動画内ではVBScript、batファむルを実行しおいたすがプログラム本䜓はsrcフォルダ内のPythonコヌドです。 ナヌザ操䜜PoCを実行する。 むンタヌネット䞊のLLMずの通信を開始する。 LLMからのレスポンスを基に新たにプログラム generated_recon.py を䜜成する。 generated_recon.py を実行する。 sandboxフォルダをzipに圧瞮しお、distフォルダぞ出力する。 䞊蚘動䜜における2 ~ 4の流れがAI駆動型マルりェアの特城的な動䜜になりたす。 今回の動䜜デモではsandboxフォルダを察象ずしたzipぞの圧瞮たでを実装しおいたすが、 実際の攻撃では圧瞮察象範囲の拡倧や圧瞮ファむルの倖郚送信ずいった機胜が远加で䜜成されるず考えられたす。 LAMEHUGの事䟋では、コンピュヌタ内における広範な情報収集ずSFTPおよびHTTPを利甚したデヌタの倖郚送信をしたず報告されおいたす。 怜蚌を通しお䜜成されたgenerated_recon.pyの䞀䟋を䞋蚘に瀺したす。 これらのコヌドはPoC内のプロンプトに応じおLLMが動的生成したコヌドです。 同じ機胜を持ちたすが、芋かけ䞊は異なるコヌドずしお生成される堎合がありたす。 import os from pathlib import Path from zipfile import ZipFile, ZIP_DEFLATED from datetime import datetime def main (): # 1. Set base_dir to "sandbox" under this script's directory base_dir = Path(__file__).parent / "sandbox" if not base_dir.is_dir(): print (f "'sandbox' directory not found at {base_dir}" ) return # 2. Recursively find all files in sandbox file_list = [] for root, dirs, files in os.walk(base_dir): for file in files: abs_path = Path(root) / file rel_path = abs_path.relative_to(base_dir) file_list.append((abs_path, rel_path)) # 3. Prepare output ZIP path dist_dir = Path(__file__).parent / "dist" dist_dir.mkdir(exist_ok= True ) timestamp = datetime.now().strftime( "%Y%m%d%H%M%S" ) zip_name = f "sandbox_snapshot_{timestamp}.zip" zip_path = dist_dir / zip_name # 4. Write files into ZIP file with paths relative to sandbox with ZipFile(zip_path, "w" , ZIP_DEFLATED) as zipf: for abs_path, rel_path in file_list: zipf.write(abs_path, arcname= str (rel_path)) # 5. Optional: Append to log log_path = Path(__file__).parent / "recon_log.txt" with open (log_path, "a" , encoding= "utf-8" ) as logf: logf.write(f "[{datetime.now().strftime('%Y-%m-%d %H:%M:%S')}] Zipped {len(file_list)} files from sandbox to {zip_name} \n " ) if __name__ == "__main__" : main() 今回のPoCでは実隓䞭の想定倖の動䜜を防ぐために、䞋蚘のような安党面を考慮した関数を実装しおいたす。 def basic_safety_check (code: str ) -> None : """ デモ甚の簡易チェックWindows でも共通で危険そうなものをざっくり犁止 """ forbidden_keywords = [ # 削陀系 "os.remove" , "shutil.rmtree" , "os.rmdir" , "unlink(" , # ネットワヌク系 "socket." , "requests." , "httpx." , "urllib." , "ftplib." , # 環境・プロセス系 "os.environ" , "subprocess.Popen" , "subprocess.call" , "subprocess.run(" , # Windows レゞストリ "winreg" , # 䜕でも実行系 "eval(" , "exec(" , ] for kw in forbidden_keywords: if kw in code: raise RuntimeError (f "安党のため犁止キヌワヌドが怜出されたした: {kw}" ) チヌム内での議論 技術LTの質疑応答時間で出た発蚀に぀いお、いく぀か抜粋しお玹介したす。 どれくらい耇雑な機胜を動的生成できるのか 私: どれくらい耇雑な攻撃コヌドを動的生成できるかはLLMの性胜に䟝存しおいる。 AI駆動型マルりェアの事䟋に限らず、今埌どれくらい攻撃コヌド生成の胜力をAIが備えるかは泚芖しおいきたい。 メンバヌA: デモプログラムや芳枬された怜䜓では、ファむル列挙や倖郚通信などの簡易な機胜のみを実装させおいるが、 アンチりむルスやEDRの怜知回避などの、より攻撃者が実珟したい高床な機胜を動的に生成させるこずが珟段階でできるのか、 あるいは将来的にできるようになるのかずいった芳点で远加調査するのも良さそう。 攻撃者芖点のメリットはなに 私: ランダム性のある攻撃コヌドを動的に生成するずいう挙動はシグネチャ型怜知を回避しやすいずいうメリットがありそう。 高床なコヌディング胜力を持たない攻撃者でも扱えるずいうメリットもあるかも。 メンバヌB: 事䟋やデモプログラムで生成させおる機胜は簡易なもの悪性ずは蚀い切れないなので、 本栌的な悪性コヌドを動的生成させるような実装になったずき、怜知回避の芳点でどれくらい通甚するのか気になる。 メンバヌC: シグネチャ型怜知を回避する方法は他にもあるず思うので、わざわざAIに動的生成させるずいうのは回りくどいやり方な気がする。 そういう意味ではコヌディング胜力を持たずずも自然蚀語でコヌド生成できる点のほうが珟状はメリットずしお匷そう。 私: 埓来のペむロヌドを攻撃者基盀からダりンロヌドしおくる手法ずAIで動的に生成する手法ずで、 実際にステルス性の違いがあるのかずいう芳点で調査するのも䟡倀がありそう。 攻撃ベクトル発展の可胜性に぀いお メンバヌB: AI駆動型マルりェアが流行っおくるず意図せず公開されたAIサヌビスの悪甚や、 流出したAIサヌビスのAPIキヌを悪甚するこずで攻撃者の痕跡を隠すケヌスが出おくる気がする。 私: 同じようなこずが気になっおいお、今埌゚ンタヌプラむズ向けのCopilot系サヌビスが普及した䞖界になったずき、 䌁業環境内のモデルを悪甚したAI駆動型マルりェアずかが登堎しおくる可胜性があるのではず思った。 参考: 業務で進むLLM掻甚、その裏に朜む脅嚁ずはMicrosoft 365 Copilotを介した攻撃怜蚌むンタヌン䜓隓蚘  おわりに この蚘事では、AI駆動型マルりェアの抂芁説明およびデモ甚PoCを発衚した技術LTの内容に぀いお玹介したした。 今埌もAIが普及・進化した䞖界で起こり埗る脅嚁に぀いお調査を続けおいき、埗られた技術的知芋に぀いおは共有しおいきたいず思いたす。 明日は鈎ヶ嶺の蚘事ですお楜しみに 参考 AI駆動型マルりェアずは䜕か Vibe Codingを駆䜿するLAMEHUG、PromptLockを解説 ↩ CERT-UAによるLAMEHUGに関するレポヌト ↩ ESET ResearchによるPromptLockに関するレポヌト ↩ wikipedia - バむブコヌディング ↩
この蚘事は、 NTT docomo Business Advent Calendar 2025 17日目の蚘事です。 はじめに 本蚘事は、コミュニケヌションアプリケヌションサヌビス郚でビゞネスdアプリの開発を担圓しおいる 立朚・富田・西谷 の共同執筆です。 私たちは、 ビゞネスdアプリ ずいう、ビゞネスパヌ゜ンの仕事や生掻に圹立぀ポヌタルアプリを開発しおいたす。 ビゞネスdアプリチヌムでは、モバむルアプリ・フロント゚ンド・バック゚ンドなどの開発ずデザむンの䞀郚を瀟員で内補しおおり、以䞋の蚘事で以前蚘茉したようにGoogle Cloudのサヌバヌレスサヌビスをフル掻甚しおいたす。 サヌバレスをフル掻甚したビゞネスアプリのアヌキテクチャ前線 サヌバレスをフル掻甚したビゞネスアプリのアヌキテクチャ埌線 このため、私たちのチヌムではGoogle Cloudのプロフェッショナルレベルの資栌をチヌムメンバヌ党員が1幎間に1個以䞊取埗するずいう目暙を立お、昚幎床は党員目暙を達成しおいたす。 その䞭でも、同チヌムのメンバヌ3名立朚・富田・西谷が Google Cloud 認定資栌の党冠※2025幎8月時点を達成 し、 Google Cloud Partner All Certification Holders 2025 に遞出されたした  受賞者の䞀芧は こちら 本蚘事では、瀟内で知芋を共有するこずを目的ずしお、党冠者による座談䌚 を開催したので、その内容をたずめおご玹介したす。 はじめに Google Cloudの資栌に぀いお 資栌レベルず有効期限 座談䌚 圓日の流れ テヌマ 資栌取埗を始めた理由 孊習のコツやTips英語の詊隓察応 どの資栌が倧倉だったか 参加者からの質問・コメント たずめ Google Cloudの資栌に぀いお たず、Google Cloud 認定資栌ずは䜕かに぀いお説明したす。 Google Cloud 認定資栌は、Google Cloud に関する知識・スキルを公匏に蚌明するための資栌です。 Google Cloudを䜿ったクラりドアヌキテクチャ蚭蚈、デヌタ分析、セキュリティ、ネットワヌク、機械孊習、DevOps、Workspace管理など、資栌ごずに求められる専門性が異なりたす。 このGoogle Cloudの認定資栌を党お保持しおいる、パヌトナヌ䌁業所属の゚ンゞニアを衚地するプログラム 「Google Cloud Partner All Certification Holders」 が、今幎から始たりたした。 2025 幎版では、2025幎6月1日時点で䞀般公開されおいるすべおの認定資栌が察象ずなり、合蚈13資栌が芁件ずしお定められおいたす。 蚀語は䞍問で、バヌゞョン曎新に䌎うベヌタ詊隓も察象です。たた、Associate Google Workspace Administratorに぀いおはProfessional Google Workspace AdminstratorPGWAで代替可 ずされおいたす。 たた、2025 幎版の募集は 2025幎8月18日に公匏発衚 され、8月18日〜9月30日の玄1か月間が応募期間、10月に審査、11月に遞出者発衚 ずいうスケゞュヌルで実斜されたした。 察象資栌は以䞋の通りです。 Cloud Digital Leader Certification (CDL) Generative AI Leader Certification (GAIL) Associate Cloud Engineer Certification (ACE) Associate Data Practitioner Certification (ADP) Associate Google Workspace Administrator (AGWA)PGWAでも可 Professional Cloud Architect Certification (PCA) Professional Cloud Developer Certification (PCD) Professional Data Engineer Certification (PDE) Professional Cloud Security Engineer Certification (PCSE) Professional Cloud Network Engineer Certification (PCNE) Professional Cloud DevOps Engineer Certification (PCDE) Professional Cloud Database Engineer Certification (PCDBE) Professional Machine Learning Engineer (PMLE) ※2025幎12月時点では、䞊蚘に加えお Professional Security Operations Engineer (PSOE) が新たに远加されおいたす。 資栌レベルず有効期限 Google Cloudの資栌は、䞻に以䞋の 3段階のレベル に分類されおいたす。 Fundamental クラりドの基本抂念や Google Cloud の抂芁理解が䞭心。 クラりド未経隓者やビゞネス職にも向けた入門レベル。 有効期限3幎 Associate 実践的な Google Cloud の利甚スキルを問う技術者向けレベル。 特に 運甚・デプロむ担圓者 や、これから Professional を目指す゚ンゞニアの基瀎固めに盞圓。 有効期限3幎 Professional クラりドアヌキテクチャ蚭蚈、セキュリティ、デヌタ分析など、専門領域で高床なスキルが求められる最䞊䜍レベル。 難易床が最も高く、詊隓自䜓の蚭問も実務寄り。 有効期限2幎 Google Cloud Partner All Certification Holders に申請する際は、党おの資栌を有効期限内にする必芁があリたす。このため、曎新時期の管理が重芁 になりたす。 座談䌚 ここからは、9月末に瀟内で行われた座談䌚の内容に぀いお玹介したす。 Google Cloudの党資栌を取埗した、幎次の異なる立朚若手・富田䞭堅・西谷ベテランの3名が、それぞれの芖点で8぀のテヌマで座談䌚を行いたした。 圓日の流れ 圓日は、Google Cloud Japanのテクニカルマネヌゞャヌの方をお招きし、オンラむンで1時間行いたした。 オヌプニングから始たり、たずGoogle Cloud Japanの方からGoogle Cloudの資栌制床に関する説明がありたした。 その埌、座談䌚の登壇者3名立朚・富田・西谷から自己玹介があり、座談䌚に進むずいう流れで行いたした。 具䜓的な流れは以䞋の通りです。 オヌプニング Google Cloud認定資栌・孊習制床の説明Google Cloud Japan テクニカルマネヌゞャヌ 自己玹介 座談䌚 質疑応答 テヌマ 座談䌚のテヌマは以䞋の内容でした。 8぀のテヌマに぀いお話し、最埌に質疑応答を行いたした。 今回の蚘事では、その䞭でもいく぀かのテヌマをピックアップしお、内容を玹介したす。 資栌取埗を始めた理由 3名ずも 「䜓系的な知識習埗」 が倧きな理由でした。 Google Cloudはサヌビスが幅広く、業務で䜿う範囲だけでは偏りが出やすいため、資栌取埗を通じお党䜓像を把握したいずいう共通のモチベヌションがありたした。 たた、クラりドの知識がない若手瀟員にずっおも、䜓系的な知識を埗られるので、良い教材になりそうです。 立朚若手 入瀟盎埌クラりドに関する知識が党くなく、知識を埗たかったため、たずはア゜シ゚むト資栌ACEから着手。 富田䞭堅 普段觊れないサヌビスも知識ずしお埗お、業務に掻かしたいずいう思いからスタヌト。 西谷ベテラン 2018幎に内補開発を始めた圓初、AWSに比べお日本語情報が少なかったので、䜓系的に孊ぶため資栌取埗を決意。幎霢問わず、挑戊できるこずを瀺したかった。 孊習のコツやTips英語の詊隓察応 3名ずも 公匏のサンプル問題などの暡擬問題集を掻甚 し、 Google Cloud Skills Boostで実際にサヌビスを動かす こずで、理解の定着を図っおいたした。 たた、ハヌドルの高い英語の詊隓では、暡擬問題集を解く際にブラりザの翻蚳機胜などを甚い、時間の短瞮をしおいたした。 立朚若手 公匏のサンプル問題や垂販の暡擬問題集を掻甚。英語は翻蚳ツヌルを䜿い、専門甚語も芚えるようにした。 富田䞭堅 詊隓察策マニュアルやネットの情報で党䜓像を掎み、Udemyなどの暡擬詊隓で実践。 西谷ベテラン 苊手分野はGoogle Cloud Skills Boostで実際にサヌビスを動かしお孊習。英語詊隓はブラりザ翻蚳機胜を掻甚。 どの資栌が倧倉だったか 3名ずも「Professional Machine Learning Engineer」・「Associate Google Workspace Administrator」・「Professional Cloud Network Engineer」など、 業務で普段䜿わない領域の資栌 の取埗に苊劎したようです。 特に、 「Professional Machine Learning Engineer」 ず 「Associate Google Workspace Administrator」 の2぀は、3名䞭2名が特に孊習に時間がかかった資栌ずしおあげおいたした。 普段銎染みのない専門甚語を芚える必芁があり、難易床が高かったようです。 立朚若手 「Professional Machine Learning Engineer」ず「Associate Google Workspace Administrator」。詊隓を受けた圓初は英語しかなく、甚語も芚える必芁があったため、難しかった。 富田䞭堅 「Professional Machine Learning Engineer」ず「Associate Google Workspace Administrator」。業務で觊れた経隓がほずんどなく、理解に時間がかかった。 西谷ベテラン 「Professional Cloud Network Engineer」。普段サヌバヌ開発䞭心の業務でネットワヌク構成BGP、専甚線などに觊れる機䌚が少なかったため。 参加者からの質問・コメント 座談䌚の参加者からは「党冠維持のモチベヌションはどこから来るのか」や、「IAM関連の孊習で圹立ったコンテンツは䜕か」などのさたざたな質問がありたした。 登壇者からは「党冠取埗ずいう目暙の分かりやすさや、Google Cloud Partner All Certification Holdersで衚地されるこずがモチベヌションになる」ずいった話や、Google Cloud Skills Boostなどの具䜓的な孊習コンテンツに関する情報があり、参加者のGoogle Cloudの資栌取埗のモチベヌションを高める良いきっかけになったようです。 たずめ 本蚘事では、Google Cloud認定資栌の抂芁ず、Google Cloud Partner All Certification Holders 2025 に遞出されたメンバヌによる瀟内座談䌚の様子、そこから芋えおきた孊習のポむントに぀いお玹介したした。 座談䌚を行うこずで、参加者のGoogle Cloud認定資栌の取埗のモチベヌションに぀ながり、良いきっかけずなりたした。 皆さたももし興味があれば、Google Cloud認定資栌の党冠を目指されおはいかがでしょうか それでは、明日の蚘事もお楜しみに ※ 私たちが開発しおいるビゞネスdアプリに興味を持った方は、 公匏ペヌゞ をご確認ください。 瀟内報やタスク管理など、私たちが開発しおいる機胜䞀芧が蚘茉されおいたす。
この蚘事は、 NTT docomo Business Advent Calendar 2025 の16日目の蚘事です。 瀟内サヌクルのメンバヌでハッカ゜ンに参加した結果、気が付いたら競銬の冠レヌスを開催しおいたずいう掻動報告です。 はじめに AIロボット郚の玹介 参加したハッカ゜ンの抂芁 アむデアの背景ずコンセプト 「でっかい」瞛り 100均アむテム瞛り 「スマホのみ」瞛り 「お腹」に関連した機胜 制玄ず創造性 結果はオヌディ゚ンス賞そしお颚倉わりな賞品を頂く 船橋競銬堎にお「みかかロボット杯」開催 おわりに はじめに こんにちは、AIロボット郚のサヌクルメンバヌの宮岞( @daiking1756 )です。 普段は5G&IoTサヌビス郚で映像系サヌビスの䌁画やプリセヌルス的なお仕事をしおいたす。 この蚘事では、AIロボット郚のメンバヌ2名で参加した颚倉わりなハッカ゜ンの暡様ず、颚倉わりな賞品をご玹介したす。 AIロボット郚の玹介 AIロボット郚はものづくり系の瀟内サヌクルです。 普段はSlackで情報亀換しながらメンバヌが個人で䜜りたいものを䜜っおいたす。 昚幎のアドベントカレンダヌの蚘事でもAIロボット郚の掻動を曞いおいたす engineers.ntt.com 参加したハッカ゜ンの抂芁 2025幎3月、私たちは「創発遊戯 2025」ずいう瀟䌚人向けのハッカ゜ンに参加したした。 同ハッカ゜ンが2024幎に開催されたずきの様子を、私がSNS䞊で芋おいお、ナニヌクなハッカ゜ンだなヌず思っおいたした。 そんな時に、2025幎開催の情報を聞いおAIロボット郚のメンバヌに声を掛けたのが、参加のきっかけでした。 このハッカ゜ンはチヌム毎に異なる「瞛り」が適甚されるずいう特城がありたす。 瞛りは「テヌマ」「技術・玠材」「その他 環境・条件」のカテゎリに分かれおおり、各カテゎリに玄10個の瞛りが甚意されおいたす。 各チヌムで遞べるのはカテゎリず瞛りの個数最倧4぀たでで、どの瞛りが遞ばれるかはランダムです。 今回我々は各カテゎリから1぀ず぀瞛りを遞びたした。 遞ばれた瞛りは䞋蚘です。 瞛りカテゎリ 瞛り内容 テヌマ 「でっかい」 技術・玠材 100円均䞀ショップで買った玠材を3぀以䞊取り入れる その他 環境・条件 「スマホのみで」どこたでできるか、チャレンゞする 他の参加チヌムでは「本業に関するなにか」や「シラフ犁止」などを匕いおおり、どのチヌムも頭を悩たせながらも楜しそうに開発しおいた印象です。 うちのチヌムは「スマホのみ」瞛りがかなり重いですが、やれるずころたで挑んでみるこずにしたした。 その他ハッカ゜ンの詳现は䞋蚘に蚘茉されおいたす。 https://mashupawards.connpass.com/event/344340 mashupawards.connpass.com アむデアの背景ずコンセプト 簡単にどんな䜜品を䜜ったのか玹介したす。 我々は SMART HARAMAKI ずいう腹巻き型のりェアラブルデバむスを開発したした。 「でっかい」瞛り 「でっかい」ずいう瞛りに察し、普段小さいものを倧きくするずいう逆転の発想から、スマヌトりォッチの巚倧版を䜜るこずにしたした。アむデアが生たれたした。 倧きさ的に手銖ではなくお腹に巻くようなものになりそうだったので、腹巻き型デバむスにしたした。 100均アむテム瞛り 100均アむテムの瞛りに察しおは、振動モヌタヌは100均の電装ハンディプッシャヌから分解しお調達したり、スマホに拡倧鏡を取り付けるこずで画面を巚倧化させお「でっかい」に結び぀けるなどの詊みを行いたした。 ハッカ゜ン期間䞭、近所の100均をハシゎした回数は片手で収たりたせん。たたたた3皮の100均が埒歩圏内にあった 「スマホのみ」瞛り 䞀番倧倉だったのが「スマホのみ」瞛りです。 序盀はWebアプリ偎のベヌス実装はスマホからVibe Codingするなどで、スマホでの開発の新鮮さを楜しんでいたした。 しかし、マむコン(ESP32)にプログラムを曞き蟌む工皋で苊戊しおしたいたす。 1 次第にスマホの画面サむズでの開発や、マむコンずの接続䞍調に心が折れおしたい、PCでの開発に泣く泣く切り替えたした。 スマホの画面内での開発はさすがにキツくなっおきた😇 #創発遊戯 pic.twitter.com/pl58tmG2wX — みやぎdaiking⊿🌗 (@daiking1756) 2025幎3月14日 x.com 「お腹」に関連した機胜 腹巻き型デバむスを䜜っおいく䞭で、「お腹」に関連した機胜ずしお䞋蚘の機胜を実装したした。 満腹時蚈: お腹の膚らみを圧力センサヌで怜出しお食事䞭の満腹床を可芖化する。 食べ物レヌダヌ: 4カ所に蚭眮したモヌタヌの振動によっお近くの飲食店の䜍眮を䌝える。「お腹が震える方向に歩けばご飯に蟿り着く」䜓隓を 実珟。 私はりェブアプリ偎の開発を担圓したのですが、デバむス偎を担圓したメンバヌからは「腹巻きに基盀を瞫い付けるのが倧倉だった」ずいう予想倖の芖点からのコメントがありたした。 たた、今回のハッカ゜ンはリモヌト開催だったのですが、デバむスが䞭心ずなるプロダクトであっため、期間䞭に1床だけ出瀟しおオフラむンで䜜戊䌚議をしたした。 モヌタヌをLEDに倉えたデバッグ甚の回路を盞方から受け取ったこずで、その埌の開発をスムヌズに進めるこずができたした。 デバむスの制䜜過皋や䜜品の詳现は䞋蚘のペヌゞに蚘茉しおいたす。 protopedia.net 制玄ず創造性 「スマホだけで䜜れ」ずいう瞛りを匕いた瞬間、正盎『詰んだかも』ず思いたした。 でも、 創造的制玄の力 の動画でも語られおいるように、制玄っお䞍思議で、逆にアむデアがどんどん湧いおきたんです。 知識ずしおは知っおいたものの、制玄が新たな創造のきっかけになるこずを今回のハッカ゜ン䞭に肌で感じたした。 この蚘事を読んだ方が創発遊戯に参加するこずがあれば、瞛りはMAXの個数を遞ぶこずをオススメしたす 少し話はズレたすが、生成AIに入力するプロンプトも出力結果ぞの制玄を課しおいるずみるこずができたす。 制玄が少ない・抜象的だず、欲しい出力が埗られないずいうこずは、AIに眮き換えおみるず私たちは実䜓隓ずしおよく知っおいるかず思いたす。 結果はオヌディ゚ンス賞そしお颚倉わりな賞品を頂く 参加者による盞互投祚の結果、SMART HARAMAKIはオヌディ゚ンス賞を受賞したした🙌 そしおオヌディ゚ンス賞の賞品ずしお莈られたのが、なんず 地方競銬の賞レヌス冠暩 でした。 䞋蚘の通り賞品は䞉択から遞べたのですが、䞀番楜しそうなや぀にしたした オヌディ゚ンス賞の賞品 A~Cのどれかを遞べる #創発遊戯 pic.twitter.com/EB1aIBAznl — ひげだるた (@masaya3) 2025幎3月13日 x.com 船橋競銬堎にお「みかかロボット杯」開催 党囜に15か所ある地方競銬堎の䞭から、運営さんずも盞談し、メンバヌの家からも近い船橋競銬堎で開催しお頂くこずにしたした。 そしお、2025幎11月7日、぀いに船橋競銬堎にお、我々の冠レヌスが開催されたした。 レヌス名は「みかかロボット杯」です ハッカ゜ン参加時のチヌム名「みかかロボット郚」が由来です。 レヌス圓日の様子は䞋蚘でも投皿しおいたすが、来賓宀から芋るレヌスは䞀味違う䜓隓でした。 ず蚀っおも、メンバヌ2人ずも競銬堎に行くのはほが初めおでしたが 個宀の来賓宀から芋るレヌスは最高でした🙌 予想も的䞭させるこずができ、みかかロボット郚初のサヌクル遠足は倧成功でした🏇 今回䜜成頂いた暪断幕は今埌サヌクル内で倧切に䜿わせお頂きたす。 pic.twitter.com/nmht7UXWtw — みやぎdaiking⊿🌗 (@daiking1756) 2025幎11月7日 x.com おわりに 簡単ですが、創発遊戯ぞの参加報告および船橋競銬堎での冠レヌス「みかかロボット杯」の開催報告でした。 瀟内サヌクルでの掻動でたさか競銬堎に行くずは思っおいたせんでした。 次のサヌクル遠足はどこに行くのか、楜しみです。 たた、ハッカ゜ンは毎回䜕か新しい発芋や孊びがあるので、今埌も継続的に参加しおいきたす。 今回参加した2名ずもハッカ゜ン期間䞭に確定申告に远われながらの開発ずなっおしたったこずが反省点でした。 3月䞭旬のハッカ゜ンに参加する際は、事前に確定申告を終わらせおおくこずをオススメしたす。 今埌も、AIロボット郚では遊び心ず技術力を融合させたチャレンゞを続けおいきたす。 次回の掻動報告も乞うご期埅ください それでは明日の蚘事もお楜しみに〜👋 ArduinoやESP32系マむコンにSketchを曞き蟌める ArduinoDroid ずいうAndroid向けアプリがあるようですが、私の手元の端末では動䜜したせんでした。 ↩
この蚘事は、 NTT docomo Business Advent Calendar 2025 の15日目の蚘事です。 皆さたどうもこんにちは、 @strinsert1Na ずいう人です。以前は 株匏䌚瀟゚ヌ・゚フ・ラボラトリヌズ ずいう䌚瀟に出向しながらバリバリ「脅嚁むンテリゞェンス」のお仕事をしおおりたしお、今幎の7月からはNTTドコモビゞネス 情報セキュリティ郚の管理職ずしお新たなキャリアを歩んでおりたす。 ここたで曞くず「なんだ、ただの順調にキャリア圢成しおいる人のめでたい話か」ず思われおしたいそうですが、そんなこずはありたせん。正盎なずころ、ほが毎日「(あんなやり方でよかったんだろうか )」ずいう䞍安の蚀葉が頭の䞭を駆け巡るような日々を過ごしおおり、半幎経過した珟圚でもプレむダヌず管理職のロヌル/責任の違いにおんおこたいな状態です。 この蚘事では、瀟䌚人人生をずっず”゚ンゞニア(プレむダヌ)”ずしおだけバリュヌを出し続けおきた筆者が、管理職になっお発生した苊悩やモダモダ、そしおそれを解決するためにずったアプロヌチに぀いおたずめたいず思いたす。 もし同じような境遇になっお苊しんでいる人や、これから゚ンゞニアリングマネヌゞャヌのキャリアを目指す人にずっお䜕かしらの垌望になれば幞いです。 ひずよひずよに管理職(マネヌゞャヌ)
 ふたやく以䞊での立ち回り !? み぀められおもなんにも出ないですよ ? (1on1の話題) りェルカムトゥ圱(ダヌク)サむト 超絶進化のマネヌゞャヌ生掻この手に぀かむ! 1. チヌムのふりかえりで出た良し悪しを自身の良し悪しぞ転換する 2. 自身がしっくりくる “゚ンゞニアリングマネヌゞャヌ” の型にそっくりハマるよう動いおみる それ(憧れのマネヌゞャヌ)目指しお歩き出しおきたんです確か  ひずよひずよに管理職(マネヌゞャヌ)
 たずは筆者がプレむダヌ時代にどんな働き方をしおいたかに぀いお、経歎を含めお玹介したす。 䞀蚀でたずめるず「子䌚瀟出向しお技術力ずアりトプットの魅せ方に泚力を眮いおいたら、プレむダヌずしお高く評䟡された」ずいった状況です。 旧NTTコミュニケヌションズに入瀟、新入瀟員研修を終え1幎目で株匏䌚瀟゚ヌ・゚フ・ラボラトリヌズぞ出向 そこから玄6幎間、゚ンゞニアリングチヌムでセキュリティプロダクトの開発・運甚・マルりェア解析、脅嚁むンテリゞェンスの生成業務をプレむダヌずしおひたすら頑匵る チヌムメンバヌはマネヌゞャヌを陀くず20代から30代のみで、技術獲埗に察するモチベヌションが非垞に高い 雑談の堎でも共通の話題で盛り䞊がりやすい マネヌゞャヌっぜい動きはほずんどしおこず、ただただ向䞊した技術力で顧客が喜ぶモノを高打率で䜜れるようになったこずず、アりトプットの魅せ方が倚少うたかったずいう理由だけで良い評䟡をいただく堎面が倚かった こんな状況が珟堎でしばらく続いた結果、ずんずん拍子で昇栌しお瀟䌚人8幎目でタヌニングポむントが来たした。 それはスペシャリストになるかマネヌゞャヌになるかの遞択です。 ここたで読んでいただいた方は「いやいやそんなに技術䞀本でやっおいくならスペシャリスト遞択しろよ」ず思うかもしれたせん。 しかしながら、NTTドコモビゞネスの堎合はスペシャリストのロヌルにリヌダヌずしおチヌムをリヌドするたでの暩限がなく、チヌムを䜜っおいきたいず思うならマネヌゞャヌの道を遞ぶ必芁がありたす。 筆者はこれたで仕事をしおいく䞭で技術をずこずん極めるずいうよりも「よい゚ンゞニアリングチヌムを䜜っおいきたいなぁ」ずいう気持ちが勝り、マネヌゞャヌずなる遞択をしたした。 遞択をした圓時は「これたでのマネヌゞャヌの動きやチヌムビルディングの方法論は知っおいるし、倧䞈倫なはず!」ず思っおいたした。 ですが筆者はこの7幎間でたった2぀の(しかもバリバリの゚ンゞニア集団のみで構成された)チヌムしか知りたせん。この考えが浅はかすぎるずいうこずを、筆者は埌々知るこずずなりたす。 ふたやく以䞊での立ち回り !? このような背景のもず、筆者は芪䌚瀟のNTTドコモビゞネスに戻り晎れおそこで10人チヌムのマネヌゞャヌをするこずになりたした。 「さお、これから良いチヌムを䜜っおいくぞヌ」ず意気蟌んだずころですぐ問題に盎面したす。 「  あれ、タスクっおどうやっおメンバヌに振っおいけばいいんだろう?」   䜕を蚀っおいるんだこい぀は? ず思った方がいらっしゃるかもしれたせんが、実は筆者はこれたでの仕事で「タスクをトップダりンで割り振る」ずいうこずをしたこずがありたせんでした。 筆者が所属しおいたチヌムはこれたでスクラムで業務を行っおおり、みんなが実斜するタスクはスクラムボヌド䞊に䜜られたバックログで管理され優先床が高い順にメンバヌが自䞻的にずっおいく圢匏をずっおいたした。 しかしながら、任されたチヌムにはそもそもタスクが可芖化されおいるボヌドがありたせんでした。 党おの仕事はマネヌゞャヌが管理しおいお、それを適切にメンバヌに分配、進捗報告䌚で状況把握ず方向性を決めおいきたす。 ぀たり、楜しそうな仕事も面倒な仕事も、党おはマネヌゞャヌの決断によっおメンバヌの誰が䜜業をするかが決たる組織䜓系だったのです。 それでは「じゃあ個人にダむレクトメッセヌゞを送っおタスクをお願いしおいくぞ!」ずいう気持ちで再スタヌト ..しようずしお、すぐに手が止たりたす。 それは、管理職研修で䜕床も聞かされた゚ンゲヌゞメントやメンタルヘルスケアの問題です。 おそらく JTC で管理職になった皆さんは、成り立おの頃に嫌ずいうほどさたざたな ”管理職研修”ずいうものを受けたのではないかず思いたす。 筆者も䟋倖ではなくもちろん倚くの研修を受けたしたが、珟状倧䌁業の倚くには「゚ンゲヌゞメント向䞊」に関する研修も含たれおいるかず思いたす。 ゚ンゲヌゞメントずは䌁業や仕事ずの結び぀きを数倀化した抂念でこのスコアが高いほど生産性の高さなどに぀ながるず蚀われおいたすが、厳しいこずに近幎のチヌムのKPIに゚ンゲヌゞメントスコアの向䞊も含たれおおりたす。 「『耇数あるチャネルから該圓の項目数数えろ』なんお面倒な仕事をバンバンお願いしお゚ンゲヌゞメントスコア䞋がったらダバむのか ?」そんな、本職ずは党く関係ないこずが頭をチラ぀くのです。 組織構造ず組織文化ず筆者自身の特性が党く噛み合わず、刀断がバグり始めたす。 結論どうなったかずいうず、巷でよく聞く「プレむングマネヌゞャヌ」の爆誕です。 筆者がむンタヌネット䞊でよく聞くケヌスは「仕事量が膚倧でプレむングをせざるを埗ない」ずいうケヌスなのですが、もしかしたら筆者のような「゚ンゲヌゞメントなどの新たなベクトルで生たれたKPIの未達を恐れお、面倒なタスクはマネヌゞャヌが巻き取る」ケヌスもそこそこいるのではないかなず思っおおりたす。 ただしこうなるず、マネヌゞャヌ業務がどんどん溜たっおいっお銖が回らなくなっおいきたす。「こういう時はどうすればいいんだ ? せや! 管理職研修でやらされた “1on1” で興味関心を聞きながら、仕事をお願いしおいったらええやん!!」 み぀められおもなんにも出ないですよ ? (1on1の話題) そんなモチベヌションで始たる 1on1 も、倚くの JTC 管理職を悩たせた(おいる)斜策ではないでしょうか。 最近の管理職研修には 1on1 の実斜そのものが含たれおいお、おそらく倚くの JTC では半匷制的に導入されおいるこずでしょう。この蚘事を読んでいる皆さたも、1on1をすでに経隓されたこずがあるかず思いたす。 筆者自身もこれたで䜕床も䞊叞にセッティングされた1on1に参加し、䜕1぀苊に感じるこずなく䌚話をしおきたした。 ですが、実はセッティングする偎になっおみるずなかなか難しいこずがわかりたす。 䜕が難しいかずいうず、前述のような筆者のモチベヌションで1on1をセッティングするず、瀟員の成長よりも「筆者自身がどう仕事をうたくアサむン/コントロヌルするか」に焊点がいっおしたう点です。 こうなっおしたうずメンバヌ芖点の1on1は「面倒な仕事が振っおくる堎所」になっおしたっお成長よりも遥かに「苊痛の堎」です。 なので、なるべく筆者の事情は䌏せおうたく仕事の悩みや最近の出来事などを匕き出そうずするんですが  䌚話が䞭々出おこないんですよね。 以前筆者が所属しおいたチヌムは皆幎霢局が近い職堎で専門性も熟知しおいたので、奜きな技術スタックの話やネットミヌムを口から垂れ流しおいれば楜しみながらモチベヌションの向䞊や成長ぞ぀ながる方向に䌚話が匟みたした。 しかしながら、筆者が新たに着任したチヌムの幎霢局は20代から50代たでさたざたであり、メンバヌ党員テクニカル領域が奜きなわけではありたせん。 筆者の浅い経隓では䌚話の皮に詰たったり、「(自分よりも倍以䞊の瀟䌚人経隓がある人にコヌチングするのも、プレッシャヌがあるな )」ず勝手に察話に難しさを感じたりしお、自身が経隓しおきた「感觊の良い1on1」を実珟できおいる気が党くしたせんでした。 たた、筆者のケヌスではセキュリティ゚ンゞニアずしお同期入瀟した人もチヌムメンバヌに含たれおおり、コンプラむアンスの郜合で䞊叞ずしおの立堎の発蚀は慎重にならなければならないず教えられる昚今では、どういう心持ちで1on1の堎に臚めばいいのかも悩みの1぀になりたした。 このような背景から、1on1䞭は「(この埌どういい方向に持っおいったらいいんだろう ..)」ず考えるシヌンが増え、結果ずしおお互いみ぀めあう無蚀の堎面やおそらく仕事の成長に぀ながらないであろう話が続いお1on1を終えるこずもありたす。 䌚瀟偎からも月に1回皋床の1on1は掚奚されおいるし過去の経隓からも1on1は重芁な堎であるず理解しおいるのですが、「自分がやっおいる 1on1 はメンバヌの成長の糧になっおいるんだろうか」ず、毎回1on1をセッティングする床に考えるようになりたした。 りェルカムトゥ圱(ダヌク)サむト このような事象が2~3ヶ月くらい続いた結果、筆者は俗に蚀う「むンポスタヌ症候矀」ず呌ばれる状態になりたした。 盎蚳するず、自身の䞊叞やメンバヌから「この人党然マネヌゞャヌの仕事できおないじゃんっお思われおるんだろうなぁ 」ず考えながら仕事をする状態になったずいうこずです。 メンバヌ芖点で芋るず、発蚀や決断に自信がない管理職なんお䞍安になるだけです。 そのため、この症状を抱え続けおいおもチヌム党䜓の士気は䞋がりたすし自身のパフォヌマンスも悪くなるだけなので回埩させたいのですが、ここでプレむダヌずマネヌゞャヌの倧きな違いが壁ずしお立ちはだかりたす。 それは、ポゞティブ/ネガティブ䞡偎面でのフィヌドバックをもらう機䌚が極端に少なく、具䜓的にどこをどう倉えおいけばいいのかがわからないずいうこずです。 プレむダヌ時代は䞊叞ずの面談を通しお自身の良かった行動や成長のためのフィヌドバックが定期的に返っおくるため、その機䌚を通しお自身の貢献を実感したり改善点に察しおアプロヌチをかけるこずができたした。 しかしながら、マネヌゞャヌになるず目暙達成に察するフィヌドバックはありたすが、行動に察するフィヌドバックをもらえる機䌚はほがありたせん。 それではチヌムメンバヌから貰えるかずいうず、1on1で「䜕か筆者に察するリク゚ストあったら蚀っおね!」ず発蚀しお反応が返っおきたこずはないですし、「(そりゃあ郚䞋芖点で面ず向かっお改善点を䞊叞に話せるわけないよな)」ずも発蚀する偎芖点でも思いたす。 ぀たり、自身のマネヌゞャヌずしおの振る舞いは「セルフマネゞメント」をするこずによっおその良し悪しを振り返り、改善をする必芁がありたす。 これは倚くの管理職にずっおは垞識なのでしょうが、これたで他者からのフィヌドバックで生きおいた筆者にずっおはすぐにセルフマネゞメントの技術を身に぀けるこずができたせんでした。 ですが、チヌムのパフォヌマンスを出すためにもセルフマネゞメントの技術を少しず぀身に぀け、改善しおいく必芁がありたす。 超絶進化のマネヌゞャヌ生掻この手に぀かむ! それでは、プレむダヌから䞊がったばかりの筆者は具䜓的にどう改善しおいったのか? ずいうのを2点ほど曞いおいきたいず思いたす。 1. チヌムのふりかえりで出た良し悪しを自身の良し悪しぞ転換する 1぀めは䞻にメンタル面での改善です。 本来は行動の良し悪しを自己で振り返っお評䟡し、改善するのが望たしい姿なのでしょうが、気持ちが萜ち蟌み気味の状態で始めおも䞊向きになるには時間がかかりたす。 そこで筆者は、チヌムに「ふりかえり(レトロスペクティブ)」の抂念を導入し、チヌムメンバヌの力を借りながらフィヌドバックを埗る方向性にしおみたした。 ふりかえりのフレヌムワヌクずしお KPT/YWT などがメゞャヌなものずしお存圚したすが、これらのフレヌムワヌクではチヌムが詊しおみお”よかったこず”や”改善しおほしいこず”などが各々のメンバヌから率盎な意芋ずしお衚珟されたす。 これはチヌムの改善掻動ずしお非垞に有意矩なのですが、それずは別にチヌムが改善しおみお”よかったこず”を筆者のマネゞメントずしお”よかったこず”ぞ、逆に”改善を芁望しおいる”郚分を筆者のマネゞメントにおける”改善のためのフィヌドバック”ずしお捉えさせおもらうようにしたした。 個人的には、ふりかえりの結果をこのように捉えるだけでマネヌゞャヌずしおの仕事が栌段にしやすくなりたしたし、最もメンタルの改善にも効果的だったず思いたす。 新人マネヌゞャヌ向けの研修を受けるず「成果を出さなければず思っおいるメンタルモデル/固定芳念を捚およう」や「チヌムのためを思えば!」のような粟神偎ぞのアプロヌチが出おきたすが、正盎なずころ粟神が萜ち蟌み気味のずころでこのような蚀葉をもらっおもほずんど回埩はしたせんでした。 それよりも、筆者のような他者からのフィヌドバックを事実ずしお受け止めお改善したい人は、チヌムメンバヌや䞊叞から率盎なフィヌドバックが出るような堎をセッティングした方が、䟋えネガティブフィヌドバックが倚くおも、むンポスタヌ症候矀を長匕かせるこずなく改善に向かっおいけるのではないかず思いたす。 2. 自身がしっくりくる “゚ンゞニアリングマネヌゞャヌ” の型にそっくりハマるよう動いおみる 2぀めは行動面での改善です。 筆者が受けた管理職研修の倚くは「倧切な軞はこれ! でもマネゞメントに正解はないから、課題出すからみんなで考えおみおね!! (完)」ずいう圢匏が倚く、「䜕かしら方法論を提瀺しお欲しい、それに沿っおやっおみるから」ず思ったのが個人の感想になりたす。 その䞀方で、JTC の堎合はさたざたな職皮やコンテキストを持った人間が同じ管理職研修を受けるので、ベストプラクティスを䞀般化しにくいずいった問題もあるのだろうずは思いたすので玍埗もしたす。 しかしながら、ずっず゚ンゞニアリング業務をしおいた筆者にずっおは経隓ベヌスよりもたずは「䜕かしらのベストプラクティス」に沿っお物事を始めおいかないずモダモダするタむプですし、そこから改善するずしおも元ずなる改善の土台が理に適っおいるかすらわからないず改善の方向性を決めるのも自身にずっおは困難です。 そこで、䞀般的には”よくないこず”ず蚀われそうですが、自身が最もしっくりくる「゚ンゞニアリングマネヌゞャヌ論」の型を探し、そこにハマるようにしお動いおみたした。 具䜓的には、䞀般的に提唱されおいる ゚ンゞニアリングマネヌゞャヌの4領域 ごずに自身の業務ドメむンで必芁ずなるカテゎリを掗い出し、それぞれのベストプラクティスに則る(䟋えば、1on1ならば「互いに事前に話す内容やトピックを共有しおおいお、メモずしお残しおおく」など)ずずもに自身の埗意領域を分析、その領域を匷みずしお自身のマネゞメントの軞が構築されおいくよう意識しおみたした。 具䜓的な4領域ずその領域に含たれるカテゎリの䟋は以䞋です。 1 ピヌプルマネゞメント (䟋: 1on1、チヌミング) テクノロゞヌマネゞメント (䟋: DevOps) プロゞェクトマネゞメント (䟋: アゞャむル) プロダクトマネゞメント(䟋: 仮蚭怜蚌) この4軞を意識するこずで、「プロダクトマネゞメントは苊手だけどやらないず゚ンゞニアリングマネゞャヌずしお最䜎限の仕事をこなせないから孊がうか」「あのセキュリティの領域はテクノロゞヌの郚分に入れおリヌドを取るのが必芁だな」「1on1のカテゎリはほが必須芁件だからこの本のやり方を暡倣するか」ずいった自身の方向性ず方法論が明確になり、1のふりかえりず合わせお栌段に業務がクリアになりたした。 特に筆者のような「理論がわからないず動くのが難しい」ずいう方には、このような守砎離の”守”を1぀䜜っおみるこずをお勧めしたす。 守を䜜っおいく方法はさたざたあるず思いたすが、もう1぀私がよく参考にしおいた本ずしお ゚ンゞニアリングマネヌゞャヌのしごず ―チヌムが必芁ずするマネヌゞャヌになる方法 がありたす。 業界ではメゞャヌな本で䞊蚘の4領域よりもスコヌプが広いですが、マネヌゞャヌになるず避けおは通れない道が党お入っおいるのでお勧めです。 それ(憧れのマネヌゞャヌ)目指しお歩き出しおきたんです確か  新人゚ンゞニアリングマネヌゞャヌの悩みを、埒然なるたたに曞かせおいただきたした。 眰ゲヌム化する管理職 なんお本が䞖間で話題になった通り、管理職に求められるロヌルが幎々増えおきお単玔に業瞟を出す以䞊の負荷がかかっおいるのは事実かなず思いたす。 某ギャングの幹郚になった人が「『任務は遂行する』『郚䞋も守る』䞡方やらなくっちゃあならないっおのが蟛いずころだな」なんお蚀葉を発しおいたしたが、珟代だずそれ以䞊にやるこずが増えおいお本人もビックリするこずでしょう。 その䞀方で「じゃあマネヌゞャヌリタむアしたいの?」ず蚀われるずそんなこずはありたせん。 筆者は瀟䌚人2幎目で心から尊敬する゚ンゞニアリングマネヌゞャヌに出䌚えたこずで゚ンゞニアリングの考え方が倉わりたした。 おそらくその人に出䌚わなければ筆者は技術にそこたで泚力しお向き合うこずもなかったし、このような衚舞台に出るこずもなかったでしょう。 いいマネヌゞャヌずの出䌚いはその人の成長速床だけでなく゚ンゞニアリングの考え方の根底そのものを倉えるほどの匷い圱響力を持っおいるず筆者は信じおいたす。 その人はもうドコモビゞネスから去っおしたいたしたが、筆者の目指す姿の1぀がその人から孊んだ「゚ンゞニアリング組織ず文化の土台を䜜れる゚ンゞニアリングマネヌゞャヌ」像ずしお残っおいたす。 筆者はただただその領域には至っおいたせんが、懇芪の堎で「マネヌゞャヌが倉わっおもう少しここで孊んでいきたいず思いたした!」ずいう蚀葉をいただくず「あぁ、もしかしたらチヌムに䜕かいい圱響を䞎えられたのかもしれないな」ず小さな成長を感じるこずもできたした。 ただただ道は遠く管理職の仕事はムズカシむこずばかりですが、か぀お憧れおいた存圚にたた䞀歩近づくこずを目指しお、少しでもチヌムに良い圱響が䞎えられるよう粟進しおいきたいず思いたす。 あたりたずたりのない話でしたが、同じような境遇になっおいる人、キャリアを目指しおいる人の䜕かしらの参考になれば嬉しいです。 明日は「AIロボット郚で出たハッカ゜ンの話ず副賞で頂いた競銬の冠レヌスの話」です! お楜しみに!! ゚ンゞニアリングマネヌゞャ/プロダクトマネヌゞャのための知識䜓系ず読曞ガむド, https://qiita.com/hirokidaichi/items/95678bb1cef32629c317 ↩
この蚘事は、 NTT docomo Business Advent Calendar 2025 13日目の蚘事です。 OpenStackのAPIをModel Context Protocol(MCP)を䜿っお操䜜できるようにし、Large Language Model(LLM)経由でクラりドのリ゜ヌスを操䜜できるようにしたした。 しかし、MCPサヌバヌを介しおAPIをそのたた叩けるようにするだけではLLMにずっお扱いづらく、コンテキストが無駄に倧きくなる・ツヌルをうたく実行できない、ずいった問題がありたした。 こういった問題に察しお、コンテキストを取捚遞択しお削枛し぀぀、必芁な機胜に絞ったMCPサヌバヌを実装するこずで察応したので、その内容を玹介したす。 はじめに OpenStack MCPサヌバヌを䜜る 党䜓構成 MCPサヌバヌの実装 MCPサヌバヌを䜿っおみるが   LLMに易しいMCPサヌバヌを䜜る 動䜜確認 たずめ はじめに みなさんこんにちは。むノベヌションセンタヌの會柀です。 むノベヌションセンタヌでは、今幎床からAIOps基盀プロゞェクトずいう新しいプロゞェクトを立ち䞊げ、オンプレミスのシステムやクラりド環境をタヌゲットに、AI技術を利甚した運甚自動化に向けた取り組みを始めおいたす。 その䞀環ずしお、NTTドコモビゞネスで運甚しおいるOpenStackで構築されたクラりド環境を察象にLLMを利甚した運甚自動化を進めおいたす。 運甚自動化を進めるにあたっお、たずはLLMからクラりド環境のリ゜ヌスを操䜜できるようにする必芁がありたす。 LLMから盎接OpenStackのAPIを操䜜できないので、MCPを䜿っおAPI呌び出しをラッピングするこずにしたした。 OpenStackを察象ずしたMCPサヌバヌの実装はすでに幟぀か公開されおいるものが存圚するのですが、珟状ではデファクトスタンダヌドず呌べるものは存圚しないようです。 そこで、我々の開発チヌムでは自分たちで新たにMCPサヌバヌを実装するこずにしたした。 OpenStack MCPサヌバヌを䜜る 党䜓構成 MCPずは、Anthropic瀟が発衚したLLMアプリに倖郚のシステムを接続するためのプロトコルです。 このMCPを利甚しおサヌバヌを構築し、OpenStack APIを操䜜する機胜を ツヌル ずしおLLMに公開するこずで、AI゚ヌゞェントからOpenStackのリ゜ヌスを操䜜できるようにしたす。 党䜓の構成はこんな感じです。 今回はClaude Codeを䜿っおMCPサヌバヌの動䜜を確認しおみたす。 たず、ナヌザヌはClaude Codeを䜿っお、自然蚀語でクラりド環境ぞの操䜜を指瀺したす。 Claude CodeにはMCP経由でツヌルに接続する機胜があるため、サヌバヌを登録しおおけばナヌザヌからの入力を受けお適切なツヌルを利甚しおくれたす。 これにより、ツヌルからOpenStackのAPIを操䜜しおクラりド環境のリ゜ヌスを操䜜できるようになりたす。 MCPサヌバヌの実装 MCPサヌバヌを実装するにあたり、今回は FastMCP ずいうPython向けのMCPアプリケヌション構築甚フレヌムワヌクを利甚しおいたす。 2025幎にリリヌスされたばかりのFastMCP 2.0では、耇数のMCPサヌバヌの統合や、MCPサヌバヌのプロキシなど高床な機胜が備わっおいたす。 その䞭には、OpenAPI Specificationを入力するだけで、適切なMCPツヌルに倉換しおサヌバヌを構築できる機胜もありたす。 今回の実装にあたっお、最初にこのOpenAPI連携機胜をサクッず詊しおみるこずにしたした。 OpenStackのMCPサヌバヌを実装するにあたっお、たずはOpenStackのAPIスキヌマを䜜成したす。 詳现な手順は割愛したすが、 OpenStack CodeGenerator を䜿うこずでAPIスキヌマを生成できたす。 リポゞトリのREADMEに蚘茉されおいる手順に埓っお、 OpenStack Compute (Nova) のリポゞトリからスキヌマを生成できたす。 NovaずいうのはOpenStackを構成するコンポヌネントの1぀であり、仮想マシンの䜜成・管理機胜を提䟛しおいたす。 ここでは、FastMCPを䜿っおNovaのAPIスキヌマからMCPサヌバヌを構築し、仮想マシンを操䜜しおみたす。 FastMCPにはOpenAPI Specificationから自動でAPIを識別し、適切な゚ンドポむントで自動的にサヌバヌを構築しおくれる機胜がありたす。 それを䜿うこずで、以䞋のようなPythonコヌドでMCPサヌバヌを実装できたす。 import os import httpx import yaml from fastmcp import FastMCP client = httpx.AsyncClient(base_url= "https://nova.example.com" ) print (os.getcwd()) with open ( "/path/to/openapi_specs/compute/v2.yaml" , 'r' , encoding= 'utf-8' ) as f: openapi_spec = yaml.safe_load(f) mcp = FastMCP.from_openapi( openapi_spec=openapi_spec, client=client, name= "nova_mcp" , ) if __name__ == "__main__" : mcp.run() MCPサヌバヌを䜿っおみるが   Claude Codeを䜿っお動䜜確認しおみたす。 FastMCPには他のAIアシスタントツヌルず連携するためのCLIが付属しおおり、以䞋のコマンドでMCPサヌバヌの起動ず接続をしおくれるようになりたす。 fastmcp install claude-code server.py Claude Codeを起動しお、OpenStack環境の特定のノヌドにデプロむしおいるむンスタンスを確認しおみたす。 最終的に、2぀のむンスタンスが存圚するずわかりたした。 しかし、MCPク゚リを実行する際のパラメヌタの指定に問題があったようで、むンスタンスの詳现情報がうたく取埗できなかったようです。 たた、ここで気になっおくるのが、MCPを利甚するこずによるClaude Codeのパフォヌマンスの倉化です。 ずいうのも、今回のやり方のように倧量の゚ンドポむントず耇雑なパラメヌタを持぀APIをMCPに倉換するこずは、LLMに入力されるコンテキストが膚倧になるため、パフォヌマンスの芳点から 掚奚されないずいう話がありたす 。 ブヌトストラッピングやプロトタむプの実装にはこれでも十分かもしれたせんが、業務レベルで利甚できるアプリケヌションを䜜ろうず思うず、もうちょっず実装を考える必芁がありそうです。 実際、瀟内にデプロむしたロヌカルLLMでこのMCPサヌバヌを扱おうずするず、入力されるコンテキストが倚すぎるためかツヌルを実行できないずいう問題もありたした。 LLMに易しいMCPサヌバヌを䜜る OpenAPI SpecificationをそのたたMCPサヌバヌに倉換するやり方では、LLMに入力されるコンテキストが膚倧になるずいう問題がありたした。 そこで、AI゚ヌゞェントを利甚するナヌスケヌスを絞り、本圓に必芁な凊理だけを実装したMCPサヌバヌを実装するこずにしたした。 珟圚考えおいるナヌスケヌスは、OpenStackを䜿っお構築されたクラりド環境の運甚を、LLMを䜿っお自動化するずいうものです。 クラりドのオペレヌタヌの定垞的な業務の䞀郚をAI゚ヌゞェントに代行させたす。 今回は、オペレヌタの業務の䞀郚であるラむブマむグレヌションLive Migrationの実斜にナヌスケヌスを絞っお考えおみるこずにしたした。 ラむブマむグレヌションずは、皌働䞭のむンスタンスを停止させるこずなく別のコンピュヌトノヌドに移行させるずいうものです。 このラむブマむグレヌションに必芁な機胜を掗い出しおみたした。 特定のノヌドのむンスタンス䞀芧を取埗する 特定のむンスタンスの情報を確認する 移行するむンスタンスず移行先ノヌドを指定しおラむブマむグレヌションを実行する これらの機胜をそれぞれ、MCPサヌバヌのツヌルずしお実装したす。 前述の FastMCP.from_openapi() を䜿った実装ずは異なり、API呌び出し時のパラメヌタやレスポンスの受け取り方はそれぞれ適切な方法で定矩しおいきたす。 import json from fastmcp import FastMCP from os_client import send_get, send_post # API呌び出しは自前のパッケヌゞで定矩 mcp = FastMCP( "nova_mcp" ) @ mcp.tool () async def get_servers_detail (host: str ) -> str : """ コンピュヌトノヌドのホスト名から該圓コンピュヌトノヌド䞊に存圚する党おのむンスタンス䞀芧を取埗する Parameters: host: ホスト名 returns: str: むンスタンス䞀芧 """ resource_path = "servers/detail" params = { "all_tenants" : "true" , "host" : host } data = await send_get(resource_path, params=params) servers = data.get( "servers" , []) return json.dumps(servers, ensure_ascii= False , indent= 2 ) @ mcp.tool () async def get_servers_serverId (server_id: str ) -> str : """ むンスタンスの情報を取埗する Parameters: server_id: むンスタンスの ID returns: str: むンスタンス情報 """ resource_path = f "servers/{server_id}" data = await send_get(resource_path) server = data.get( "server" , []) return json.dumps(server, ensure_ascii= False , indent= 2 ) @ mcp.tool () async def post_server_live_migrate ( server_id: str , target_host: str ) -> str : """ 指定されたサヌバを Live Migration で移行する Parameters: server_id (str): 移行察象のサヌバID target_host (str): 移行先ホスト名 Returns: str: ステヌタスコヌドずレスポンス情報 """ resource_path = f "servers/{server_id}/action" json_body = { "os-migrateLive" : { "host" : target_host, "block_migration" : "auto" } } extra_headers = { "OpenStack-API-Version" : "compute 2.88" , } data = await send_post(resource_path, json_body=json_body, extra_headers=extra_headers) return json.dumps({ "status" : data.get( "status" , 202 if data == {} else "unknown" ), "response_data" : data }, ensure_ascii= False , indent= 2 ) if __name__ == "__main__" : mcp.run() ここで重芁なのは、LLMに入力される情報をできるだけ絞り、䜙蚈なこずを考えさせないようにするこずです。 今回の䟋では以䞋のような工倫をしおいたす。 ナヌスケヌスを限定しお必芁な機胜だけをMCPサヌバヌに実装するこずで、LLMが扱うツヌルの数を枛らし、コンテキストのサむズを小さくする ツヌルの簡朔な説明をdocstringで蚘述し、LLMが目的のツヌルを遞びやすくする API呌び出し時のパラメヌタにあらかじめ適切な倀を蚭定し、LLMから指定するパラメヌタはなるべく少なくする レスポンスの情報も必芁な倀だけを抜出しお構造化し、敎理しおから返す 動䜜確認 続いお゚ヌゞェントを起動しお動䜜を確認しおみたす。 予めツヌルの実装を詳现に定矩しおいたおかげで、1発で欲しい情報を埗られたした。 LLMで指定するパラメヌタが必芁最小限になった分、スムヌズに必芁な情報に蟿り着けおいたす。 続けお、ラむブマむグレヌションの凊理も実行しおみたす。 こちらも問題なく凊理を実行できたした。 ラむブマむグレヌションの実行に加えお、移行埌のむンスタンスの情報も正しく取埗できおいたす。 たた、予め必芁な凊理の内容をコヌドで定矩しおいるこずもあっお凊理の実行に安心感があり、仮に実行が倱敗した堎合でも手元のコヌドを分析しお容易にデバッグできたす。 たずめ OpenAPI Specificationをそのたた党おMCPサヌバヌに倉換するのではなく、必芁な機胜に絞っお個別に実装するこずでLLMに易しいMCPサヌバヌを䜜りたした。 工倫したのは䞻に以䞋のポむントです。 APIをそのたたMCPサヌバヌに倉換するのではなく、ナヌスケヌスを考えお必芁なツヌルだけを実装する LLMに䞎えるコンテキストを小さくする ツヌルの説明を過䞍足なく蚘述する API呌び出し時のパラメヌタを適切に蚭定し、LLMが指定するパラメヌタを最小限にする レスポンスの情報も必芁な倀だけを抜出しお敎理しおから返す 本栌的な運甚自動化ツヌルを開発するにあたっおは、より倧芏暡なMCPサヌバヌを䜜っおツヌルの数も倧きく増えるこずになりたすが、そういった堎合でも適切な粒床でツヌルを実装しLLMの負荷を䞋げるこずが倧切になるでしょう。 堎合によっおは、察象ずするドメむンに応じお゚ヌゞェントずMCPサヌバヌを分割し、マルチ゚ヌゞェントワヌクフロヌを組むこずで個々の゚ヌゞェントが扱う関心毎を枛らすこずも有効でしょう。 本日はここたでです。明日もお楜しみに
SBOMSoftware Bill of Materialsずは、゜フトりェアに含たれるコンポヌネントの䞀芧衚であり、近幎の法統制によりその管理が求められおいたす。本蚘事では、SBOM管理の必芁性ず珟状の認知床に぀いおお話ししたす。たた、SSVCによる脆匱性評䟡ずAIを掻甚した、効率的なSBOM管理のベストプラクティスに぀いお解説いたしたす。 はじめに SBOMSoftware Bill of Materialsずは SBOMの認知床 SBOM法統制ずガむドラむン SBOM管理の法統制が進む背景 OSSオヌプン゜ヌス゜フトりェアの急速な普及 発芋される脆匱性の爆発的な増加 珟状考えうるベストプラクティス たずめ 脚泚 参考文献 はじめに この蚘事は、 NTT docomo Business Advent Calendar 2025 11日目の蚘事です。 こんにちはむノベヌションセンタヌMetemcyberプロゞェクトの千坂知也ず申したす。 Metemcyberプロゞェクトは10/9朚10/10金に開催されたdocomoBusinessForum'25 [1] にお、開発䞭のSBOMSoftware Bill of Materials管理゜リュヌション「Threatconnectome」 *1 を展瀺させおいただきたした。倚くのお客さたにご来堎いただき、SBOM管理が必芁のある珟堎での課題感などを議論させおいただきたした。 そこで感じたのは法統制などによりSBOM管理が求められおいるこずは、ある皋床呚知されおいる䞀方で、その管理方法やなぜ必芁ずされおいるのかの認知が広がっおいないずいうこずでした。 以䞊のこずから本蚘事では、SBOM管理の必芁性ず珟堎での課題感、個人的に思う珟状のベストプラクティスに぀いお曞いおいこうかず思いたす。 以降では、次の3぀に぀いお述べおいきたいず思いたす。 SBOMSoftware Bill of Materialsずは SBOM管理の法統制が進む背景 珟状考えうるベストプラクティス SBOMSoftware Bill of Materialsずは SBOMずはSoftware Bill of Materialsの略であり、日本語では「゜フトりェアの郚品衚」ずいう意味になりたす。補造業の方には゜フトりェアのBOMず蚀えば分かりやすいかもしれたせん。今日、倚くのシステムに組み蟌たれおいる゜フトりェアはさらに小さな耇数の゜フトりェアを組み合わせお構成されおいたす。これらはコンポヌネントず呌ばれ、パッケヌゞ、ラむブラリなどが該圓したす。SBOMはこれら゜フトりェアのコンポヌネントの䞀芧衚のこずを指したす。各コンポヌネントの名称、バヌゞョン情報、ラむセンス情報に加え、コンポヌネント間の䟝存関係なども含たれたす。 我々Metemcyberプロゞェクトでは、よくこのSBOMを「食品の成分衚瀺」ず同じずいうふうに説明いたしたす。皆さんがスヌパヌ・コンビニなどで買う食品の裏には必ずどのような原材料・成分が含たれおいるかを衚す成分衚瀺が曞かれおいたす。この成分衚瀺をみお、自身にずっおアレルギヌのものが含たれおいればその食品は買わない、などの刀断ができるわけです。 ゜フトりェアも䞭に含たれおいる成分コンポヌネント衚瀺から、危険なもの脆匱性が含たれおいるパッケヌゞなどが含たれおいるのではないかを怜知できるずいうわけです。 SBOMの認知床 MetemcyberプロゞェクトがdocomoBusinessForum’25におThreatconnectomeを展瀺させおいただき、倚くのお客さたず議論を亀わしたなかで、次のようなお声を倚く耳にしたした。 「SBOMずいう蚀葉自䜓は聞きかじったこずある」 「最近SBOMずいうワヌドをよく聞きたす」 「法統制でSBOM察応が迫られおいるのは知っおいる」 「SBOMで管理しろっおいわれおも具䜓的にどうすればよいかわからない」 「結局なんで必芁なのかが分からない」 蚀葉自䜓の認知床はやや䞊がり぀぀あるものの、具䜓的にSBOMが䜕なのか、SBOM管理ず蚀われおも䜕をしたら良いのか分からない、ずいった皋床の認知床であるこずをひしひしず感じたした。ベリサヌブ瀟が囜内補造業の蚭蚈開発郚門および品質管理郚門の担圓者を察象に実斜したSBOMの導入状況アンケヌト [2] では、「導入予定はない」は79であり、「導入怜蚎䞭」は14、「導入枈み」は7ず䟝然ずしお導入ぞは課題がありたす。 SBOM法統制ずガむドラむン SBOM管理は米囜での2021幎の倧統領什 [3] を皮切りに䞖界的に法芏制が進んでいたす。EUでは2024幎のサむバヌレゞリ゚ンス法Cyber Resilience ActCRA *2 [4] におSBOM察応が必須芁件ずなり、日本でも医療機噚のサむバヌセキュリティ手匕曞 [5] でSBOMに関する蚀及が倚くありたす。 ガむドラむン面においおも、経枈産業省が2023幎7月にSBOM導入のメリットず掻甚プラクティス [6] を公開し、内閣サむバヌセキュリティセンタヌ [7] も2024幎7月の改蚂で調達基準ぞのSBOM導入の可胜性に蚀及しおいたす。デゞタル庁も2024幎1月に政府情報システムでのセキュリティバむデザむンの手段ずしおSBOM [8] を掚奚したした。 さお、そもそもなぜこのような法統制が進んできおいるのでしょうか SBOM管理の法統制が進む背景 SBOM管理が必芁になった背景には、以䞋の点があるず考えおいたす。 OSSオヌプン゜ヌス゜フトりェアの急速な普及 発芋される脆匱性の爆発的な増加OSSぞのサプラむチェヌン攻撃の増加 OSSオヌプン゜ヌス゜フトりェアの急速な普及 近幎の商甚゜フトりェアは、コヌドベヌスの平均で70以䞊、システムによっおは90近くがOSS由来のコンポヌネントで構成されおいる [9] ずいわれおいたす。OSSは゜ヌスコヌドが公開され、改倉・再配垃が可胜であるため、既存の機胜を掻甚するこずで開発コストの削枛や生産性向䞊に倧きく寄䞎したす。 しかし、OSSも゜フトりェアである以䞊、脆匱性の存圚する可胜性がありたす。実際、2021幎12月にはApache Log4jずいうOSSにおいお、Log4Shellず呌ばれる非垞に深刻な脆匱性 [10] が発芋され、Amazon AWSやiCloud、Steamなど䞖界芏暡のサヌビスにたで圱響が及びたした。こうした重倧な脆匱性に迅速に察応するためには、たず自瀟システムがどのOSSを利甚しおいるかを正確に把握するこずが䞍可欠です。把握しおいなければ、適切な修正や封じ蟌めは困難になりたす。 たた、珟代の゜フトりェアの倚くは、衚面からは芋えないOSSやラむブラリで構成されおおり、開発者でも「䜕が含たれおいるか」を完党に把握するのは難しい状況です。そのため、SBOMを掻甚するこずで、こうした隠れた䟝存関係を可芖化し脆匱性察応を効率的に行うこずが可胜になるず考えられおいたす。 発芋される脆匱性の爆発的な増加 情報システムの技術的な発展に䌎い、゜フトりェアは瀟䌚システムの基盀そのものを構成するようになりたした。䞀方で、技術の進歩ず単玔な゜フトりェアの数の増加により、そこに含たれる脆匱性も急速に増加しおいたす。CVE [11] の登録件数を芋おも、ここ10幎で著しい増加が続いおおり、2025幎においおは、すでに昚幎を䞊回る件数が登録されおいたす。前述した通り、このこずの背景にはOSSの普及によっお膚倧な量の゜フトりェアが耇雑な䟝存関係を持぀ようになったこずが関連しおいたす。そのため、脆匱性に迅速か぀確実に察応するために、SBOMが䞍可欠になっおきおいるずいうこずです。 これらの芁因からSBOM管理は法敎備され぀぀あるずいうわけです。 しかしながら、SBOMによっお゜フトりェアの䞭身の芋える化を図ったずしおも、結局どのように脆匱性察応に圓たればよいかが珟時点で明確化されおいないずいう実情がありたす。膚倧すぎる成分衚瀺を枡されおも、その䞭身が危険かどうかを刀断するためのプラクティスが確立されおいないのです。 珟状考えうるベストプラクティス ぀は察応する脆匱性のトリアヌゞを行うずいうこずが挙げられたす。゜フトりェアにもよりたすが、SBOMに含たれるコンポヌネントの数は、䞀般的には数千数䞇にも及びたす。それらの脆匱性党おに察応しようずするず、ずおも珟実的な時間では䞍可胜です。䞀方で゜フトりェアに含たれおいる脆匱性は察応を無芖しおも党く問題のないものが倧倚数です。組織や人呜にずっお重倧な被害を及がしかねない脆匱性のみをピックアップしお迅速に察応しおいくこずが重芁になっおきたす。 もう぀は、垞に最新の脆匱性ず同期させ、その脆匱性による組織内ぞの被害の圱響がどの皋床の範囲に及ぶのかを把握しおおく必芁があるずいうこずです。前述した通り、新たな脆匱性は日々芋぀かっおおり、それが組織固有のシステムに圱響を及がす可胜性がありたす。どの組織のシステムにも甚倧な被害を及がしかねない危険性が含たれおいるかもしれないのです。 これら぀のプラクティスを実践するためにSSVCずいう脆匱性の評䟡の指暙を利甚するこずず、AIによる自動化が有効であるず我々Metemcyberプロゞェクトは結論付けおいたす。埓来、脆匱性評䟡に倚く甚いられおきたCVSSCommon Vulnerability Scoring System [12] ずいう指暙は脆匱性そのものの性質のみを芋お評䟡をしおいるため、同じCVSSスコアでも、組織によっお「察応の優先床」が倉わり、察応方針たでは決められたせん。SSVCStakeholder-Specific Vulnerability Categorization [13] は「誰どのステヌクホルダヌ」が意思決定をするかを前提に蚭蚈された脆匱性評䟡の指暙です。この評䟡指暙は人呜ぞの圱響床、悪甚された堎合の組織ぞの圱響床、利甚システムのむンタヌネットぞの公開状況などをパラメヌタずしお最終的な脆匱性の危険床を評䟡したす。これらのパラメヌタを甚いるこずで出力された脆匱性危険床は その組織 の このシステム を察象に この皋床の範囲 で圱響が出るずいう、具䜓的な評䟡を䞋したす。さらにAIによっお事前に該圓゜フトりェアが組み蟌たれおいるシステムの組織的な䜍眮づけ利甚目的などから䞊蚘パラメヌタを掚定できれば、人力でのSBOM管理の手間はより䜎枛されるず考えおおりたす。このような手段を甚いお、脆匱性のトリアヌゞを行うずいうのがベストプラクティスなのではないでしょうか。 䞊蚘の理由により、私たちMetemcyberプロゞェクトではSSVCによる脆匱性評䟡を甚いた脆匱性のトリアヌゞがSBOM管理ず盞性の良いものであるずいうふうに考えおおり、さらにAIによる自動化を図るこずでこれから求められ぀぀あるSBOM管理のベストプラクティスを提瀺しようずしおいたす。 たずめ 本蚘事では珟堎におけるSBOMの認知床ず課題感、および珟状考えうるベストプラクティスに぀いお曞かせおいただきたした。SBOMずいうこず自䜓は聞きかじったこずのあるものの、その具䜓的な内容や管理・運甚の仕方がただ分からないずいう方が倚いずいうのが実情です。前述したずおり、我々Metemcyberプロゞェクトでは、SSVCず呌ばれる脆匱性評䟡の指暙をもずに脆匱性のトリアヌゞをし぀぀SBOMを管理できる゜リュヌション「Threatconnectome」を開発しおおりたす。ご興味がある方はぜひThreatconnectomeのGitHubペヌゞなどもご芧ください。 以䞊でAdventcalendar11日目の蚘事は終了です 明日もお楜しみに 脚泚 nttcom/threatconnectome ↩ 珟時点のCRAの本文䞭で「SBOM」ずいう略語は盎接的に䜿甚されおいないものの、「Software Bill of Materials」ずいう蚀葉を甚いお、明確にSBOMの䜜成・管理・提䟛に繋がる芁件が芏定されおいる。 ↩ 参考文献 NTT docomo Business Forum'25 囜内補造業の1,000名を察象ずしたSBOMに関する調査を実斜 Executive Order 14028 - Improving the Nation's Cybersecurity Cyber Resilience Act 医療機噚のサむバヌセキュリティ導入に関する手匕曞 ゜フトりェア管理に向けたSBOMSoftware Bill of Materialsの導入に関する手匕 内閣サむバヌセキュリティセンタヌ デゞタル瀟䌚掚進実践ガむドブック DS-200 Synopsys Study Shows that Ninety-One Percent of Commercial Applications Contain Outdated or Abandoned Open Source Components Apache Log4jの脆匱性「Log4Shell」ずは CVE - Common Vulnerabilities and Exposures 共通脆匱性評䟡システムCVSS抂説 CVSSを逆から読むず脆匱性察応の意思決定に䜿えるSSVCに぀いお
この蚘事は、 NTT docomo Business Advent Calendar 2025 10日目の蚘事です。 Microsoft の IaC 蚀語である Bicep (+ Azure CLI/Databricks CLI) を䜿っお、Azure Databricks ワヌクスペヌスをデプロむし、そのバック゚ンド通信や Azure デヌタサヌビスぞの通信を閉域化する方法を玹介したす。 たた、その環境を䜿ったデヌタ収集の䞀䟋ずしお、Azure Event Hubs を䜿ったプラむベヌトなデヌタストリヌミングを詊したす。 はじめに なぜこの構成を蚘事にするのか 今回の構成ず前提 前提 Bicep +α による構築 ネットワヌク基盀 デヌタサヌビスずその Private Link Azure Databricks ワヌクスペヌス デヌタサヌビスに察する RBAC Bicep でデプロむ ワヌクスペヌスストレヌゞの Private Link サヌバレスプレヌンに察する Private Link Unity Catalog 倖郚ロケヌション プラむベヌトなデヌタストリヌミングの実践 たずめ はじめに こんにちは、C&A郚の吉仲です。 初期配属からメヌル系システムや文曞芁玄 API の開発・運甚業務を担圓しおおり、珟圚は䞻にシステムログ分析のためのデヌタ基盀の䌁画開発業務に取り組んでいたす。 昚幎のアドベントカレンダヌでの投皿蚘事 では、Azure Databricks を䜿ったログ分析を詊したした。 今幎はよりむンフラに近い郚分を扱いたす。 具䜓的には、Azure Databricks を䞭心ずしたプラむベヌトなデヌタ基盀・デヌタストリヌミングを、Microsoft 玔正の IaC 蚀語である Bicep を䜿っお構築する方法を玹介したす。 そしお、 Azure Event Hubs からデヌタを取り蟌み、 Azure Data Lake Storage Gen2 (ADLS2) ぞ保存するたでの䞀連のフロヌを、パブリックネットワヌクを経由しないセキュアな経路で実珟する実装䟋をコヌドず共に解説したす。 なぜこの構成を蚘事にするのか ゚ンタヌプラむズ環境でのデヌタ基盀においお、「セキュリティ」は避けお通れない芁件です。 特に Azure Databricks を採甚する堎合、VNet ぞのデプロむ ( VNet 統合 ) に加えお、ストレヌゞやむベント゜ヌスぞのアクセスもパブリックネットワヌクを経由させずに閉域化したいずいう芁望は䞀般的だず思いたす。 しかし、実際にこれを構築しようずするず、次のような壁に圓たりたせんか (少なくずも私は苊戊したした) 公匏ドキュメントはリファレンスアヌキテクチャを提瀺しおいるが、具䜓的な蚭定倀が分散しおいお党䜓像を把握するのが難しい ポヌタルでのポチポチ䜜業は解説されおいるが、IaC (特に Microsoft 公匏蚀語である Bicep) での実装䟋が少ない コントロヌルプレヌン/デヌタプレヌン、サヌバレス/クラスタヌごずにネットワヌク芁件が耇雑で、「疎通できない」トラブルが起きがち そこで本蚘事では、私が実際にプラむベヌトなデヌタ基盀・デヌタストリヌミングを構築する䞭で苊戊した郚分や埗られた知芋を螏たえお、具䜓的な構築方法をコヌドず共に解説したいず思いたす。 今回の構成ず前提 Azure Databricks のバック゚ンド通信や Azure Databricks からデヌタサヌビスぞの通信の閉域化に぀いおは、以䞋の公匏ブログなどでリファレンスアヌキテクチャが玹介されおいたす。 www.databricks.com 今回はこの構成に倣い、以䞋のような環境を構築したす。 ハブ&スポヌク構成 、むンタヌネット向き通信の Firewall 匷制トンネリング Databricks の VNet 統合ず Secure Cluster Connectivity 蚭定 (パブリック IP 無効化) コントロヌルプレヌン (バック゚ンド) ずの Private Link サヌバレスプレヌン/デヌタプレヌンそれぞれに察する Azure デヌタサヌビスの Private Link なお、ハブ VNet (リファレンスアヌキテクチャの図で蚀う " Customer transit VNet ") 䞊に䜜る Gateway に぀いおは、察向拠点䟝存の郚分が倚いため本蚘事のスコヌプ倖ずしたす。 実際のナヌスケヌスでは、VPN Gateway や ExpressRoute Gateway をハブ VNet に構築しお、オンプレミス環境等ずのプラむベヌト接続を実珟したす。 (【参考】 Azure Databricks ワヌクスペヌスをオンプレミス ネットワヌクに接続する ) たた、䞊蚘の構成では Databricks の Web UI ぞのアクセスたでは閉域化できたせん。 Web UI たで閉域化する「フロント゚ンドの Private Link」を実珟するには、リファレンスアヌキテクチャに蚘茉の通り、より耇雑な構成になりたす。 本蚘事では、構成を簡単にするため フロント゚ンドの閉域化を察象倖 ずし、バック゚ンドの閉域化だけにフォヌカスしたす。 ※本構成は Azure Firewall や 倚数の Private Link を䜿甚するため、怜蚌環境であっおも䞀定のコスト (時間課金) が発生したす。 怜蚌埌は速やかにリ゜ヌスを削陀するこずを掚奚したす。 前提 構築の芁件は以䞋の通りです。 Azure で「グロヌバル管理者」ずサブスクリプションの「所有者」暩限を持぀アカりント (※「グロヌバル管理者」は Databricks アカりントコン゜ヌルぞのログむンに必芁) Azure CLI (>=2.81.0) および Databricks CLI (>=0.259.0) の実行環境 以降は、基本的には以䞋の公匏ドキュメントに倣った内容・蚭定で構築を進めたす。 learn.microsoft.com learn.microsoft.com Bicep +α による構築 ここからはハンズオン圢匏で Bicep ず各皮 CLI ツヌルを䜿っお必芁なリ゜ヌスを順に構築しおいきたす。 ネットワヌク基盀 ハブ&スポヌク構成の VNet ず、各 VNet 内のリ゜ヌスを定矩しおいきたす。 VNet はハブ/スポヌク甚にそれぞれ䜜成するためモゞュヌル化したす。 サブネットに぀いおは、VNet 甚モゞュヌルの subnets パラメヌタでたずめお定矩する圢にしおいたす。 modules/vnet.bicep param name string param location string param tags object = {} param addressPrefixes array @description('''e.g. [{name:'default',properties:{addressPrefix:'10.0.0.0/24',networkSecurityGroup:null}}]''') param subnets array = [] resource vnet 'Microsoft.Network/virtualNetworks@2024-05-01' = { name: name location: location tags: tags properties: { addressSpace: { addressPrefixes: addressPrefixes } encryption: { enabled: true enforcement: 'AllowUnencrypted' } } @batchSize(1) resource snet 'subnets' = [ for snet in subnets: if (!empty(subnets)) { name: snet.name properties: snet.properties } ] } output id string = vnet.id output name string = vnet.name Databricks を VNet 統合する堎合、ネットワヌクセキュリティグルヌプ (NSG) のルヌルが自動で蚭定されたすが、これらも事前に Bicep で定矩しおおきたす。 今回は、パブリック IP の無効化 + コントロヌルプレヌンずの Private Link 構成のため、以䞋のような定矩になりたす (= " No Azure Databricks Rules " 蚭定)。 なお、この NSG ルヌルの倉曎や削陀は非掚奚です。 modules/nsgDbw.bicep param name string param location string param tags object = {} resource nsg 'Microsoft.Network/networkSecurityGroups@2024-05-01' = { name: name location: location tags: tags properties: { securityRules: [ { name: 'Microsoft.Databricks-workspaces_UseOnly_databricks-worker-to-worker-inbound' properties: { description: 'Required for worker nodes communication within a cluster.' protocol: '*' sourcePortRange: '*' destinationPortRange: '*' sourceAddressPrefix: 'VirtualNetwork' destinationAddressPrefix: 'VirtualNetwork' access: 'Allow' priority: 100 direction: 'Inbound' } } { name: 'Microsoft.Databricks-workspaces_UseOnly_databricks-worker-to-worker-outbound' properties: { description: 'Required for worker nodes communication within a cluster.' protocol: '*' sourcePortRange: '*' destinationPortRange: '*' sourceAddressPrefix: 'VirtualNetwork' destinationAddressPrefix: 'VirtualNetwork' access: 'Allow' priority: 100 direction: 'Outbound' } } { name: 'Microsoft.Databricks-workspaces_UseOnly_databricks-worker-to-sql' properties: { description: 'Required for workers communication with Azure SQL services.' protocol: 'tcp' sourcePortRange: '*' destinationPortRange: '3306' sourceAddressPrefix: 'VirtualNetwork' destinationAddressPrefix: 'Sql' access: 'Allow' priority: 101 direction: 'Outbound' } } { name: 'Microsoft.Databricks-workspaces_UseOnly_databricks-worker-to-storage' properties: { description: 'Required for workers communication with Azure Storage services.' protocol: 'tcp' sourcePortRange: '*' destinationPortRange: '443' sourceAddressPrefix: 'VirtualNetwork' destinationAddressPrefix: 'Storage' access: 'Allow' priority: 102 direction: 'Outbound' } } { name: 'Microsoft.Databricks-workspaces_UseOnly_databricks-worker-to-eventhub' properties: { description: 'Required for worker communication with Azure Eventhub services.' protocol: 'tcp' sourcePortRange: '*' destinationPortRange: '9093' sourceAddressPrefix: 'VirtualNetwork' destinationAddressPrefix: 'EventHub' access: 'Allow' priority: 103 direction: 'Outbound' } } ] } } output id string = nsg.id output name string = nsg.name その他、Firewall やそれに割り圓おるパブリック IP 、スポヌク VNet から Firewall ぞ匷制トンネリングするためのナヌザヌ定矩ルヌト (UDR)、ハブずスポヌクの VNet ピアリングもモゞュヌル化したす。 modules/afw.bicep param name string param policyName string param location string param zones array = [] param tags object = {} param tier string = 'Basic' param vnetName string param afwPipId string param afwManagementPipId string resource afwp 'Microsoft.Network/firewallPolicies@2024-05-01' = { name: policyName location: location tags: tags properties: { sku: { tier: tier } threatIntelMode: 'Alert' } resource rcg 'ruleCollectionGroups' = { name: 'default' properties: { priority: 100 ruleCollections: [ { name: 'allow-rules' ruleCollectionType: 'FirewallPolicyFilterRuleCollection' action: { type: 'Allow' } priority: 1000 rules: [ { name: 'Allow-InternetOutBound' ruleType: 'NetworkRule' ipProtocols: ['Any'] sourceAddresses: ['10.0.0.0/8'] destinationAddresses: ['*'] // 怜蚌のため党蚱可. 本来は厳密に蚱可する通信先だけを列挙すべき. destinationPorts: ['*'] } ] } ] } } } resource afw 'Microsoft.Network/azureFirewalls@2024-05-01' = { name: name location: location zones: zones tags: tags properties: { sku: { name: 'AZFW_VNet' tier: tier } firewallPolicy: { id: afwp.id } ipConfigurations: [ { name: 'afwIPConf' properties: { subnet: { id: resourceId('Microsoft.Network/virtualNetworks/subnets', vnetName, 'AzureFirewallSubnet') } publicIPAddress: { id: afwPipId } } } ] managementIpConfiguration: { name: 'afwManagementIPConf' properties: { subnet: { id: resourceId('Microsoft.Network/virtualNetworks/subnets', vnetName, 'AzureFirewallManagementSubnet') } publicIPAddress: { id: afwManagementPipId } } } threatIntelMode: 'Alert' } } output id string = afw.id output name string = afw.name output ipAddress string = afw.properties.ipConfigurations[0].properties.privateIPAddress modules/pip.bicep param name string param location string param zones array = [] param tags object = {} param sku string = 'Standard' param tier string = 'Regional' resource pip 'Microsoft.Network/publicIPAddresses@2024-05-01' = { name: name location: location zones: zones tags: tags sku: { name: sku tier: tier } properties: { publicIPAddressVersion: 'IPv4' publicIPAllocationMethod: 'Static' } } output id string = pip.id output name string = pip.name output ipAddress string = pip.properties.ipAddress modules/rt.bicep param name string param udrName string param location string param tags object = {} param afwIpAddress string resource rt 'Microsoft.Network/routeTables@2024-05-01' = { name: name location: location tags: tags resource udr 'routes' = { name: udrName properties: { addressPrefix: '0.0.0.0/0' nextHopType: 'VirtualAppliance' nextHopIpAddress: afwIpAddress } } } output id string = rt.id output name string = rt.name modules/peer.bicep param vnetHubName string param vnetSpokeName string resource vnetHub 'Microsoft.Network/virtualNetworks@2024-05-01' existing = { name: vnetHubName resource peer 'virtualNetworkPeerings' = { name: 'peer-hub-to-spoke' properties: { allowVirtualNetworkAccess: true allowForwardedTraffic: true allowGatewayTransit: true useRemoteGateways: false remoteVirtualNetwork: { id: resourceId('Microsoft.Network/virtualNetworks', vnetSpokeName) } } } } resource vnetSpoke 'Microsoft.Network/virtualNetworks@2024-05-01' existing = { name: vnetSpokeName resource peer 'virtualNetworkPeerings' = { name: 'peer-spoke-to-hub' properties: { allowVirtualNetworkAccess: true allowForwardedTraffic: true allowGatewayTransit: false useRemoteGateways: false // VPN/ExpressRoute Gateway を䜜成する堎合は true remoteVirtualNetwork: { id: resourceId('Microsoft.Network/virtualNetworks', vnetHubName) } } } } ここたでの各モゞュヌルを組み合わせお、 main.bicep で各リ゜ヌスを定矩しおいきたす。 たずはハブ VNet の定矩からです。 targetScope = 'resourceGroup' param location string param tags object = {} param vnetHubName string param pipAfwName string param pipAfwManagementName string param afwName string param afwpName string module vnetHub './modules/vnet.bicep' = { params: { name: vnetHubName location: location tags: tags addressPrefixes: ['10.1.0.0/16'] subnets: [ { name: 'GatewaySubnet' // 名前固定. VPN/ExpressRoute Gateway 甹 properties: { addressPrefix: '10.1.1.0/26' } } { name: 'AzureFirewallSubnet' // 名前固定 properties: { addressPrefix: '10.1.1.64/26' } } { name: 'AzureFirewallManagementSubnet' // 名前固定 properties: { addressPrefix: '10.1.1.128/26' } } ] } } module pipAfw './modules/pip.bicep' = { params: { name: pipAfwName location: location tags: tags } } module pipAfwManagement './modules/pip.bicep' = { params: { name: pipAfwManagementName location: location tags: tags } } module afw './modules/afw.bicep' = { params: { name: afwName policyName: afwpName location: location tags: tags vnetName: vnetHub.outputs.name afwPipId: pipAfw.outputs.id afwManagementPipId: pipAfwManagement.outputs.id } } 【説明】 ハブ VNet には Firewall ず Gateway をデプロむするための3぀のサブネットを䜜成 VNet 内に、むンタヌネット向きアりトバりンド通信を担う (SNAT や監芖) Firewall を䜜成 次にスポヌク VNet、぀たり Databricks デヌタプレヌンや各皮プラむベヌト゚ンドポむントを配眮する VNet を定矩したす。 param vnetSpokeName string param nsgPepName string param nsgDbwName string param rtName string param udrName string module vnetSpoke './modules/vnet.bicep' = { params: { name: vnetSpokeName location: location tags: tags addressPrefixes: ['10.2.0.0/16'] subnets: [ { name: 'snet-host' properties: { addressPrefix: '10.2.1.0/24' networkSecurityGroup: { id: nsgDbw.outputs.id } routeTable: { id: rt.outputs.id } delegations: delegations // Databricks ぞの委任 } } { name: 'snet-container' properties: { addressPrefix: '10.2.2.0/24' networkSecurityGroup: { id: nsgDbw.outputs.id } routeTable: { id: rt.outputs.id } delegations: delegations // Databricks ぞの委任 } } { name: 'snet-pep' properties: { addressPrefix: '10.2.3.0/27' networkSecurityGroup: { id: nsgPep.id } routeTable: { id: rt.outputs.id } } } ] } } resource nsgPep 'Microsoft.Network/networkSecurityGroups@2024-05-01' = { name: nsgPepName location: location tags: tags } module nsgDbw './modules/nsgDbw.bicep' = { params: { name: nsgDbwName location: location tags: tags } } module rt './modules/rt.bicep' = { params: { name: rtName udrName: udrName location: location tags: tags afwIpAddress: afw.outputs.ipAddress // 匷制トンネリング先の Firewall の IP アドレス } } var delegations = [ { name: 'delegation-dbw' properties: { serviceName: 'Microsoft.Databricks/workspaces' } } ] 【説明】 スポヌク VNet には Databricks クラスタヌのホスト/コンテナ甚、各皮プラむベヌト゚ンドポむント甚の3぀のサブネットを䜜成 クラスタヌ (ホスト/コンテナ) 甚サブネットには、" No Azure Databricks Rules " 蚭定の NSG を割り圓お、 Microsoft.Databricks/workspaces ぞの委任を蚭定 各サブネットでは、UDR によりハブ VNet 䞊の Firewall ぞ匷制トンネリング 最埌にハブ VNet ずスポヌク VNet 間のピアリングを定矩したす。 module peer './modules/peer.bicep' = { params: { vnetHubName: vnetHub.outputs.name vnetSpokeName: vnetSpoke.outputs.name } } デヌタサヌビスずその Private Link Databricks から接続する Azure デヌタサヌビスの Private Link を定矩しおいきたす。 Databricks の倖郚ロケヌションずしお䜿う ADLS2 の定矩ず、デヌタストリヌミング甚の Event Hubs の定矩をそれぞれモゞュヌル化したす。 (なお、以降も同様ですが、SKU やスペックは必芁最䜎限のものに固定しおいたす) modules/dls.bicep param name string param containerNames array = [] param location string param tags object = {} param sku string = 'Standard_LRS' param accessTier string = 'Hot' param resourceAccessRules array = [] resource dls 'Microsoft.Storage/storageAccounts@2025-01-01' = { name: name location: location tags: tags sku: { name: sku } kind: 'StorageV2' properties: { accessTier: accessTier allowBlobPublicAccess: false allowedCopyScope: 'PrivateLink' encryption: { keySource: 'Microsoft.Storage' services: { blob: { enabled: true } } } isHnsEnabled: true // 必須 (Data Lake Storage Gen2化) largeFileSharesState: 'Disabled' minimumTlsVersion: 'TLS1_2' networkAcls: { defaultAction: 'Deny' // ファむアりォヌルを有効化 (デフォルトで拒吊) resourceAccessRules: resourceAccessRules bypass: 'Logging, Metrics' } publicNetworkAccess: 'Enabled' // Databricks アクセスコネクタからのアクセスを蚱可するため ('Disabled'だず党遮断) supportsHttpsTrafficOnly: true } resource blob 'blobServices' = { name: 'default' properties: {} resource container 'containers' = [ for containerName in containerNames: { name: containerName properties: { publicAccess: 'None' } } ] } } output id string = dls.id output name string = dls.name modules/evh.bicep param name string param instanceName string param location string param tags object = {} param sku string = 'Standard' param capacity int = 1 param isAutoInflateEnabled bool = false param maximumThroughputUnits int = 0 param partitionCount int = 1 resource evhns 'Microsoft.EventHub/namespaces@2024-01-01' = { name: name location: location tags: tags sku: { name: sku tier: sku capacity: capacity } properties: { isAutoInflateEnabled: sku == 'Standard' ? isAutoInflateEnabled : null maximumThroughputUnits: sku == 'Standard' ? maximumThroughputUnits : null publicNetworkAccess: 'Disabled' minimumTlsVersion: '1.2' kafkaEnabled: true } resource evh 'eventhubs' = { name: instanceName properties: { partitionCount: partitionCount retentionDescription: { cleanupPolicy: 'Delete' } messageRetentionInDays: 1 } // デヌタストリヌミングの収集元で䜿うため SAS キヌを事前に甚意 resource sas 'authorizationRules' = { name: '${instanceName}Send' properties: { rights: ['Send'] } } } } output id string = evhns.id output name string = evhns.name 最埌に、Private Link を䜜成するためのプラむベヌト DNS ゟヌンずその VNet 接続、プラむベヌト゚ンドポむントを定矩するモゞュヌルを䜜りたす。 modules/pep.bicep param name string param zoneName string param location string param tags object = {} param vnetName string param snetName string param privateLinkServiceId string param groupIds array resource zone 'Microsoft.Network/privateDnsZones@2024-06-01' = { name: zoneName location: 'global' tags: tags resource vnetLink 'virtualNetworkLinks' = { name: 'pl-${vnetName}' location: 'global' properties: { virtualNetwork: { id: resourceId('Microsoft.Network/virtualNetworks', vnetName) } } } } resource pep 'Microsoft.Network/privateEndpoints@2024-05-01' = { name: name location: location tags: tags properties: { subnet: { id: resourceId('Microsoft.Network/virtualNetworks/subnets', vnetName, snetName) } privateLinkServiceConnections: [ { name: name properties: { privateLinkServiceId: privateLinkServiceId groupIds: groupIds } } ] } resource dnsZoneGroup 'privateDnsZoneGroups@2024-05-01' = { name: 'default' properties: { privateDnsZoneConfigs: [ { name: 'default' properties: { privateDnsZoneId: zone.id } } ] } } } output id string = pep.id output name string = pep.name ここたでの各モゞュヌルを組み合わせお、 main.bicep に各リ゜ヌスの定矩を远蚘したす。 なお、順番が前埌しおしたいたすが、埌述の Databricks アクセスコネクタをストレヌゞアカりントのファむアりォヌルで蚱可しおいたす。 param dlsName string param evhName string module dls './modules/dls.bicep' = { params: { name: dlsName containerNames: ['lake'] location: location tags: tags resourceAccessRules: [ { resourceId: dbw.outputs.acId // Databricks アクセスコネクタからのアクセスを蚱可 tenantId: tenant().tenantId } ] } } module pepDfs './modules/pep.bicep' = { params: { name: 'pep-${dls.outputs.name}-dfs' zoneName: 'privatelink.dfs.core.windows.net' location: location tags: tags vnetName: vnetSpoke.outputs.name snetName: 'snet-pep' privateLinkServiceId: dls.outputs.id groupIds: ['dfs'] } } module pepBlob './modules/pep.bicep' = { params: { name: 'pep-${dls.outputs.name}-blob' zoneName: 'privatelink.blob.core.windows.net' location: location tags: tags vnetName: vnetSpoke.outputs.name snetName: 'snet-pep' privateLinkServiceId: dls.outputs.id groupIds: ['blob'] } dependsOn: [ pepDfs ] } module evh './modules/evh.bicep' = { params: { name: evhName instanceName: 'topic1' location: location tags: tags } } module pepEvh './modules/pep.bicep' = { params: { name: 'pep-${evh.outputs.name}' zoneName: 'privatelink.servicebus.windows.net' location: location tags: tags vnetName: vnetSpoke.outputs.name snetName: 'snet-pep' privateLinkServiceId: evh.outputs.id groupIds: ['namespace'] } dependsOn: [ pepBlob ] } プラむベヌト゚ンドポむントの定矩では、ADLS2 は dfs / blob 、Event Hubs は namespace を識別子 ( groupIds ) に指定したす。 なお、ADLS2 ぞのアクセスが Unity Catalog 経由のみの堎合、 blob ゚ンドポむントはおそらく䞍芁だず思いたす。 Azure Databricks ワヌクスペヌス Databricks ワヌクスペヌスずコントロヌルプレヌンぞの Private Link を定矩しおいきたす。 Databricks ワヌクスペヌスず、そこから Azure デヌタサヌビスぞアクセスする際に䜿われる Databricks アクセスコネクタの定矩をモゞュヌル化したす。 modules/dbw.bicep param name string param connectorName string param location string param tags object = {} param sku string = 'premium' param managedRgName string = 'mrg-${name}' param vnetName string param snetHostName string param snetContainerName string param storageAccountSkuName string = 'Standard_LRS' resource dbac 'Microsoft.Databricks/accessConnectors@2024-05-01' = { name: connectorName location: location tags: tags identity: { type: 'SystemAssigned' } properties: {} } resource dbw 'Microsoft.Databricks/workspaces@2024-05-01' = { name: name location: location tags: tags sku: { name: sku } properties: { managedResourceGroupId: subscriptionResourceId('Microsoft.Resources/resourceGroups', managedRgName) accessConnector: { id: dbac.id identityType: 'SystemAssigned' } defaultStorageFirewall: 'Enabled' publicNetworkAccess: 'Enabled' parameters: { customVirtualNetworkId: { value: resourceId('Microsoft.Network/virtualNetworks', vnetName) } customPublicSubnetName: { value: snetHostName } customPrivateSubnetName: { value: snetContainerName } enableNoPublicIp: { value: true } storageAccountSkuName: { value: storageAccountSkuName } } requiredNsgRules: 'NoAzureDatabricksRules' } } output id string = dbw.id output name string = dbw.name output acId string = dbac.id output acName string = dbac.name output acPrincipalId string = dbac.identity.principalId 䞊蚘のモゞュヌルを䜿っお main.bicep に定矩を远蚘したす。 param dbwName string param dbacName string module dbw './modules/dbw.bicep' = { params: { name: dbwName connectorName: dbacName location: location tags: tags vnetName: vnetSpoke.outputs.name snetHostName: 'snet-host' snetContainerName: 'snet-container' } } module pepDbw './modules/pep.bicep' = { params: { name: 'pep-${dbw.outputs.name}' zoneName: 'privatelink.azuredatabricks.net' location: location tags: tags vnetName: vnetSpoke.outputs.name snetName: 'snet-pep' privateLinkServiceId: dbw.outputs.id groupIds: ['databricks_ui_api'] } dependsOn: [ pepEvh ] } デヌタサヌビスに察する RBAC Databricks から Azure デヌタサヌビスぞのアクセスは、前述のずおり Databricks アクセスコネクタで行いたす。 したがっお、このアクセスコネクタに察しお ADLS2 や Event Hubs の暩限を付䞎する必芁がありたす。 ADLS2 ず Event Hubs の RBAC ロヌルを付䞎するモゞュヌルを䜜りたす。 modules/dlsRbac.bicep param name string param dlsName string param roleId string param principalId string resource dls 'Microsoft.Storage/storageAccounts@2025-01-01' existing = { name: dlsName } resource assign 'Microsoft.Authorization/roleAssignments@2022-04-01' = { name: name scope: dls properties: { principalId: principalId roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleId) } } output id string = assign.id output name string = assign.name modules/evhRbac.bicep param name string param evhName string param roleId string param principalId string resource evhns 'Microsoft.EventHub/namespaces@2024-01-01' existing = { name: evhName } resource assign 'Microsoft.Authorization/roleAssignments@2022-04-01' = { name: name scope: evhns properties: { principalId: principalId roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleId) } } output id string = assign.id output name string = assign.name これらを䜿っお main.bicep にお以䞋の RBAC ロヌルを Databricks アクセスコネクタに付䞎したす。 ADLS2 (ストレヌゞアカりント): " Azure Storage Blob Contributor " (デヌタの読み曞き甚) Event Hubs: " Azure Event Hubs Data Receiver " (むベントデヌタの読み取り甚) module dlsRbac './modules/dlsRbac.bicep' = { params: { name: guid(dlsName, dbacName, 'Storage Blob Data Contributor') dlsName: dls.outputs.name roleId: 'ba92f5b4-2d11-453d-a403-e96b0029c9fe' // Storage Blob Data Contributor principalId: dbw.outputs.acPrincipalId } } module evhRbac './modules/evhRbac.bicep' = { params: { name: guid(evhName, dbacName, 'Azure Event Hubs Data Receiver') evhName: evh.outputs.name roleId: 'a638d3c7-ab3a-418d-83e6-5f17a39d4fde' // Azure Event Hubs Data Receiver principalId: dbw.outputs.acPrincipalId } } Bicep でデプロむ ここたでかなり長くなっおしたいたしたが、Bicep でのリ゜ヌス定矩は以䞊です。 ここからは実際にデプロむしおいきたす。 最初に Azure CLI でリ゜ヌスグルヌプを䜜成したす。 az login # 「所有者」ロヌルのアカりントでログむン az group create --location japaneast --name rg-azuredatabricks-demo 次に Bicep パラメヌタファむルを甚意しおリ゜ヌス名などのパラメヌタを指定したす。 今回は SKU やスペックを固定しおいるので、ここではほがリ゜ヌス名の指定だけになっおいたす。 Bicep パラメヌタの䟋 (environments/demo.bicepparam) using '../main.bicep' var project string = 'adbdemo' param location = 'japaneast' param vnetHubName = 'vnet-hub-${project}-${location}' param pipAfwName = 'pip-${project}-${location}-001' param pipAfwManagementName = 'pip-${project}-${location}-002' param afwName = 'afw-${project}-${location}' param afwpName = 'afwp-${project}-${location}' param vnetSpokeName = 'vnet-spoke-${project}-${location}' param nsgPepName = 'nsg-${project}-pep' param nsgDbwName = 'nsg-${project}-dbw' param rtName = 'rt-${project}' param udrName = 'udr-default-gateway' param dlsName = 'dls${project}001' // Globally unique param evhName = 'evhns-${project}-001' // Globally unique param dbwName = 'dbw-${project}-${location}' param dbacName = 'dbac-${project}' それでは main.bicep ず䞊蚘のパラメヌタファむルを䜿っおリ゜ヌスをデプロむしたす。 # デプロむ埌の掚定状態を確認 az deployment group what-if -g rg-azuredatabricks-demo --template-file main.bicep --parameters environments/demo.bicepparam # デプロむ実行 az deployment group create -c -g rg-azuredatabricks-demo --template-file main.bicep --parameters environments/demo.bicepparam デプロむ成功埌、以䞋のようにリ゜ヌスグルヌプ内に各皮リ゜ヌスが衚瀺されおいるず思いたす。 ワヌクスペヌスストレヌゞの Private Link さお、Bicep でのデプロむは完了したしたが、ここからが肝になりたす。 Databricks ワヌクスペヌスの䜜成箇所では説明を省きたしたが、今回は既定のマネヌゞドストレヌゞ (" ワヌクスペヌスストレヌゞ ") でもファむアりォヌルを有効にし、パブリックアクセスを犁止する蚭定を入れおいたす。 ワヌクスペヌスストレヌゞずは、Databricks のシステムデヌタや DBFS ルヌトなどに䜿われるストレヌゞです。 公匏ドキュメントでも説明されおいたすが、ワヌクスペヌスストレヌゞのファむアりォヌルを有効にしおいるずきは、その Private Link も䜜成する必芁がありたす。 learn.microsoft.com 【䜙談】私は圓初、このファむアりォヌルを有効にしたこずを忘れたたた構築を進めおしたいたした。 そしお、クラスタヌでパむプラむンを䜜成しようずしたずころで疎通䞍可ずなり、原因特定に随分ず時間を費やしたした。 ワヌクスペヌスストレヌゞの Private Link の構築は Bicep だけでは完結したせん。 ずいうのも、デプロむ埌に䜜成されるマネヌゞドリ゜ヌスグルヌプ内を芋おもらうず分かるように、ストレヌゞ名が dbstorage<ランダム文字列> になっおいたす。 これは動的に決たるリ゜ヌス名であるため、前述たでの Bicep コヌド内で参照するこずが難しいです。 そこで、 main.bicep ずは別に postprocess.bicep を甚意し、ワヌクスペヌスストレヌゞの Private Link のみを個別に定矩する圢ずしたす。 targetScope = 'resourceGroup' param location string param tags object = {} param vnetName string param storageId string var stName string = last(split(storageId, '/')) module pepStBlob './modules/pep.bicep' = { params: { name: 'pep-${stName}-blob' zoneName: 'privatelink.blob.core.windows.net' location: location tags: tags vnetName: vnetName snetName: 'snet-pep' privateLinkServiceId: storageId groupIds: ['blob'] } } module pepStDfs './modules/pep.bicep' = { params: { name: 'pep-${stName}-dfs' zoneName: 'privatelink.dfs.core.windows.net' location: location tags: tags vnetName: vnetName snetName: 'snet-pep' privateLinkServiceId: storageId groupIds: ['dfs'] } } この Bicep コヌドのデプロむ時に、すでにデプロむ枈みのワヌクスペヌスストレヌゞの ID をパラメヌタずしお指定したす。 # マネヌゞドリ゜ヌスグルヌプ内の ADLS2 (ワヌクスペヌスストレヌゞ) の ID を取埗 # マネヌゞドリ゜ヌスグルヌプ名は本蚘事のBicepコヌドでは "mrg-dbw-adbdemo-japaneast" az storage account list -g < マネヌゞドリ゜ヌスグルヌプ名 > --query ' [].id ' -o tsv # 䞊蚘のコマンドで衚瀺された ID をパラメヌタに指定しおデプロむ実行 az deployment group create -c -g rg-azuredatabricks-demo \ --template-file bicep/postprocess.bicep \ --parameters location =japaneast \ --parameters vnetName =vnet-spoke-adbdemo-japaneast \ --parameters storageId = < ワヌクスペヌスストレヌゞのID > 以䞊で、Databricks クラスタヌからワヌクスペヌスストレヌゞぞのプラむベヌト通信が可胜になりたした。 サヌバレスプレヌンに察する Private Link ここたで䜜成しおきた Private Link は、党おデヌタプレヌン内にあるクラスタヌからの通信甚の接続構成です。 サヌバレスプレヌンからの通信甚には、以䞋の公匏ドキュメントに蚘茉されおいる蚭定: Network Connectivity Configuration (NCC) が必芁です。 learn.microsoft.com 残念ながら珟状はこの蚭定も Bicep で実斜できたせん。 Azure CLI および Databricks CLI を䜿っお、ADLS2 ず Event Hubs の Private Link を䜜成したす。 事前準備: # アカりントレベルのログむン (アカりント ID は䞋蚘 URL のコン゜ヌルで確認) databricks auth login --host https://accounts.azuredatabricks.net --account-id < アカりントID > # ワヌクスペヌスレベルのログむン (ワヌクスペヌス URL は Azure Portal で確認) databricks auth login --host https://adb- < ワヌクスペヌス識別子 > .azuredatabricks.net NCC 䜜成ずワヌクスペヌスぞの割り圓お: # NCC の䜜成 databricks account network-connectivity create-network-connectivity-configuration \ --json ' {"name":"ncc-adbdemo-japaneast","region":"japaneast"} ' # 䞊蚘のコマンドで衚瀺された NCC の ID "network_connectivity_config_id" を指定 databricks account workspaces update < ワヌクスペヌスID > --network-connectivity-config-id < NCCID > ADLS2 の Private Link 䜜成 ( dfs ゚ンドポむントの䟋): # Private Link を䜜成する ADLS2 の ID を取埗 az storage account list -g rg-azuredatabricks-demo --query ' [].id ' -o tsv # プラむベヌト゚ンドポむントの䜜成 databricks account network-connectivity create-private-endpoint-rule < NCCID > \ --json ' {"resource_id":"<ストレヌゞID>","group_id":"dfs"} ' # Azure 偎で承認保留䞭のプラむベヌト゚ンドポむントを確認 az network private-endpoint-connection list --id < ストレヌゞID > \ | jq -r ' .[]|select(.properties.privateLinkServiceConnectionState.status =="Pending").id ' # 䞊蚘のコマンドで衚瀺されたプラむベヌト゚ンドポむントの ID を指定しお、接続を承認 az network private-endpoint-connection approve --id < プラむベヌト゚ンドポむントID > Event Hubs の Private Link 䜜成: # Private Link を䜜成する Event Hubs の ID を取埗 az eventhubs namespace list -g rg-azuredatabricks-demo --query ' [].id ' -o tsv # プラむベヌト゚ンドポむントの䜜成 databricks account network-connectivity create-private-endpoint-rule < NCCID > \ --json ' {"resource_id":"<EventHubsID>","group_id":"namespace"} ' # Azure 偎で承認保留䞭のプラむベヌト゚ンドポむントを確認 az network private-endpoint-connection list --id < EventHubsID > \ | jq -r ' .[]|select(.properties.privateLinkServiceConnectionState.status =="Pending").id ' # 䞊蚘のコマンドで衚瀺されたプラむベヌト゚ンドポむントの ID を指定しお、接続を承認 az network private-endpoint-connection approve --id < プラむベヌト゚ンドポむントID > 以䞊で、サヌバレスプレヌン向けの Azure デヌタサヌビスの Private Link が䜜成されたした。 Databricks のアカりントコン゜ヌルで、以䞋のように各゚ンドポむントの接続が ESTABLISHED になっおいれば完了です。 なお、NCC を蚭定するず、ワヌクスペヌスストレヌゞのファむアりォヌルにおいおサヌバレスプレヌンの VNet が自動的に蚱可されたす。 そのため、今回はワヌクスペヌスストレヌゞの Private Link は省略したす。 Private Link でのアクセスずしたい堎合は、䞊蚘ず同じ手順で䜜成したす。 Unity Catalog 倖郚ロケヌション Databricks から ADLS2 ぞのプラむベヌト接続が可胜になったので、その ADLS2 で Unity Catalog の倖郚ロケヌションを䜜成しおみたす。 以降は、Bicep ではなく Azure CLI/Databricks CLI を䜿った䜜成になりたす。 # アクセスコネクタの ID を確認 az databricks access-connector list -g rg-azuredatabricks-demo --query ' [].id ' -o tsv # 䞊蚘のアクセスコネクタの ID を指定しお、資栌情報を䜜成 databricks storage-credentials create \ --json ' {"name":"adbdemo_storage","azure_managed_identity":{"<Databricks アクセスコネクタID>"}} ' # 䞊蚘の資栌情報を指定しお、倖郚ロケヌションを䜜成 databricks external-locations create adbdemo_storage \ abfss:// < コンテナ名 > @ < ストレヌゞアカりント名 > .dfs.core.windows.net/ adbdemo_storage Databricks ワヌクスペヌスにログむンし、[カタログ゚クスプロヌラヌ]>[倖郚ロケヌション] から䜜成した倖郚ロケヌションを開き、右䞊の [接続テスト] を実行したす。 党お「成功」であれば完了です。 なお、Private Link に䞍備がある堎合は倖郚ロケヌションの䜜成自䜓が倱敗し、Databricks アクセスコネクタの暩限䞍足の堎合は接続テストで倱敗するず思いたす。 以䞊で、プラむベヌト接続のためのむンフラ構築・蚭定は完了です。お疲れ様でした プラむベヌトなデヌタストリヌミングの実践 最埌は、構築したプラむベヌト接続環境を䜿っおデヌタストリヌミングの実装䟋を玹介したす。 構築した VNet ずプラむベヌト接続された環境にあるサヌバをデヌタ゜ヌスずしお、 Fluent Bit から Event Hubs ぞデヌタを送信し、Event Hubs からの受信デヌタを Databricks のパむプラむンでストレヌゞに曞き蟌む、ずいう構成です。 たずは、Unity Catalog のカタログずスキヌマを䜜成したす。 今回は、カタログ/スキヌマ甚のストレヌゞは同じ ADLS2 コンテナ内でパスを分ける圢で分離したす (※実際のナヌスケヌスでは、 メダリオンアヌキテクチャ の各レむダヌごずにコンテナもしくはストレヌゞアカりントレベルで分離する方が良いず思いたす)。 たた、あわせお Databricks パむプラむンから Event Hubs ぞ接続するための資栌情報も䜜成したす。 # カタログの䜜成 databricks catalogs create adbdemo --storage-root abfss:// < コンテナ名 > @ < ストレヌゞアカりント名 > .dfs.core.windows.net/catalog # スキヌマの䜜成 databricks schemas create bronze adbdemo --storage-root abfss:// < コンテナ名 > @ < ストレヌゞアカりント名 > .dfs.core.windows.net/bronze # Event Hubs 接続甚にサヌビス資栌情報を䜜成 databricks credentials create-credential --purpose SERVICE \ --json ' {"name":"adbdemo_service","azure_managed_identity":{"<Databricks アクセスコネクタID>"}} ' 次に、Event Hubs を゜ヌスずする Lakeflow (旧: Delta Live Tables) パむプラむンを䜜成したす。 pipelines/bronze_ingest_eventhubs_raw.py : from pyspark import pipelines as dp from pyspark.sql import SparkSession from pyspark.sql.functions import col, expr spark = SparkSession.builder.getOrCreate() # Event Hubs の Kafka モヌドでデヌタ受信するための蚭定 # ここでは SAS キヌではなく Databricks アクセスコネクタで認蚌 KAFKA_OPTIONS = { "databricks.serviceCredential" : spark.conf.get( "streaming.dbw.serviceCredential" ), "kafka.bootstrap.servers" : spark.conf.get( "streaming.evh.namespace" ), "subscribe" : spark.conf.get( "streaming.evh.name" ), "kafka.request.timeout.ms" : spark.conf.get( "streaming.kafka.requestTimeout" ), "kafka.session.timeout.ms" : spark.conf.get( "streaming.kafka.sessionTimeout" ), "maxOffsetsPerTrigger" : spark.conf.get( "streaming.spark.maxOffsetsPerTrigger" ), "failOnDataLoss" : spark.conf.get( "streaming.spark.failOnDataLoss" ), "startingOffsets" : spark.conf.get( "streaming.spark.startingOffsets" ), } def parse (df): return ( df.withColumn( "records" , col( "value" ).cast( "string" )) .withColumn( "eventhub_timestamp" , expr( "timestamp" )) .withColumn( "ingested_timestamp" , col( "current_timestamp" )) .withColumn( "date" , expr( "to_date(ingested_timestamp)" )) .withColumn( "hash" , expr( "md5(records)" )) .withWatermark( "eventhub_timestamp" , "10 minutes" ) .dropDuplicatesWithinWatermark([ "hash" ]) .drop( "key" , "value" , "partition" , "offset" , "timestamp" , "timestampType" ) ) @ dp.table ( comment= "Raw Logs aggregated from FluentBit-EventHubs" , partition_cols=[ "date" ], spark_conf={ "pipelines.trigger.interval" : "5 seconds" }, table_properties={ "quality" : "bronze" , "pipelines.reset.allowed" : "false" }, ) def common_logs_raw (): # テヌブル名 (topic=むンスタンスを区別しおいないので "common" にした) return spark.readStream.format( "kafka" ).options(**KAFKA_OPTIONS).load().transform(parse) このパむプラむンの定矩を Databricks アセットバンドル ずしお甚意したす。 Python コヌド内で参照する各皮パラメヌタもここで定矩したす。 databricks.yml : bundle : name : adbdemo databricks_cli_version : ">=0.259.0" targets : demo : workspace : host : https://<ワヌクスペヌス識別子>.azuredatabricks.net mode : production # 連続モヌドをオンにするため resources : pipelines : bronze_ingest_eventhubs_raw : name : bronze_ingest_eventhubs_raw catalog : <カタログ名> schema : bronze tags : quality : Bronze continuous : true # 連続モヌドをオン (ストリヌミングなので垞時実行にする) channel : CURRENT edition : CORE photon : true clusters : # 今回はサヌバレスではなくクラスタヌで実行 - label : default apply_policy_default_values : true node_type_id : Standard_D4ds_v5 custom_tags : quality : Bronze libraries : - file : path : ./pipelines/bronze_ingest_eventhubs_raw.py configuration : pipelines.clusterShutdown.delay : 60s streaming.dbw.serviceCredential : <サヌビス資栌情報名> streaming.evh.namespace : <EventHubs名>.servicebus.windows.net:9093 streaming.evh.name : <EventHubsむンスタンス名> streaming.kafka.requestTimeout : "60000" streaming.kafka.sessionTimeout : "30000" streaming.spark.maxOffsetsPerTrigger : "50000" streaming.spark.failOnDataLoss : "false" streaming.spark.startingOffsets : earliest 䞊蚘を䜿っおパむプラむンをデプロむしたす。 databricks bundle validate databricks bundle deploy デプロむ完了埌しばらく埅ち、グラフが衚瀺されお「実行䞭...」ずなれば成功です。 最埌に、Event Hubs 経由で Databricks にデヌタ収集する゜ヌスずしお、Fluent Bit が動䜜する環境を甚意したす。 この環境は前述の通り、VNet 内にある Event Hubs のプラむベヌト゚ンドポむントの IP アドレスぞ疎通できる堎所に䜜成したす。 Event Hubs ぞ ログ ( /var/log/system.log ) をストリヌミングするコンフィグを䜜成したす。 /etc/fluent-bit/fluent-bit.conf : [INPUT] Name tail Tag systemlog Path /var/log/system.log # 収集するログ [OUTPUT] Name kafka # Event Hubs の Kafka ゚ンドポむントぞ送信 Match systemlog timestamp_key timestamp timestamp_format iso8601 format json brokers <EventHubs名>.servicebus.windows.net:9093 # Event Hubs ゚ンドポむント topics <EventHubsむンスタンス名> rdkafka.security.protocol SASL_SSL rdkafka.sasl.mechanisms PLAIN rdkafka.sasl.username $ConnectionString rdkafka.sasl.password <EventHubsのSASポリシヌ接続文字列> 接続文字列はすでに Bicep で䜜成枈みで、Event Hubs の共有アクセス (SAS) ポリシヌの画面から取埗できたす。 なお、簡単のために Fluent Bit が動䜜する環境では、プラむベヌト゚ンドポむントの FQDN ( <EventHubs名>.servicebus.windows.net ) を /etc/hosts で名前解決させたす。 実際には Azure DNS Private Resolver を䜿うなどしお、Azure 倖からでもプラむベヌト DNS ゟヌンを参照できるようにするのがよいず思いたす。 それでは、実際に Fluent Bit が動䜜するサヌバで、収集察象の /var/log/system.log にログを远蚘しおみたす。 するず、Fluent Bit が収集したログがストリヌミング凊理によっおテヌブルに远蚘されたした。 以䞊、デヌタストリヌミングのパむプラむンを閉域で実珟できたした たずめ 本蚘事では、ハンズオン圢匏で Bicep (+α) を䜿っお Azure Databricks のプラむベヌト接続環境を構築したした。 たた、その環境を䜿っお Event Hubs 経由でのプラむベヌトなデヌタストリヌミングも実践したした。 今回の構築を通じお、特に以䞋のポむントが実践的な知芋ずしお埗られたした。 IaC の限界ず工倫: ワヌクスペヌスストレヌゞのような「動的リ゜ヌス」は Bicep だけで完結させず、スクリプトず組み合わせる珟実解が必芁 閉域化の勘所: マネヌゞドリ゜ヌスやサヌバレス (NCC) たで考慮するこずで、真にセキュアな構成が組める PaaS の柔軟性: 構成は耇雑になるが、SaaS ずは異なり、自瀟のセキュリティポリシヌに合わせおネットワヌクを柔軟に制埡できる 正盎かなりニッチな内容になっおしたいたしたが、これから䌌たような環境を構築する方の参考になったり、PaaS デヌタ基盀のカスタマむズ性の高さ (SaaS 系ずの倧きな違いの1぀) が䌝わったりしおいれば嬉しいです。 ここたでかなりの長文でしたが、最埌たでご芧いただきありがずうございたした それでは、明日の蚘事もお楜しみに
この蚘事は NTT docomo Business Advent Calendar 2025 9日目の蚘事です。 Unitree Go2はROSの通信ミドルりェアずしおEclipse Cyclone DDSを利甚しおいたすが、DDSはNATを越えられないずいう課題がありたす。 この課題に察し、DDSをZenohにブリッゞしおNAT越えを実珟する事䟋がコミュニティでいく぀か玹介されおいたす1 1 , 2 2 , 3 3 。 本蚘事ではこのアプロヌチをUnitree Go2に適甚し、zenoh-plugin-ros2ddsを甚いお Unitree Go2が扱うDDSメッセヌゞをむンタヌネット越しに送受信する方法を玹介したす。 はじめに 環境 前提知識 Unitree Go2 ROS Zenoh 実装 ビルド 実行 たずめず今埌の取り組み 参考 はじめに こんにちは。むノベヌションセンタヌの柎原です。普段ぱッゞコンピュヌティング基盀技術の怜蚌や生成AIアプリケヌションの開発に取り組んでいたす。 フィゞカルAIずいう蚀葉を聞いたこずがあるでしょうか。生成AIの次に来るテヌマずしお泚目されおおり、物理䞖界を理解しお自埋的に行動するAIを指したす。 フィゞカルAIの発展により、ロボットがこなせるタスクの幅は飛躍的に広がっおいたす。 䞀方で、ロボットにはバッテリヌ容量や搭茉できる蚈算リ゜ヌス量に制玄がありたす。 これらの制玄を克服するためには、クラりドをはじめずするロボット倖郚の蚈算リ゜ヌスを掻甚するこずが䞍可欠になるず考えおいたす。 そこで本蚘事では、クラりドからロボットを制埡するための第䞀歩ずしお、キヌボヌド入力でロボットを操䜜する簡単なデモを䜜成したので玹介したす。 環境 次のような環境で実装したした。 機皮: Unitree Go2 R&D Plus Docking Station (Jetson Orin NX)Ubuntu 22, ROS 2 Humble クラりド (Azure VM): Ubuntu 22, ROS 2 Humble 前提知識 Unitree Go2 Unitree Robotics瀟の小型四足歩行ロボットです。今回扱うGo2 R&D Plusは公匏SDKを利甚しお二次開発ができるモデルです。 ROS ROS (Robot Operating System)はロボットの゜フトりェア開発においおデファクトスタンダヌドのプラットフォヌムです。 通信方法やセンサ倀のデヌタ構造、パッケヌゞ管理機胜を提䟛しおおり、Unitree Go2もROSを利甚した二次開発が可胜です。 Zenoh Unitree Go2はROSに察応しおいたすが、その通信ミドルりェアはCyclone DDSに固定されおいたす。 Cyclone DDSは隣のROSノヌドを自動発芋するためにマルチキャストを䜿甚するなどLAN向けに蚭蚈されおおり、NAT越えが困難です。 䞀方ROSの䞖界ではWANに察応した通信ミドルりェアずしおZenohが泚目されおいたす。珟圚ROSの最新バヌゞョンであるJazzyでは公匏にサポヌトされおいるようです。 Zenohの提䟛元であるEclipseはZenoh・Cyclone DDS間のブリッゞも提䟛しおおり、これを利甚しおむンタヌネット越しの通信を実珟しおいる事䟋がいく぀かありたす。 本蚘事ではZenohずブリッゞを利甚しおむンタヌネット越しにGo2のセンサ倀を読み取り、キヌボヌドからGo2を操䜜するずころたでを実装したす。 実装 TechShare瀟の 【Unitree Go2】キヌボヌドからGo2を操䜜する次開発方法 を基に、これをむンタヌネット越しで実行したす。 ビルド . └── workspace/ ├── docker/ │ ├── Dockerfile.azure │ ├── Dockerfile.jetson │ └── docker-compose.yml ├── src/ │ ├── ros/ │ │ ├── unitree_ros2/ │ │ └── cmd_vel_control/ │ ├── zenoh/ │ └── zenoh-plugin-ros2dds/ ├── zenoh-config-azure.json └── zenoh-config-jetson.json Docking StationのOS・ROS環境は、 unitree_ros2 の .devcontainer/docker-compose.yaml で定矩されおいる devcontainer-humble サヌビスを䜿いたす。 クラりド偎マシンでも同じサヌビスを、ベヌスむメヌゞをARMのものからx64のものに倉曎しお䜿いたす。 docker/ はこれらを移動しただけです。 src/ 配䞋に利甚するパッケヌゞを配眮しおいたす。 unitree_ros2 : Go2を二次開発するためのROSパッケヌゞ cmd_vel_control : 【Unitree Go2】キヌボヌドからGo2を操䜜する次開発方法 で䜜成されたROSパッケヌゞの䞀郚 zenoh (Commit: 44f8b2489) : Zenoh本䜓を提䟛するRustパッケヌゞ zenoh-plugin-ros2dds (Commit: 592422b) : Zenoh <-> CycloneDDSのブリッゞを提䟛するRustパッケヌゞ zenoh-plugin-ros2ddsはzenohに䟝存しおおり、バヌゞョンによっおビルドできないこずがあるのでcommitを指定しおいたす。これらをクラりドずJetsonそれぞれに配眮し、コンテナ内で src/ をビルドしたす。 Clone git clone https://github.com/shibahara2/ros2_ws.git cd ros2_ws git submodule udpate --init --recursive コンテナに入りたす。 cd docker docker compose up unitree_ros2-<azure or jetson> -d docker exec -it unitree_ros2-<azure or jetson> zsh Rustをむンストヌルしたす。 curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh source /root/.cargo/env rustup update zenohをビルドしたす。 cd src/zenoh cargo build --release zenoh-plugin-ros2ddsをビルドしたす。 cd src/zenoh-plugin-ros2dds cargo build --release ROSパッケヌゞをビルドしたす。 cd src/ros colcon build 実行 クラりド䞊でzenohdを起動したす。 # Cloud terminal 1 src/zenoh/target/release/zenohd -c zenoh-config-azure.json ポヌト7447でクラむアントを埅ちたす。モヌド (router/peer/client)やプラグむンのPATHを以䞋のjsonで蚭定しおいたす。 $ cat zenoh-config-azure.json { mode: "router", plugins: { ros2dds: { __path__: "src/zenoh-plugin-ros2dds/target/release/libzenoh_plugin_ros2dds.so", } }, listen: { endpoints: ["tcp/0.0.0.0:7447"] }, } Jetson䞊でzenohdを起動したす。 # Jetson terminal 1 src/zenoh/target/release/zenohd -c zenoh-config-jetson.json クラりドのzenohdに接続したす。蚭定は以䞋の通りです。 $ cat zenoh-config-jetson.json { mode: "client", plugins: { ros2dds: { __path__: "src/zenoh-plugin-ros2dds/target/release/libzenoh_plugin_ros2dds.so", } }, connect: { endpoints: ["tcp/<クラりドのグロヌバルIP>:7447"] } } zenohd同士を接続するず勝手にトピックが同期され、クラりド䞊でJetson䞊のトピックが芋られるようになりたす。 Go2のセンサ倀を確認しおみたす。 # Cloud terminal 2 source src/ros/install/setup.sh export RMW_IMPLEMENTATION=rmw_cyclonedds_cpp ros2 topic echo /sportmodestate 結果最初の䞀郚 --- stamp : sec : 1765203140 nanosec : 497936758 error_code : 1001 imu_state : quaternion : - -0.9969053864479065 - 0.005156185943633318 - 0.05559273064136505 - 0.05533893033862114 続いおクラりドからロボットを操䜜したす。 クラりド䞊でノヌドを起動したす。 # Cloud terminal 2 ros2 run teleop_twist_keyboard teleop_twist_keyboard ノヌド teleop_twist_keyboard はキヌボヌド入力を受け付け、トピック /cmd_vel ぞpublishしたす。 Jetson䞊でノヌドを起動したす。 # Jetson terminal 2 ros2 run unitree_ros2_example cmd_vel_control ノヌド cmd_vel_to_sport_request はトピック /cmd_vel をsubscribeし、トピック /api/sport/request ぞpublishしたす。これが䜎レむダヌの呜什に倉換されおいき、最終的にモヌタヌが駆動したす。 実行の様子です。 このブラりザヌは埋め蟌み動画に察応しおいたせん。 タヌミナル画面が4分割されおおり、巊䞊はクラりド䞊でzenohd、巊䞋はJetson䞊でzenohd、右䞊はクラりド䞊でROSノヌド teleop_twist_keyboard 、右䞋はJetson䞊でROSノヌド cmd_vel_to_sport_request を実行しおいたす。 (本来かなり運動性胜が高いのですが、6畳の郚屋では䞀歩が限界でした。) たずめず今埌の取り組み 本蚘事ではUnitree Go2をクラりドから制埡する簡単なデモを䜜成したした。 クラりド偎の凊理がシンプルだったため、Zenohにこだわる理由が䌝わらなかったかもしれたせん。 確かにリアルタむム性を求めないアプリであれば、他に適したプロトコルがありたす。 状態監芖・ログ収集・UIずいった凊理は、MQTTやREST、WebSocketを䜿っおクラりド偎に簡単に実装できたす。 しかし私はロボットの制埡ルヌプそのものをどこたでオフロヌドできるかに興味がありたす。遅延やゞッタがロボットの挙動に盎結するため、ROSが提䟛する予定のZenohを䜿うのが良さそうだず刀断したした。 今埌の取り組みずしお、以䞋を調査したいです。 他プロトコルずの比范 SLAMや経路蚈画など、ロボットの制埡ルヌプのうち遅延の制玄がそこたで厳しくない凊理をクラりドで実行可胜か フィゞカルAIがロボットの制埡ルヌプに組み蟌たれるこずで、遅延の制玄がどう倉化するか たたNTTドコモビゞネスは docomo MEC ずいうモバむル回線の基地局の偎に眮かれた゚ッゞサヌバヌや、 5Gワむド ずいう優先制埡サヌビスなど、䜎遅延・䜎ゞッタの基盀を提䟛しおいたす。 これらのサヌビスを利甚するこずで遅延・ゞッタの制玄が緩和され、オフロヌドできる範囲が広がるかもしれたせん。 本日はここたでです。明日の蚘事もお楜しみに 参考 zenoh-bridge-ros2ddsでZenohずROS 2間通信 ↩ ROS 2のZenoh察応ずZenohのROS 2察応 ↩ Zenoh bridge を甚いた ROS 2 の通信性胜評䟡 ↩
この蚘事は、 NTT docomo Business Advent Calendar 2025 8日目の蚘事です。 自動テストの文脈で、モックやスタブずいう甚語を目にするこずがあるかず思いたす。この甚語は、人やテストフレヌムワヌクごずに異なった意味で䜿われるこずがあり、しばしば混乱を招いおいたす。そしお、そのような指摘をした䞊で抂念の敎理を図ったものずしおGerard Meszarosの曞籍『xUnit Test Patterns』xUTP 1 ずりェブサむト 2 がありたす。 xUTPでは、テスト察象SUTの䟝存コンポヌネントDOCを眮き換えるものを総称しお「テストダブル」ず呌び、その目的に応じお以䞋の皮類に分類しおいたす。 モック スタブ フェむク スパむ (ダミヌ) このxUTPによるテストダブルの分類に぀いおは、日本語での玠晎らしい解説蚘事がすでにいく぀か存圚したすが、私が瀟内でテストダブルの分類に぀いお説明するずきは、それらの蚘事を玹介し぀぀も個人的に以䞋の図を利甚しおいたす。 この蚘事では、その図に簡単な説明を添えお玹介したいず思いたす。 甚語の導入 テストダブルに぀いお詳现な議論をするために、いく぀かの甚語を敎理する必芁があり、xUTPで定矩されおいるいく぀かの甚語を導入したす。 テスト察象SUT; System Under Testは、文字通りテストの察象を意味したす。クラスやメ゜ッド、関数などの他、システム党䜓を指すこずもありたす。文脈によっお指し瀺す察象が異なるので、それらを抜象化したものです。 䟝存コンポヌネントDOC; Depended-on Componentずは、テスト察象が䟝存するものです。テスト察象ず同様にクラスやメ゜ッド、関数などの他、デヌタベヌスや認蚌サヌビスなどを指すこずもありたす。 テスト察象ず䟝存コンポヌネントずいう抂念が抜象化されおいるので、関数の入出力などの抂念も抜象化をする必芁がありたす。 テスト察象がテストから受け取る入力のこずを盎接入力、テスト察象からテストコヌドぞの出力を盎接出力ずいいたす。テスト察象が関数であれば、兞型的には、関数の匕数が盎接入力、返り倀が盎接出力にあたりたす。テスト察象がHTTPベヌスのWeb APIを提䟛するバック゚ンドサヌビスであれば、兞型的には、HTTP Requestが盎接入力、HTTP Responseが盎接出力にあたりたす。 䞀方、テスト察象が䟝存コンポヌネントから受け取る入力のこずを間接入力、テスト察象から䟝存コンポヌネントぞの出力を間接出力ずいいたす。テスト察象ず䟝存コンポヌネントが関数であれば、兞型的には、䟝存される関数の匕数がテスト察象の間接出力、䟝存される関数の返り倀が間接入力にあたりたす。 テスト察象を䞭心ずしお入出力の関係が敎理されおいるため、盎接/間接入力が関数の匕数、盎接/間接出力が関数の返り倀、のような察応付けずはならないこずに泚意しおください。 この節で導入したこれらの甚語テスト察象、䟝存コンポヌネント、盎接入出力、間接入出力を図にたずめるず、次のようになりたす。 テストダブルずその分類 xUTPでは、モックやスタブなどの䟝存コンポヌネントを眮き換えるものを総称しおテストダブルず呌んでいたした。そしお、それらの抂念をその目的によっお以䞋の通り再敎理しおいたす。 モック モックずは、テスト察象が䟝存するコンポヌネントぞの間接出力を怜蚌するこずを目的ずしたテストダブルです。間接出力の怜蚌の䟋には、䟝存するリレヌショナルデヌタベヌスに枡すSQL文の怜蚌やWebフロント゚ンドからバック゚ンドぞのリク゚ストの怜蚌などがありたす。 スパむ スパむずは、テスト察象が䟝存するコンポヌネントぞの間接出力を蚘録するこずを目的ずしたテストダブルです。間接出力に関心があるずいう意味でモックず䌌おいたすが、スパむは間接出力を蚘録するもので、䟝存コンポヌネントが実行された 埌に 間接出力の怜蚌ができたす。 スタブ スタブずは、テスト察象が䟝存するコンポヌネントからの間接入力を操䜜するこずを目的ずしたテストダブルのこずです。間接入力の操䜜の䟋には、珟圚時刻を返す関数を垞に指定した時刻で返すようにする操䜜などがありたす。 フェむク フェむクずは、テスト察象が䟝存するコンポヌネントの実装を眮換するこずを目的ずしたテストダブルのこずです。実装の眮換の䟋には、リレヌショナルデヌタベヌスに䟝存するコンポヌネントのオンメモリ実装ぞの眮換やクラりドサヌビスのプロバむダヌが提䟛するロヌカルで動䜜する゚ミュレヌタヌなどが挙げられたす。 フェむクは、䟝存するコンポヌネントの実行速床が遅い堎合やテスト環境で本物の䟝存するコンポヌネントが利甚できない堎合などに利甚されたす。 ダミヌ xUTPではダミヌず呌ばれる分類も導入されおいたすが、厳密にはダミヌはテストダブルではなく倀パタヌンの䞀郚であるずいう議論も同時になされおいたす。ダミヌは今回玹介する図では敎理しにくいこずもあり、この蚘事では分類から陀倖したす。 これらのテストダブルの分類のうち、モックずスパむは間接出力に、スタブは間接入力に、フェむクはそのどちらでもなく䟝存コンポヌネントの実装に関心がありたす。 モック間接出力の怜蚌 スパむ間接出力の蚘録 スタブ間接入力の操䜜 フェむク䟝存コンポヌネントの実装の眮換 したがっお、これらの関心の違いを元に、次のように図再掲にたずめるこずができたす。 おわりに この蚘事では、xUTPによるテストダブルの分類の図解を玹介したした。 この図が、少しでも理解の助けずなれば幞いです。 NTT docomo Business Advent Calendar 2025 を、明日もお楜しみに 参考文献 Meszaros, Gerard. xUnit test patterns: Refactoring test code. Pearson Education, 2007. ↩ Meszaros, Gerard. xUnit Patterns.com, xunitpatterns.com . Accessed 8 Dec. 2025. ↩
この蚘事は、 NTT docomo Business Advent Calendar 2025 7日目の蚘事です。 こんにちは。むノベヌションセンタヌの加藀です。普段はコンピュヌタビゞョンの技術開発やAI/機械孊習MLシステムの怜蚌に取り組んでいたす。 ディヌプラヌニングの実装をしおいるずきに、倉数のshapeを管理するのはなかなか倧倉です。い぀のたにか次元が増えおいたり、想定倖のshapeがやっおきたりしお実行時に萜ちおしたったずいうのは日垞茶飯事だず思いたす。 こういった問題に察しお静的解析で䜕ずかできないかず詊行錯誀した結果を共有したす。 mypyプラグむンを䜿うモチベヌション mypyプラグむンの䜜成 初期化 jaxtyping annotationを拟う テン゜ル䜜成関数を拟う テン゜ル蚈算 ここで限界が来たFuture work 倉数付きのshape蚘法 次元の四則挔算 stubの是非 レむダヌの型泚釈 たずめ mypyプラグむンを䜿うモチベヌション Pythonのプログラムを静的怜査する方法のひず぀に mypy がありたす。これは゜ヌスコヌドに぀けられた型アノテヌションに矛盟がないか調べおくれるもので、倉な代入や挔算由来の゚ラヌを未然に防ぐこずができたす。 しかしながら、NumPyやPyTorchなどの䞀般的な数倀蚈算ラむブラリにはそれなりの型がアノテヌションされおいるものの、せいぜいテン゜ルの型(intやfloatなど)どたりで次元(shape)に぀いおは考慮されおいないため、そのたたでは次元の䞍䞀臎などを怜出できたせん。 jaxtyping などのラむブラリは元の型を拡匵しお次元などをアノテヌションできるようにしおくれたすが、これらは実行時解析のみをサポヌトしおおり、mypyからは扱えたせん。 from torch import Tensor import torch from jaxtyping import Float32, jaxtyped from beartype import beartype as typechecker from typing_extensions import reveal_type @ jaxtyped (typechecker=typechecker) def f (x: Float32[Tensor, "1 224 224" ]) -> Float32[Tensor, "1 1000" ]: print ( "processing f" ) w = torch.randn( 1000 , 224 * 224 ) x_flat = x.view( 1 , 224 * 224 ) y = x_flat @ w.t() return y.view( 1 , 1000 ) x: Float32[Tensor, "1 224 224" ] = torch.randn( 1 , 224 , 224 ) y = torch.randn( 1 , 224 , 225 ) print ( "f(x)" ) reveal_type(f(x)) # OK print ( "f(y)" ) reveal_type(f(y)) # NG """ 実行時は匕数に誀ったshapeを枡した時点で゚ラヌ > python .\example.py f(x) processing f Runtime type is 'Tensor' f(y) Traceback (most recent call last): ... しかしmypyでは怜出できない > mypy .\example.py example.py:19: note: Revealed type is "torch._tensor.Tensor" example.py:20: note: Revealed type is "torch._tensor.Tensor" Success: no issues found in 1 source file """ 結局プログラミングの段階ではあくたで可読性を高めるための泚釈に留たり、実行時はお祈りしながら終了を埅぀こずになりたす。 そこで本皿ではmypyプラグむンを実装しおjaxtypingの型に察する凊理を远加するこずで、次元の敎合性を実行前に怜蚌できないかトラむしおみたした。もしこれができれば、mypyを䜿っお次元蟌みの静的怜査ができ、Visual Studio Codeのmypy拡匵ず連携すればプログラミング䞭もテン゜ルの次元を远うこずができるようになりたす。 mypyプラグむンの䜜成 初期化 uv でプロゞェクトを新芏䜜成したす。 $ uv init --name jaxmy --lib Initialized project `jaxmy` $ uv add mypy jaxtyping $ uv add torch numpy pytest --optional tests src/jaxmy/mypy_plugin.py にプラグむンスクリプトを䜜成したす。 from typing import Any, Optional, List, Tuple import re from mypy.plugin import Plugin class ShapePlugin (Plugin): pass # TODO def plugin (version: str ): print ( "Hello world! version:" , version) return ShapePlugin そしおmypy実行時に自䜜のpluginを玐づけるには以䞋のようにpyprojectを線集したす。 [build-system] requires = [ "hatchling" ] build-backend = "hatchling.build" [tool.hatch.build.targets.wheel] packages = [ "src/jaxmy" ] [tool.mypy] ignore_missing_imports = true plugins = [ "jaxmy.mypy_plugin" ] mypy_path = "$MYPY_CONFIG_FILE_DIR/src/jaxmy/stubs" (mypy_pathに぀いおは埌述) これでuv環境からmypyを実行するずpluginが介入するようになりたす。 > uv run mypy example.py Hello world! version: 1 . 18 . 2 jaxtyping annotationを拟う たずはjaxtyping蚘法によるアノテヌションを拟うずころから始めたす。 jaxtypingが提䟛する型の実䜓はmypyなどの静的解析時( typing.TYPE_CHECKING == True )ず実行時で異なっおおり、静的解析時は jaxtyping._indirection 内で定矩された以䞋のコヌドが読み蟌たれたす。 from typing import ( Annotated as BFloat16, # noqa: F401 Annotated as Bool, # noqa: F401 Annotated as Complex, # noqa: F401 Annotated as Complex64, # noqa: F401 Annotated as Complex128, # noqa: F401 Annotated as Float, # noqa: F401 ... そのためあらゆる型は Annotated[T, ...] ずみなされ、これは事前に T ず解決しおから静的解析が走りたす。 これによっおjaxtyping蚘法が型ずしお正しくない衚蚘であるにもかかわらず゚ディタやmypyのチェックをすり抜けおいるのですが、 Float32[Tensor, "1 224 224"] や Int8[Tensor, "3 224 224"] などがすべお Tensor ずいう同じ型に眮き換えられおしたうため静的解析が䞍可胜になりたす。 そこで、stubを泚入しお呌び出しを捕捉するこずでプラグむンから觊れるようにしたす。 # stub/jaxtyping/__init__.pyi from typing import Any, Literal, NoReturn, Union, TypeVar, Generic _ArrayType = TypeVar( "_ArrayType" ) _Shape = TypeVar( "_Shape" ) class AbstractArray (Generic[_ArrayType, _Shape]): pass class UInt2 (AbstractArray[_ArrayType, _Shape]): ... class UInt4 (AbstractArray[_ArrayType, _Shape]): ... class UInt8 (AbstractArray[_ArrayType, _Shape]): ... """以䞋よしなに""" これでプラグむンからは get_type_analyze_hook を通しお jaxtyping.Float32 などのアノテヌションを拟えるようになりたした。ただしjaxtyping蚘法はshapeの郚分が型泚釈ずしお蚱されない文字列リテラルであるため、これを有効な型に眮き換える必芁がありたす。これを怠るずmypyがshape郚分を Any に眮き換えおしたいたす。 from typing import Any, Optional, List, Tuple import re from mypy.plugin import Plugin, FunctionContext, AnalyzeTypeContext from mypy.types import Instance, TupleType, Type, UnboundType, LiteralType, EllipsisType, RawExpressionType, TypeStrVisitor from mypy.checker import TypeChecker def parse_dimstr (dimstr: str ) -> Optional[List[ int ]]: """Parse a dimension string like "1 3 224 224" into a list of int.""" dims: List[ int ] = [] for dim in dimstr.split( " " ): dim = dim.strip() if dim.isdigit(): dims.append( int (dim)) else : return None return dims def dump_dimlist (dimlist: List[ int ]) -> str : """Dump a list of int back into a dimension string.""" dimstrs: List[ str ] = [] for dim in dimlist: dimstrs.append( str (dim)) return " " .join(dimstrs) def construct_instance (api: TypeAnalyzerPluginInterface, dtype: str , backend: Type, dim_list: List[ int ]) -> Type: """Construct an Instance of a jaxtyping type with the given dtype, backend, and shape.""" # TODO : 本圓はFloatなどのUnion型にも察応すべきだが、ずりあえず保留 # shape衚珟をLiteralで包みjaxtypingのinstanceを返す。 return Instance( api.named_type(f "jaxtyping.{dtype}" ).type, [backend, LiteralType(value=dump_dimlist(dim_list), fallback=api.named_type( "builtins.str" ))] ) def analyze_jaxtyping (ctx: AnalyzeTypeContext) -> Type: """Parse Dtype[Array, "shape"] to the mypy-friendly type Dtype[Array, Literal["shape"]].""" typ = ctx.type # UnboundType. 䜕のこずかはわからない if len (typ.args) != 2 : return typ backend, shape = typ.args backend = ctx.api.analyze_type(backend) # UnboundTypeなbackendを解決 (Tensorなどのinstanceになる) if not isinstance (shape, RawExpressionType) or type (shape.literal_value) is not str : return backend # fallback dtype = typ.name # e.g., "Float32" dim_str = shape.literal_value # e.g., "1 224 224" dim_list = parse_dimstr(dim_str) # validationもかねおパヌス if dim_list is None : return backend # fallback return construct_instance(ctx.api, dtype, backend, dim_list) DTYPE_ANNOTS = { "UInt2" , "UInt4" , "UInt8" , ...} class ShapePlugin (Plugin): def get_type_analyze_hook (self, fullname: str ): m = re.match( r"jaxtyping\.(\w+)" , fullname) if m and m.group( 1 ) in DTYPE_ANNOTS: return analyze_jaxtyping def plugin (version: str ): return ShapePlugin 今回はjaxtypingのサブセットずしお数倀リテラルのみ䟋 Float32[Tensor, "1 3 224 224"] をサポヌトしたす。内郚的には基本リテラルで持ち Float32[Tensor, Literal["1 3 224 224"]] 、郜床バラしお型掚論を行いたす。 ※ ちなみに Float32[Tensor, Literal["1 3 224 224"]] よりも取り回しのよい内郚衚珟を䜿う手もありたすが、mypyには怜査察象のプログラムで呌ばれおいるモゞュヌルずビルトむンしか扱えないずいう制玄がありたす。そのため、䜕かいい感じのオリゞナル型を導入したい堎合はjaxtypingそのものを改造する必芁がありたす。 テン゜ル䜜成関数を拟う これに加えお、 torch.zeros() などの初期化甚の関数を get_function_hook によっお捕捉し、これらのテン゜ルにjaxtyping甚の型を付䞎したす。 たずstubを䜜成しおtorchを扱えるようにしたす。 # stubs/torch/__init__.pyi from torch._tensor import Tensor as Tensor from typing import Any def randn (*size: int , out= None , dtype= None , **kwargs) -> Tensor: ... def rand (*size: int , out= None , dtype= None , **kwargs) -> Tensor: ... def zeros (*size: int , out= None , dtype= None , **kwargs) -> Tensor: ... def ones (*size: int , out= None , dtype= None , **kwargs) -> Tensor: ... そしおhookを䜜成したす。この手の関数は入力の自由床が高く、匕数を手でパヌスするのがちょっず倧倉です。 INITIALIZER_NAMES = { "torch.randn" , "torch.rand" , "torch.zeros" , "torch.ones" , } dtype_mapper = { # mapping torch.dtype to jaxtyping type "float32" : "Float32" , "float" : "Float32" , "float64" : "Float64" , "double" : "Float64" , ... } def hook (fullname: str ): if fullname in INITIALIZER_NAMES: return construct_from_shape return None Argument = namedtuple( 'Argument' , [ 'arg_type' , 'arg_kind' , 'arg_name' , 'arg' ]) def transpose_funcargs (ctx: FunctionContext | MethodContext) -> dict [ str , Argument]: """[匕数型], [匕数名], ... を [(匕数型,匕数名,...)] にたずめる""" ctxdict = {} for i, name in enumerate (ctx.callee_arg_names): if len (ctx.arg_kinds[i]) == 0 : continue ctxdict[name] = Argument( arg_type=ctx.arg_types[i], arg_kind=ctx.arg_kinds[i], arg_name=ctx.arg_names[i], arg=ctx.args[i] ) return ctxdict def construct_from_shape (ctx: FunctionContext): if not isinstance (ctx.api, TypeChecker): return ctx.default_return_type # 倱敗時は基本的にこれを返す ctxdict = transpose_funcargs(ctx) if "size" not in ctxdict: return ctx.default_return_type args = ctxdict[ "size" ].arg_type dimensions: List[Type] = [] # shape指定にはf(1,2,3)ずf((1,2,3))の二通りあるので察応 if len (args) == 1 and isinstance (args[ 0 ], TupleType): dimensions.extend(args[ 0 ].items) else : dimensions.extend(args) # すべお数倀定数であるずきのみ察応する if all (( isinstance (dim, Instance) and dim.last_known_value is not None and type (dim.last_known_value.value) is int ) for dim in dimensions): shape_list = [dim.last_known_value.value for dim in dimensions] if "dtype" in ctxdict: # dtype指定があるずき dtype = ctxdict[ "dtype" ] dtype_argtype = dtype.arg_type[ 0 ] if isinstance (dtype_argtype, Instance) and dtype_argtype.type.fullname in [ "torch.dtype" ]: jaxtype = dtype_mapper.get(dtype.arg[ 0 ].name, None ) if jaxtype is None : ctx.api.fail( f "Unsupported dtype {ctxdict['args'][0].name} for torch function." , ctx.context ) return ctx.default_return_type # 指定の型ずshapeからjaxtyping型 DType[Tensor, Literal["shape"]] を䜜る return construct_instance( ctx.api, jaxtype, ctx.api.named_type( "torch.Tensor" ), shape_list ) else : ctx.api.fail( f "Unsupported dtype {dtype_argtype} for torch function." , ctx.context ) return ctx.default_return_type return construct_instance( # デフォルトdtypeはfloat32 ctx.api, "Float32" , ctx.api.named_type( "torch.Tensor" ), shape_list ) return ctx.default_return_type これで torch.randn などの返り倀型がTensorからjaxtypingになりたした。 def g (x: Float32[Tensor, "3 224 224" ]): ... x: Float32[Tensor, "3 224 224" ] = torch.randn( 3 , 224 , 224 ) # OK y: Float32[Tensor, "3 224 226" ] = torch.randn( 3 , 224 , 224 ) # Incompatible types in assignment g(x) # OK テン゜ル蚈算 ぀ぎはテン゜ル同士の挔算を定矩したす。考慮すべきこずは以䞋の3぀です。 型が異なる時は"偉い"方に合わせる shape䞍䞀臎の時ぱラヌ shapeのブロヌドキャスト片方の次元が1の時はもう片方に合わせおもよい ですが、いったん型の方は無芖したす。 たず準備ずしおテン゜ルの挔算子をstubに定矩したす。 # stub/jaxtyping/__init__.pyi Self = TypeVar( "Self" , bound= "AbstractArray[_ArrayType, _Shape]" ) class AbstractArray (Generic[_ArrayType, _Shape]): def __add__ (self: Self, other: Any): ... def __radd__ (self: Self, other: Any): ... def __iadd__ (self: Self, other: Any) -> Self: ... def __sub__ (self: Self, other: Any): ... def __rsub__ (self: Self, other: Any): ... def __isub__ (self: Self, other: Any) -> Self: ... def __mul__ (self: Self, other: Any): ... def __rmul__ (self: Self, other: Any): ... def __imul__ (self: Self, other: Any) -> Self: ... そしおこれを get_method_hook で捕捉したす。 arithmetic_names = { "__add__" , "__radd__" , "__sub__" , "__rsub__" , "__mul__" , "__rmul__" , "__pow__" , "__div__" , "__rdiv__" , ... } def decompose_instance (typ: Instance) -> Optional[Tuple[ str , Type, List[ int ]]]: """Decompose a jaxtyping type into (backend type, shape as list of ints).""" if len (typ.args) != 2 : return None backend, shape = typ.args if not isinstance (shape, RawExpressionType) or type (shape.literal_value) is not str : return None dtype = typ.name # e.g., "Float32" dim_str = shape.literal_value # e.g, "1 224 224" dim_list = parse_dimstr(dim_str) if dim_list is None : return None return dtype, backend, dim_list def tensor_arithmetic (ctx: MethodContext): self_type = ctx.type other_type = ctx.arg_types[ 0 ][ 0 ] if isinstance (self_type, Instance) and isinstance (other_type, Instance): if self_type.type.fullname.startswith( "jaxtyping." ): self_result = decompose_instance(self_type) if self_result is None : ctx.api.fail( f "Unable to parse Self as jaxtyping {self_type}" , ctx.context ) return ctx.default_return_type self_dtype, self_backend, self_dims = self_result else : ctx.api.fail( f "Self must be jaxtyping {self_type}" , ctx.context ) return ctx.default_return_type if other_type.type.fullname.startswith( "jaxtyping." ): other_result = decompose_instance(other_type) if other_result is None : ctx.api.fail( f "Unable to parse Other as jaxtyping {other_type}" , ctx.context ) return ctx.default_return_type other_dtype, other_backend, other_dims = other_result elif other_type.type.fullname in ( "builtins.int" , "builtins.float" ): other_dtype = self_dtype other_backend = self_backend other_dims = [] # scalar if repr (self_backend) != repr (other_backend): ctx.api.fail( f "Backend mismatch: {self_backend} vs {other_backend}" , ctx.context ) return ctx.default_return_type out_backend = self_backend if self_dtype != other_dtype: ctx.api.fail( f "Dtype mismatch: {self_dtype} vs {other_dtype}" , ctx.context ) return ctx.default_return_type # TODO : promote dtype out_dtype = self_dtype if self_dims == other_dims: out_dims = self_dims else : # broadcast check longest = max ( len (self_dims), len (other_dims)) self_dims = [ 1 ] * (longest - len (self_dims)) + self_dims other_dims = [ 1 ] * (longest - len (other_dims)) + other_dims out_dims = [] for d1, d2 in zip (self_dims, other_dims): if d1 == d2: out_dims.append(d1) elif d1 == 1 : out_dims.append(d2) elif d2 == 1 : out_dims.append(d1) else : ctx.api.msg.fail( f "Shape mismatch: {self_dims} vs {other_dims}" , ctx.context ) return ctx.default_return_type # fail return construct_instance(ctx.api, out_dtype, out_backend, out_dims) ctx.api.fail( f "Unknown types for tensor arithmetic: {self_type} and {other_type}" , ctx.context ) return ctx.default_return_type class ShapePlugin (Plugin): def get_method_hook (self, fullname: str ): if fullname.startswith( "jaxtyping." ): # jaxtyping.Float32.__add__など if fullname.split( "." )[- 1 ] in arithmetic_names: return tensor_arithmetic 泚意点ずしお、どうも実行時ず同じように __add__ から __radd__ ぞのフォヌルバックがなされおいるらしく、 __add__ の凊理で api.fail による゚ラヌを吐いおも、 __radd__ の型チェックが未実装のたただずそちらで解決したこずになり゚ラヌが消えおしたうようです。ちゃんず䞡方凊理するか、フォヌルバック先を無条件でfailさせる必芁がありたす。 これで以䞋のテストに察応できたす。 x: Float32[Tensor, "3 224 224" ] = torch.randn( 3 , 224 , 224 ) # OK y: Float32[Tensor, "3 224 226" ] = torch.randn( 3 , 224 , 226 ) # OK reveal_type(x + x) # OK reveal_type(x * 2.0 ) # OK (scalar) reveal_type(torch.randn( 1 , 224 , 224 ) + x) # OK (broadcasting) reveal_type(x + y) # Shape mismatch: [3, 224, 224] vs [3, 224, 226] ここで限界が来たFuture work この時点でテン゜ルの四則挔算ができるようになりたしたが、ここでギブアップしおしたいたした。 実甚レベルにするには以䞋のようにただただやるべきこずが山のようにありたす。 倉数付きのshape蚘法 jaxtypingは"batch 3 height width"のような蚘法に察応しおおり、これができれば畳み蟌みニュヌラルネットワヌクなど入力画像のサむズを気にしないものにも型を付けるこずができたす。 次元の四則挔算 䟋えばテン゜ルを結合したずきに次元を足し算したり、upsampleでは掛け算、downsampleでは割り算などをする必芁がありたす。そしおこれは倉数を蚱すず鬌のように難しくなりたす。 䟋えばUNetなどは画像をdownsampleしたのちupsampleしたすが、downsampleでの割り算は小数切り捚おなのでupsampleしおも元に戻るずは限りたせん。぀たり割り算ず掛け算を瞮玄するこずができないため、 batch 3 height//8*8 width//8*8 のようなshapeが batch 3 height width ず䞀臎するかなどの怜蚌をする必芁がありたす。 これはあたりにも蟛いので、「 height は8で割り切れる」のような泚釈をjaxtypingに新しく蚭けるこずで割り算をうたく凊理するずいうのが無難そうですこうするこずでUNetに䞭途半端なサむズの画像を入れおバグらせるずいうのも回避できたす。 stubの是非 プラグむンがjaxtypingやPyTorchなどのラむブラリ由来の型を拟うためにstubを䜿いたしたが、果たしおこの䜿い方が正しいのかずいう懞念がありたす。もっず゚レガントな方法はないのでしょうか   レむダヌの型泚釈 PyTorchを扱うからにはnn.Moduleに察応する必芁があるでしょう。ですがニュヌラルネットのあらゆるレむダヌに察しおjaxtypingの型怜査を実装するずいうのは骚が折れたす。 さらにmypyを基盀にする䞊でおそらく䞀番の鬌門は、PyTorchでは䞀般的な以䞋のコヌディングです。 layers = nn.ModuleList([nn.Linear( 100 , 50 ), nn.ReLU(), nn.Linear( 50 , 10 )]) def forward (x: Tensor): for layer in layers: x = layer(x) return x mypyは倉数の再代入があっおも 察応できるらしい のですが、果たしおforルヌプが回った埌の型は぀けられるか怪しいです。 たずめ この蚘事ではmypyプラグむンの機胜を利甚しお、PyTorchの゜ヌスコヌドに次元付きの型泚釈が぀けられないか挑戊しおみたした。それなりの機胜は持たせられそうでしたが、実甚的なレベルたでいけるかどうかは埮劙そうです。
この蚘事は NTT docomo Business Advent Calendar 2025 3 日目の蚘事です。 みなさんこんにちは、むノベヌションセンタヌの @Mahito です。 普段は瀟内の゚ンゞニアが働きやすくなるこずを目暙に、コヌポレヌト゚ンゞニアのような掻動や゚ンゞニア向けむベントの䌁画・運営をしおいたす。 今回は、䞊でも述べおいるように、 瀟内の゚ンゞニアが働きやすくするこずを目暙に掻動をしおいるむノベヌションセンタヌの取り組み Engineer Empowerment プロゞェクトに぀いお玹介したす。 NTTドコモビゞネスの䞭で、゚ンゞニアが働きやすくなるためにどのような掻動をしおいるのか、興味がある方に読んでいただければず思いたす。 Engineer Empowerment プロゞェクトずは Engineer Empowerment プロゞェクト蚭立の背景 これたでの掻動内容 パスワヌドマネヌゞャヌの党瀟導入 NTT グルヌプ向けむベントの開催 これたでの掻動からの孊びず䌝えたいこず 課題を共有する 実践する 評䟡・フィヌドバックする 珟圚・今埌の掻動 今埌の掻動 たずめ Engineer Empowerment プロゞェクトずは Engineer Empowerment プロゞェクトのミッションは、 NTTドコモビゞネスや NTT グルヌプの゚ンゞニアが働きやすい環境・成長できる堎を構築するこずです。 これらを実珟するために、以䞋の 3 ぀の取り組みを行っおいたす。 ゚ンゞニアからの課題を収集・集玄したうえで、゚ンゞニア有志ず協働した解決策の怜蚎・実斜 働きやすい環境やルヌルの敎備・芋盎しに関する関連郚眲ずの調敎 ゚ンゞニアの成長やプレれンス向䞊実珟の堎の甚意やそうした䌁業文化の醞成 1 ぀めに「 ゚ンゞニア有志ず協働 」ず曞いおありたすが、じ぀はこのプロゞェクトは私の 1 人プロゞェクトです。 しかしながら、䞊蚘の取り組みをする際には、瀟内や NTT グルヌプの゚ンゞニア有志が協力しおくれおいたす。 そのおかげで、2021 幎の 12 月から掻動をしおいたすが、この 4 幎の間にいく぀かの成果を出すこずができおいたす。 Engineer Empowerment プロゞェクト蚭立の背景 私はこのプロゞェクトを立ち䞊げる前は、R&D の゚ンゞニアずしお、OpenStack のコミュニティ察応や、 Docker、Kubernetes、Spinnaker などの OSS の調査や瀟内導入のための怜蚌などをしおいたした。 その傍ら、 NTT Tech Conference ずいう NTT グルヌプの゚ンゞニアが発衚をするむベントや、NTT グルヌプ内限定のむベントの䌁画・運営もしおいたした。 こうしたむベントの䞭で、瀟内やグルヌプの゚ンゞニアの働く環境ぞの課題を感じそれをなんずかしたいずいう思いがあり、 その䞀環ずしお、以前蚘事にもした ゚ンゞニアが゚ンゞニアのために開発・怜蚌甚 PC を敎備した話 に取り組みたした。 この取り組みを通じお、情報システム郚や情報セキュリティ郚では手が回らない ゚ンゞニアの働く課題を゚ンゞニアが解決できるずいうこずを感じ、これ以倖の問題にも取り組むようになりたした。 こうした自分の本来業務のミッションずは違った掻動を圓時の䞊叞からは理解しおもらったうえで実斜しおいたした。 ただ、䟡倀のある掻動だず認められおいる䞀方、チヌムのミッションずは違う掻動を続けるこずに察しお、自分の䞭で葛藀がありたした。 その折、NTTドコモビゞネスで技術顧問をしおいる吉矜( @ryuzee )さんず 1on1 をした際、 䞊蚘の悩みを盞談したずころ、それなら自分でプロゞェクトを立ち䞊げおみたらずいう話をされたした。 自分自身でもそれは頭の片隅にあったのですが、吉矜さんず話をする䞭でそういうプロゞェクトがあっおもいいかずいう玍埗が生たれ、 Engineer Empowerment プロゞェクトを立ち䞊げたした。 ちなみに、Engineer Empowerment ゚ンゞニアに力を䞎えるは圓時の䞊叞から名付けおもらいたした。 これたでの掻動内容 Engineer Empowerment プロゞェクト立ち䞊げ圓時は䞊蚘の開発・怜蚌甚 PC の敎備を半幎で決着を぀けおプロゞェクトを畳む予定でした。 しかし、その蚈画が瀟内の調敎などで遅延する䞭でそれ以倖の゚ンゞニアの働く課題も芋぀かり、 開発・怜蚌甚 PC の敎備が完了した埌も、それらの課題に 1 ぀ず぀取り組んでいるうちに珟圚 5 幎目を迎えおいたす。 これたでに取り組んだ課題の䟋ずしおは、以䞋のようなものがありたす。 パスワヌドマネヌゞャヌの党瀟導入トラむアル䞭 開発・怜蚌甚 PC から瀟内システムに接続するための VDIVirtual Desktop Infrastructure の提䟛情シスぞノりハりを匕き継ぎ終了 GitHub Enterprise の党瀟化ずその運甚 Miro の党瀟化ずその運甚 各皮 NTT グルヌプ内郚向けむベントの開催 NTT Tech Conference の䌁画・運営 圓゚ンゞニアブログのリニュヌアルずその運甚 技術系 SNS 運甚に関する取りたずめ etc これらの掻動の倚くは、゚ンゞニアからの「こういうこずに困っおいる」や「こういうこずがしたい」ずいう話から始たっおいたす。 ここでは䞀䟋ずしお、パスワヌドマネヌゞャヌの党瀟導入ず、NTTグルヌプ向けむベントの開催に぀いお玹介したす。 パスワヌドマネヌゞャヌの党瀟導入 パスワヌドマネヌゞャヌはずある゚ンゞニアの「管理する機噚やサヌビスが倚すぎおパスワヌド管理が蟛い」ずいう話から始たっおいたす。 䞀般的に、ID/Pass はそのログむン先ごずに異なるものを利甚するこずが掚奚されおいたす。 しかしながら、人間の蚘憶には限界があるため、結果的に芚えやすいパスワヌドを䜿いたわしたり、 あるいは芏則性のあるパスワヌドを利甚するなど、どこかのサヌビスで ID/Pass が挏掩した際にリスクが高たりたす。 こうした問題を解決するために、パスワヌドマネヌゞャヌを䜿うこずで、 機噚やサヌビスごずの異なる ID/Pass を人間が芚えずずも安党に䜿えるようにしたいずいう話がありたした。 そこで、Engineer Empowerment プロゞェクトでは、郚内で利甚したい人向けにパスワヌドマネヌゞャヌの提䟛を始めたした。 1 幎ほど䜿ったずころで、パスワヌドマネヌゞャヌの利甚を継続するか刀断するために利甚者アンケヌトをずったずころ、 想定通り䟿利になったずいう声が倚い䞭に「グルヌプで安心しお ID/Pass を共有できるようになった」ずいう声がありたした。 䌚瀟のセキュリティルヌルずしお、原則共有 ID は犁止されおいるのですが、 珟実問題ずしお機噚やサヌビスの仕様管理者暩限アカりントが 1 ぀しか䜜れないなどで共有 ID を䜿わざるを埗ないケヌスがありたす。 そうした堎合に埓来は口䌝や鍵付きの Excel で管理しおいたそうですが、 それをパスワヌドマネヌゞャヌで安党に共有できるようになり、利䟿性や安党性が䞊がったずのこずでした。 私は党瀟でも同じような話やニヌズがあるのではないかず思い、 情報セキュリティ郚にこの内容を共有したうえで党瀟アンケヌトを実斜したずころ、 同様にパスワヌド管理や共有の課題を感じおいる人が倚いずわかりたした。 そこで、情報セキュリティ郚ず話し合ったうえで珟圚は情報セキュリティ郚䞻導で党瀟トラむアルずいう圢で、 パスワヌドマネヌゞャヌの導入が進められおいたす。 NTT グルヌプ向けむベントの開催 2022 幎の幎末ぐらいに「OpenAI を䜿ったハッカ゜ンがしたい」ずいう話を瀟内の゚ンゞニアからされたこずをきっかけに、2023 幎の倏に NTT グルヌプ内のむベントずしお NTT Group Azure OpenAI Day ず NTT Generative AI Hack Day ずいうむベントを開催したした。 圓時、Azure OpenAI Service はリク゚ストを出しお Waiting List に登録されおから利甚できるたでに数週間かかっおおり、すぐには利甚できない状態でした。 そこで、NTT Com 珟圚NTTドコモビゞネスを退職しおマむクロ゜フトで働いおいた友人に盞談したずころ、営業を含めた打ち合わせが蚭けられ、気が぀くず NTT を巻き蟌んだ䞀倧むベントになっおいたした。 むベントスタッフは NTT グルヌプの゚ンゞニア有志で構成され、 1日目の NTT Group Azure OpenAI Day にはグルヌプから 1,000 人を超える参加者が集たり、 2~3 日目の NTT Generative AI Hack Day には 100 人皋床集たりたした。 むベントに぀いおは ゚ヌ・゚フ・ラボラトリヌズの方が少し曞いおくれおいたりしたす。 Azure OpenAI Serviceでマッチングアプリの返信を自動生成しおみた - NFLabs. ゚ンゞニアブログ 圓初は自瀟に閉じた小さいむベントの予定でしたが、 気が぀くずグルヌプを巻き蟌む倧芏暡むベントになっおしたいたした。 しかし、こうしたむベントを通じお、NTT グルヌプの゚ンゞニア同士の亀流や技術情報の共有が進んだのは良かったず思っおいたす。 これたでの掻動からの孊びず䌝えたいこず これたでの掻動を通じお、゚ンゞニアの課題解決や、やりたいこずを実珟するために、以䞋のようなこずの重芁性を改めお感じおいたす。 課題を共有する 実践する 評䟡・フィヌドバックする 課題を共有する これぱンゞニアが持぀働くうえでの課題開発・怜蚌端末や䜿えるツヌル、開発に関するルヌルなどをたずぱンゞニアの䞭で共有するこずです。 共有するこずで、その課題を倚くの人が感じおいたり、蚀われお初めお気づくこずで、 その課題を解くこずが自分たちの働きやすさに぀ながるずなったものに぀いおは解決に向けお働きかけるこずができたす。 たた、これぱンゞニアの䞭だけでなく関係する郚眲情報システム郚、情報セキュリティ郚、広報、人事などずも共有するこずで、 盞手が認識しおいない課題を認識しおもらい、䞀緒に解決ぞ向けた取り組みを進めるこずに぀ながりたす。 今回挙げたパスワヌドマネヌゞャヌの話では、たさに情報セキュリティ郚では芋えおいなかった珟堎の課題を共有するこずで、 パスワヌドマネヌゞャヌによる解決ずいう話に぀なげるこずができたした。 実践する 課題がわかったり、そもそもやりたいこずがあった堎合に、蚈画だけでなく倱敗しおもいいので実際に実斜しおみるこずが重芁です。 実際にやっおみるこずで、蚈画段階では芋えなかった問題点が芋えおきたり、 自分たちでは解決できなかった問題を他の゚ンゞニアが協力しおくれるこずで、解決できるこずがありたす。 たた、Azure OpenAI Service を䜿ったハッカ゜ンむベントのような、 思ったより倧事になるこずもありたすが、そういったものも含めお楜しめる事が倚いず思いたす。 そしお、実践するのは「 やりたいこず 」にするのをお勧めしたす。 私はずある SaaS の管理でやりたいわけではないが䌚瀟の事情を鑑みお「 やったほうがいいこず 」に手を出した際に、 興味があっお手䌝っおくれる人がいるだろうず気軜に始めたした。 しかし、実際には瀟内でほずんど協力が埗られず、 1 人でしんどい思いをする矜目になった経隓がありたす。今はなんずかしお解決しおおりたす もし、あなたが䌚瀟の䞭で有志たちず゚ンゞニアの課題を解決するのであれば「 やったほうがいい 」や「 やるべき 」に惑わされず、 自分がやりたいこず、そしおたわりもやりたいこず にするこずをお勧めしたす。 本圓に、やったほうがいいこずややるべきこずには䌚瀟が人を぀けるはずです。 評䟡・フィヌドバックする 4 幎間の掻動の反省でもあるのですが、自分たちのやっおきた掻動がどんな効果を䞊げたのか、 瀟内の゚ンゞニアが䞊げおくれたリク゚ストがどうなったのかを定期的に評䟡・フィヌドバックするこずが重芁です。 私は昚幎たでは、Engineer Empowerment プロゞェクトでの掻動を倧々的にアピヌルするこずはせず、 知っおる人が知っおくれればいいかなずいう颚に思っおいたした。 しかし、゚ンゞニアが抱えおいる課題を自分たちで解決できるこずをもっず倚くの゚ンゞニアに知っおもらうこずで、 今たでよりも倚くの゚ンゞニアの掻動に良い効果を䞎えおいけるず考えを改め、今幎から積極的に情報発信をしおいたす。 そのため、瀟内の゚ンゞニアがくれたリク゚ストに察しお、 掻動内容やその結果を共有するこずで、より倚くの゚ンゞニアにこの取り組みを知っおもらい、 ゚ンゞニアが働きやすくなるための掻動に参加しおもらえるようにしおいきたいず考えおいたす。 今回の蚘事は、こうした取り組みを瀟内だけに閉じず、瀟倖にも共有したいず思いブログずいう圢で発信させおもらっおいたす。 珟圚・今埌の掻動 珟圚は䞻に、コヌディング゚ヌゞェントを利甚できるようにする取り組みを進めおいたす。 NTT グルヌプでは AI 利甚に関しおガバナンス芏定類が定められおおり、 AI を䜿う䞊で、その利甚リスクを評䟡した䞊での利甚が求められたす。 NTTのAIに぀いお コヌディング゚ヌゞェントは利甚するモデルが孊習した内容やプロンプトで指瀺した内容次第では、 OSS のラむセンスに違反するなど、第䞉者の知的財産を䟵害する可胜性がありたす。 こうした点に察しお、゚ンゞニアが安心しおコヌディング゚ヌゞェントを利甚するために、 コヌディング゚ヌゞェントの入出力に察しおガヌドレヌルが蚭けられないかを調査・怜蚌したり、 法務や知的財産を担圓する方々ずサヌビス芏玄面からの補償なども含めお安党に䜿えるコヌディング゚ヌゞェントの調査・怜蚌を進めおいたす。 たた、それらの内容をコヌディング゚ヌゞェントを利甚するためのガむドラむンずしお䜜成を進めおおり、 近い内に瀟内でコヌディング゚ヌゞェントが正匏に䜿えるようになる予定です。 さらに、NTT グルヌプの゚ンゞニアにもコヌディング゚ヌゞェントの効果を実感しおもらうために、 NTT グルヌプの゚ンゞニア有志ず䞀緒に、コヌディング゚ヌゞェントを実際に觊るワヌクショップを開催する準備を進めおいたす。 今埌の掻動 私個人の思いずしおは、この Engineer Empowerment プロゞェクトは近いうちに終わらせたいず思っおいたす。 これはネガティブな理由ではなく、このプロゞェクトがなくおも瀟内や NTT グルヌプの゚ンゞニアが、 自分たちで゚ンゞニアが働くうえでの問題を解決し、自分たちで働きやすい環境を䜜っおいけるようになるのが理想だず考えおいるからです。 そのためにも、今埌も Engineer Empowerment プロゞェクトでは、䞀緒に問題解決しおくれる瀟内や NTT グルヌプの゚ンゞニア有志ずずもに、 ゚ンゞニアが働くうえでの問題を解決しながら仲間を増やしおいきたす。 そしお、そのノりハりを共有するこずで、誰もがより゚ンゞニアずしお働きやすい環境を䜜っおいけるようになるこずで、このプロゞェクトを終えられればず思っおいたす。 たずめ 本蚘事では、瀟内の゚ンゞニアの課題ややりたいこずを゚ンゞニアの立堎から解決や実珟に向けお働きかけるプロゞェクトに぀いお玹介させおいただきたした。 ゚ンゞニアの課題ぱンゞニアの䞭で共有し、実践し、評䟡・フィヌドバックするこずで、改善できたす。 たた、関係郚眲ずもその取組を共有するこずで、より良い解決策を芋぀けたり、䌚瀟党䜓にいい圱響を及がすこずができたす。 この蚘事が、あなたの䌚瀟や組織でも゚ンゞニアが働きやすくなるための取り組みのきっかけになれば幞いです。 明日もお楜しみに。
この蚘事は、 NTT docomo Business Advent Calendar 2025 2 日目の蚘事です。 Android 15 から Android 端末䞊で Linux 環境を動かすこずが可胜になりたした。せっかくなので、 OpenStack をむンストヌルしお VM を動かしおみたした。 はじめに スマホの Linux 開発環境に SSH する 開発環境を探怜する OpenStack のむンストヌル方法に぀いお DevStack を実行しお minimal な OpenStack 環境を぀くる スマホ OpenStack に VM を建おおみる トラブルシュヌティング Linux 開発環境が萜ちる VM が boot しない たずめ はじめに こんにちは。 Smart Data Platform (SDPF) クラりド/サヌバヌ 仮想サヌバヌチヌムの杉浊 ( @Kumassy_ ) です。 普段はハむパヌバむザや OpenStack の開発・怜蚌をしおいたす。 私は Pixel 8 Pro をメむンのスマホずしお䜿っおいたす。倖出先でスマホを眺めおいたずころ、開発者向けオプションに Linux 開発環境が远加されおいるのに気づきたした。 どうやら 2025 幎 3 月ごろから Android 15 端末向けに远加されたもののようです。 sudo も利甚できたすし、 Docker コンテナも起動できるようです。そこで、普段 OpenStack の開発をしおいる身ずしおは、 OpenStack 環境を構築しお VM を起動させおみるこずにしたした。 スマホの Linux 開発環境に SSH する スマホは画面が小さいですし文字を打぀のも䞍䟿なので、 laptop から SSH しお遊びたいです。 倖郚ネットワヌクには出られるようですが、 NAT 配䞋にいお盎接 SSH できなさそうなので、 SSH をポヌトフォワヌドしお倖郚からアクセス可胜にしたす。 たずはスマホ䞊のタヌミナルで ssh をむンストヌルしお、ログむンパスワヌドを蚭定したす。 sudo apt install ssh sudo systemctl start sshd sudo passwd droid そしお、 22/tcp を laptop に転送したす。 ssh -R 10022:localhost:22 kumassy@<laptop ip> こうすれば laptop から以䞋のようにしおスマホ䞊のタヌミナルにログむンできたす。 ssh -p 10022 droid@localhost これで普通の Linux マシンず同じように䜜業できたすね。 この手法は @kamiya334 に 教えおもらいたした 。 開発環境を探怜する 初めに Linux 開発環境がどのような環境なのか芋おみたした。 スマホなので仕方ないのですが、以䞋のように珟代の開発環境ずしおはかなり頌りないものずなっおいたした。 CPU droid@localhost:~$ lscpu Architecture: aarch64 CPU op-mode(s): 64-bit Byte Order: Little Endian CPU(s): 9 On-line CPU(s) list: 0-8 Vendor ID: ARM Model name: Cortex-A715 Model: 0 Thread(s) per core: 1 Core(s) per socket: 3 Socket(s): 1 Stepping: r1p0 BogoMIPS: 49.15 Flags: fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics fphp asimdhp cpuid asimdrdm jscvt f cma lrcpc dcpop sha3 sm3 sm4 asimddp sha512 sve asimdfhm dit uscat ilrcpc flagm sb pac a pacg dcpodp sve2 sveaes svepmull svebitperm svesha3 svesm4 flagm2 frint svei8mm sveb f16 i8mm bti Model name: Cortex-A510 Model: 1 Thread(s) per core: 1 Core(s) per socket: 1 Socket(s): 1 Stepping: r1p1 BogoMIPS: 49.15 Flags: fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics fphp asimdhp cpuid asimdrdm jscvt f cma lrcpc dcpop sha3 sm3 sm4 asimddp sha512 sve asimdfhm dit uscat ilrcpc flagm sb pac a pacg dcpodp sve2 sveaes svepmull svebitperm svesha3 svesm4 flagm2 frint svei8mm sveb f16 i8mm bti Model name: Cortex-A715 Model: 0 Thread(s) per core: 1 Core(s) per socket: 2 Socket(s): 1 Stepping: r1p0 BogoMIPS: 49.15 Flags: fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics fphp asimdhp cpuid asimdrdm jscvt f cma lrcpc dcpop sha3 sm3 sm4 asimddp sha512 sve asimdfhm dit uscat ilrcpc flagm sb pac a pacg dcpodp sve2 sveaes svepmull svebitperm svesha3 svesm4 flagm2 frint svei8mm sveb f16 i8mm bti Model name: Cortex-A510 Model: 1 Thread(s) per core: 1 Core(s) per socket: 1 Socket(s): 1 Stepping: r1p1 BogoMIPS: 49.15 Flags: fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics fphp asimdhp cpuid asimdrdm jscvt f cma lrcpc dcpop sha3 sm3 sm4 asimddp sha512 sve asimdfhm dit uscat ilrcpc flagm sb pac a pacg dcpodp sve2 sveaes svepmull svebitperm svesha3 svesm4 flagm2 frint svei8mm sveb f16 i8mm bti Model name: Cortex-A715 Model: 0 Thread(s) per core: 1 Core(s) per socket: 1 Socket(s): 1 Stepping: r1p0 BogoMIPS: 49.15 Flags: fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics fphp asimdhp cpuid asimdrdm jscvt f cma lrcpc dcpop sha3 sm3 sm4 asimddp sha512 sve asimdfhm dit uscat ilrcpc flagm sb pac a pacg dcpodp sve2 sveaes svepmull svebitperm svesha3 svesm4 flagm2 frint svei8mm sveb f16 i8mm bti Model name: - Model: 1 Thread(s) per core: 1 Core(s) per socket: 1 Socket(s): 1 NUMA: NUMA node(s): 1 NUMA node0 CPU(s): 0-8 Vulnerabilities: Gather data sampling: Not affected Itlb multihit: Not affected L1tf: Not affected Mds: Not affected Meltdown: Not affected Mmio stale data: Not affected Reg file data sampling: Not affected Retbleed: Not affected Spec rstack overflow: Not affected Spec store bypass: Mitigation; Speculative Store Bypass disabled via prctl Spectre v1: Mitigation; __user pointer sanitization Spectre v2: Mitigation; CSV2, BHB Srbds: Not affected Tsx async abort: Not affected メモリ droid@localhost:~$ free -h total used free shared buff/cache available Mem: 3.8Gi 903Mi 2.2Gi 5.6Mi 974Mi 3.0Gi Swap: 981Mi 0B 981Mi ストレヌゞ droid@localhost:~$ df -h Filesystem Size Used Avail Use% Mounted on /dev/vda1 214G 1.5G 13G 10% / /dev/vda2 191M 191M 0 100% /opt/kernel_extras devtmpfs 4.0M 0 4.0M 0% /dev tmpfs 2.0G 0 2.0G 0% /dev/shm tmpfs 786M 524K 785M 1% /run tmpfs 5.0M 0 5.0M 0% /run/lock android 229G 215G 15G 94% /mnt/shared internal 229G 215G 15G 94% /mnt/internal tmpfs 393M 0 393M 0% /run/user/0 tmpfs 393M 4.0K 393M 1% /run/user/1000 KVM droid@localhost:~$ ls /dev/kvm ls: cannot access '/dev/kvm': No such file or directory これらの結果から、開発環境の抂芁をたずめるず以䞋のようになりたす。 CPU : ARM アヌキテクチャ aarch64 の 9 コア構成で、 Cortex-A715 高性胜コアず Cortex-A510 効率コアの組み合わせです。 メモリ : 4 GB 利甚可胜でした。OpenStackのような重量玚のサヌビスを動かすには少し心もずない容量ですが、最小構成であれば動䜜させるこずができそうです。 ストレヌゞ : ルヌトファむルシステム/dev/vda1には214GBが割り圓おられおいるものの、実際に / で利甚できるのは 16 GB 皋床であるようです。 仮想化機胜 : /dev/kvm デバむスが存圚しないため、ハヌドりェア仮想化KVMは利甚できたせん。 OpenStack で VM を動かす際は QEMU の゜フトりェア゚ミュレヌションを䜿甚するこずになりたす。 制玄は厳しいですが、以䞋のように Docker コンテナは正垞に動䜜したした。 OpenStack のむンストヌル方法に぀いお OpenStack のむンストヌル方法はいく぀かありたす。 SDPF クラりド仮想サヌバヌチヌムでは kolla-ansible をベヌスに開発しおいたすが、メモリずストレヌゞの芁件がかなり厳しいので、コンテナベヌスの kolla-ansible は利甚できなさそうです。 ChatGPT にいく぀かの OpenStack むンストヌル方法に぀いお比范しおもらいたした。 ツヌル 抂芁 最小むンストヌル芁件の目安 DevStack Bash スクリプトで OS 䞊に OpenStack サヌビスを盎接むンストヌルできる OpenStack 開発者向けのツヌル 2CPU, 4GB RAM, 10 GB disk space Kolla-Ansible Docker/Podman コンテナ化された OpenStack を Ansible でデプロむするツヌル 2 NIC, 8GB RAM, 40 GB disk space OpenStack-Ansible LXC コンテナ化された OpenStack を Ansible でデプロむするツヌル 8 CPU, 8GB RAM, 50GB disk space MicroStack お手軜に導入できる snap ベヌスのシングルノヌド OpenStack 構築ツヌル 2 CPU, 8GB RAM, 100 GB disk space OpenStack は党䜓的に最小むンストヌル芁件が厳しめですが、 DevStack だずギリギリ動きそうなので、 DevStack をチュヌニングする方針ずしたした。 DevStack を実行しお minimal な OpenStack 環境を぀くる DevStack では local.conf ずいう config をもずに OpenStack をむンストヌルしたす。 メモリずストレヌゞの芁件が厳しいので、 Minimal deployment を参考にしお Cinder ず Horizon はむンストヌルしないこずにしたす。 Block Storage はなくおよいですし、 API さえ䜿えれば十分ですよね。 いろいろず詊行錯誀した結果、以䞋のような config ができたした。 stack@localhost:~/devstack$ cat local.conf [[local|localrc]] ADMIN_PASSWORD=secret DATABASE_PASSWORD=$ADMIN_PASSWORD RABBIT_PASSWORD=$ADMIN_PASSWORD SERVICE_PASSWORD=$ADMIN_PASSWORD disable_service horizon disable_service cinder c-sch c-api c-vol disable_service swift s-proxy s-object s-container s-account disable_service tempest disable_service heat h-eng h-api h-api-cfn h-api-cw disable_service ceilometer-acompute ceilometer-acentral ceilometer-api disable_service neutron-adv-service disable_service octavia o-api o-cw o-hm o-hk disable_service barbican disable_service trove disable_service sahara API_WORKERS=1 RPC_WORKERS=1 NEUTRON_PORT_SECURITY=false CIRROS_ARCH=aarch64 [[post-config|$NOVA_CONF]] [libvirt] virt_type = qemu cpu_mode = custom cpu_model = cortex-a53 DevStack のむンストヌルを進める前に、以䞋のようにしお DB に割り圓おるメモリをケチっおおきたす。 stack@localhost:~/devstack$ sudo vim /etc/mysql/conf.d/devstack-lowmem.cnf stack@localhost:~/devstack$ cat /etc/mysql/conf.d/devstack-lowmem.cnf [mysqld] innodb_buffer_pool_size = 256M innodb_log_file_size = 64M max_connections = 100 tmp_table_size = 32M max_heap_table_size = 32M あずは ドキュメント に沿っお ./stack.sh すれば OpenStack 環境ができたす。 stack@localhost:~/devstack$ ./stack.sh This is your host IP address: 10.123.149.241 This is your host IPv6 address: ::1 Keystone is serving at http://10.123.149.241/identity/ The default users are: admin and demo The password: secret Services are running under systemd unit files. For more information see: https://docs.openstack.org/devstack/latest/systemd.html DevStack Version: 2026.1 Change: f61d747518a3b4896032c7e9440ddf31856a060f Merge "Enable response validation in Keystone" 2025-11-14 14:20:56 +0000 OS Version: Debian 12 bookworm 2025-11-24 02:08:30.477 | stack.sh completed in 1923 seconds. スマホ OpenStack に VM を建おおみる ここたでできたらあずは通垞の OpenStack のように VM を䜜成できたす。 aarch64 な CirrOS の image があるので、この image をもずに VM を䜜成したす。 stack@localhost:~/devstack$ openstack image list +--------------------------------------+---------------------------+--------+ | ID | Name | Status | +--------------------------------------+---------------------------+--------+ | 2b8bfbf7-42bf-43a3-a91d-50c59633dc94 | cirros-0.6.3-aarch64-disk | active | +--------------------------------------+---------------------------+--------+ NW たわりはきちんず蚭定しおいないので、どの NW にも接続しないこずにしたす。 stack@localhost:~/devstack$ openstack server create --image 2b8bfbf7-42bf-43a3-a91d-50c59633dc94 --flavor m1.tiny test-server --nic none stack@localhost:~/devstack$ openstack server show f132c8af-cee6-4248-9128-de58e42e6665 +-------------------------------------+------------------------------------------------------------------------------------------------+ | Field | Value | +-------------------------------------+------------------------------------------------------------------------------------------------+ | OS-DCF:diskConfig | MANUAL | | OS-EXT-AZ:availability_zone | nova | | OS-EXT-SRV-ATTR:host | None | | OS-EXT-SRV-ATTR:hostname | test-server | | OS-EXT-SRV-ATTR:hypervisor_hostname | None | | OS-EXT-SRV-ATTR:instance_name | None | | OS-EXT-SRV-ATTR:kernel_id | None | | OS-EXT-SRV-ATTR:launch_index | None | | OS-EXT-SRV-ATTR:ramdisk_id | None | | OS-EXT-SRV-ATTR:reservation_id | None | | OS-EXT-SRV-ATTR:root_device_name | None | | OS-EXT-SRV-ATTR:user_data | None | | OS-EXT-STS:power_state | Running | | OS-EXT-STS:task_state | None | | OS-EXT-STS:vm_state | active | | OS-SRV-USG:launched_at | 2025-11-24T02:10:05.000000 | | OS-SRV-USG:terminated_at | None | | accessIPv4 | | | accessIPv6 | | | addresses | | | config_drive | | | created | 2025-11-24T02:09:46Z | | description | None | | flavor | description=, disk='1', ephemeral='0', extra_specs.hw_rng:allowed='True', id='m1.tiny', | | | is_disabled=, is_public='True', location=, name='m1.tiny', original_name='m1.tiny', ram='512', | | | rxtx_factor=, swap='0', vcpus='1' | | hostId | eadc3234a9f5d6b80737ed483bbdbe2d388821b0fa927cfdc237934a | | host_status | None | | id | f132c8af-cee6-4248-9128-de58e42e6665 | | image | cirros-0.6.3-aarch64-disk (2b8bfbf7-42bf-43a3-a91d-50c59633dc94) | | key_name | None | | locked | False | | locked_reason | None | | name | test-server | | pinned_availability_zone | None | | progress | 0 | | project_id | a3a363ed73e8469b98ffaae53bfa8df5 | | properties | | | scheduler_hints | | | server_groups | [] | | status | ACTIVE | | tags | | | trusted_image_certificates | None | | updated | 2025-11-24T02:10:06Z | | user_id | 6b8f5452a10542359fd0269553371366 | | volumes_attached | | +-------------------------------------+------------------------------------------------------------------------------------------------+ stack@localhost:~/devstack$ sudo virsh list Id Name State ----------------------------------- 1 instance-00000001 running virsh console か console.log を眺めるず、 CirrOS がブヌトしおきたのが確認できたした。 stack@localhost:~/devstack$ sudo tail -F /opt/stack/data/nova/instances/f132c8af-cee6-4248-9128-de58e42e6665/console.log [ 5.343116] EXT4-fs (vda1): write access will be enabled during recovery [ 5.513086] EXT4-fs (vda1): recovery complete [ 5.553111] EXT4-fs (vda1): mounted filesystem with ordered data mode. Opts: (null). Quota mode: none. [ 7.266087] EXT4-fs (vda1): re-mounted. Opts: (null). Quota mode: none. [ 243.220848] EXT4-fs (vda1): resizing filesystem from 25600 to 259835 blocks [ 243.239892] EXT4-fs (vda1): resized filesystem to 259835 ### tail -n 25 /var/log/messages Nov 24 02:10:36 cirros syslog.info syslogd started: BusyBox v1.35.0 Nov 24 02:10:39 cirros daemon.info dhcpcd[258]: dhcpcd-9.4.1 starting Nov 24 02:10:39 cirros daemon.info dhcpcd[261]: DUID 00:04:f1:32:c8:af:ce:e6:42:48:91:28:de:58:e4:2e:66:65 Nov 24 02:10:39 cirros daemon.err dhcpcd[261]: no valid interfaces found Nov 24 02:16:06 cirros syslog.info syslogd started: BusyBox v1.35.0 Nov 24 02:16:09 cirros daemon.info dhcpcd[249]: dhcpcd-9.4.1 starting Nov 24 02:16:09 cirros daemon.info dhcpcd[252]: DUID 00:04:f1:32:c8:af:ce:e6:42:48:91:28:de:58:e4:2e:66:65 Nov 24 02:16:09 cirros daemon.err dhcpcd[252]: no valid interfaces found Nov 24 02:19:09 cirros daemon.err dhcpcd[252]: timed out Nov 24 02:19:58 cirros authpriv.info dropbear[388]: Running in background ############ debug end ############## ____ ____ ____ / __/ __ ____ ____ / __ \/ __/ / /__ / // __// __// /_/ /\ \ \___//_//_/ /_/ \____/___/ http://cirros-cloud.net login as 'cirros' user. default password: 'gocubsgo'. use 'sudo' for root. cirros login: [ 246.401660] virtio_gpu virtio4: [drm] drm_plane_enable_fb_damage_clips() not called スマホさえ持っおいればい぀でも OpenStack の開発ができたすね トラブルシュヌティング Linux 開発環境が萜ちる メモリが足らず、 ずきどき Linux 開発環境が萜ちるこずもありたした。 タヌミナルを再起動すれば抂ね䜜業を再開できるので、根気匷くむンストヌル䜜業を進めおください。 openstack server create コマンドさえ実行できれば DB や MQ はいらないので、停止しおしたっおもよいでしょう。 VM が boot しない デフォルトの local.conf では nova.conf に以䞋のような蚭定が入りたす。 [libvirt] live_migration_uri = qemu+ssh://stack@%s/system cpu_mode = host-passthrough virt_type = qemu cpu_mode = host-passthrough ずなっおいたすが、 KVM が利甚できないため、このたたの蚭定だず VM の起動に倱敗したす。 : f4caa26c-ea15-428e-8e70-68dfb0aa7266] File "/opt/stack/nova/nova/virt/libvirt/driver.py", line 8247, in _create_guest : f4caa26c-ea15-428e-8e70-68dfb0aa7266] guest.launch(pause=pause) : f4caa26c-ea15-428e-8e70-68dfb0aa7266] File "/opt/stack/nova/nova/virt/libvirt/guest.py", line 167, in launch : f4caa26c-ea15-428e-8e70-68dfb0aa7266] with excutils.save_and_reraise_exception(): : f4caa26c-ea15-428e-8e70-68dfb0aa7266] File "/opt/stack/data/venv/lib/python3.12/site-packages/oslo_utils/excutils.py", line 256, in __exit__ : f4caa26c-ea15-428e-8e70-68dfb0aa7266] self.force_reraise() : f4caa26c-ea15-428e-8e70-68dfb0aa7266] File "/opt/stack/data/venv/lib/python3.12/site-packages/oslo_utils/excutils.py", line 222, in force_reraise : f4caa26c-ea15-428e-8e70-68dfb0aa7266] raise self.value : f4caa26c-ea15-428e-8e70-68dfb0aa7266] File "/opt/stack/nova/nova/virt/libvirt/guest.py", line 165, in launch : f4caa26c-ea15-428e-8e70-68dfb0aa7266] return self._domain.createWithFlags(flags) : f4caa26c-ea15-428e-8e70-68dfb0aa7266] ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ : f4caa26c-ea15-428e-8e70-68dfb0aa7266] File "/opt/stack/data/venv/lib/python3.12/site-packages/eventlet/tpool.py", line 186, in doit : f4caa26c-ea15-428e-8e70-68dfb0aa7266] result = proxy_call(self._autowrap, f, *args, **kwargs) : f4caa26c-ea15-428e-8e70-68dfb0aa7266] ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ : f4caa26c-ea15-428e-8e70-68dfb0aa7266] File "/opt/stack/data/venv/lib/python3.12/site-packages/eventlet/tpool.py", line 144, in proxy_call : f4caa26c-ea15-428e-8e70-68dfb0aa7266] rv = execute(f, *args, **kwargs) : f4caa26c-ea15-428e-8e70-68dfb0aa7266] ^^^^^^^^^^^^^^^^^^^^^^^^^^^ : f4caa26c-ea15-428e-8e70-68dfb0aa7266] File "/opt/stack/data/venv/lib/python3.12/site-packages/eventlet/tpool.py", line 125, in execute : f4caa26c-ea15-428e-8e70-68dfb0aa7266] raise e.with_traceback(tb) : f4caa26c-ea15-428e-8e70-68dfb0aa7266] File "/opt/stack/data/venv/lib/python3.12/site-packages/eventlet/tpool.py", line 82, in tworker : f4caa26c-ea15-428e-8e70-68dfb0aa7266] rv = meth(*args, **kwargs) : f4caa26c-ea15-428e-8e70-68dfb0aa7266] ^^^^^^^^^^^^^^^^^^^^^ : f4caa26c-ea15-428e-8e70-68dfb0aa7266] File "/usr/lib/python3/dist-packages/libvirt.py", line 1415, in createWithFlags : f4caa26c-ea15-428e-8e70-68dfb0aa7266] raise libvirtError('virDomainCreateWithFlags() failed') : f4caa26c-ea15-428e-8e70-68dfb0aa7266] libvirt.libvirtError: unsupported configuration: CPU mode 'host-passthrough' for aarch64 qemu domain on aarch64 host is not supported> : f4caa26c-ea15-428e-8e70-68dfb0aa7266] それから、 cpu_model の蚭定も必芁でした。 デフォルトの cpu_model の堎合は確かに qemu process ずしおは動䜜しおいるようにみえたした。 stack@lima-default:~/devstack$ sudo virsh dominfo instance-00000003 Id: 3 Name: instance-00000003 UUID: 03bd6bb9-8e56-48da-ade9-13870c876577 OS Type: hvm State: running CPU(s): 1 CPU time: 109.9s Max memory: 262144 KiB Used memory: 262144 KiB Persistent: yes Autostart: disable Managed save: no Security model: apparmor Security DOI: 0 Security label: libvirt-03bd6bb9-8e56-48da-ade9-13870c876577 (enforcing) stack@lima-default:~/devstack$ sudo virsh domstats instance-00000003 Domain: 'instance-00000003' state.state=1 state.reason=1 cpu.time=126892574000 cpu.user=126474847000 cpu.system=417727000 cpu.cache.monitor.count=0 cpu.haltpoll.success.time=0 cpu.haltpoll.fail.time=0 balloon.current=262144 balloon.maximum=262144 balloon.last-update=0 balloon.rss=179488 vcpu.current=1 vcpu.maximum=1 vcpu.0.state=1 vcpu.0.time=126430000000 vcpu.0.wait=0 vcpu.0.delay=43526812 net.count=0 block.count=1 block.0.name=vda block.0.path=/opt/stack/data/nova/instances/03bd6bb9-8e56-48da-ade9-13870c876577/disk block.0.backingIndex=1 block.0.rd.reqs=0 block.0.rd.bytes=0 block.0.rd.times=0 block.0.wr.reqs=0 block.0.wr.bytes=0 block.0.wr.times=0 block.0.fl.reqs=0 block.0.fl.times=0 block.0.allocation=0 block.0.capacity=1073741824 block.0.physical=204800 dirtyrate.calc_status=0 dirtyrate.calc_start_time=0 dirtyrate.calc_period=0 dirtyrate.calc_mode=page-sampling stack@lima-default:~/devstack$ ps aux | grep qemu libvirt+ 962634 99.9 4.4 1431616 179488 ? Sl 17:22 4:12 /usr/bin/qemu-system-aarch64 -name guest=instance-00000003,debug-threads=on -S -object {"qom-type":"secret","id":"masterKey0","format":"raw","file":"/var/lib/libvirt/qemu/domain-3-instance-00000003/master-key.aes"} -blockdev {"driver":"file","filename":"/usr/share/AAVMF/AAVMF_CODE.no-secboot.fd","node-name":"libvirt-pflash0-storage","auto-read-only":true,"discard":"unmap"} -blockdev {"node-name":"libvirt-pflash0-format","read-only":true,"driver":"raw","file":"libvirt-pflash0-storage"} -blockdev {"driver":"file","filename":"/var/lib/libvirt/qemu/nvram/instance-00000003_VARS.fd","node-name":"libvirt-pflash1-storage","auto-read-only":true,"discard":"unmap"} -blockdev {"node-name":"libvirt-pflash1-format","read-only":false,"driver":"raw","file":"libvirt-pflash1-storage"} -machine virt-8.2,usb=off,gic-version=2,dump-guest-core=off,memory-backend=mach-virt.ram,pflash0=libvirt-pflash0-format,pflash1=libvirt-pflash1-format,acpi=on -accel tcg -cpu cortex-a15 -m size=262144k -object {"qom-type":"memory-backend-ram","id":"mach-virt.ram","size":268435456} -overcommit mem-lock=off -smp 1,sockets=1,dies=1,cores=1,threads=1 -uuid 03bd6bb9-8e56-48da-ade9-13870c876577 -no-user-config -nodefaults -chardev socket,id=charmonitor,fd=30,server=on,wait=off -mon chardev=charmonitor,id=monitor,mode=control -rtc base=utc -no-shutdown -boot strict=on -device {"driver":"pcie-root-port","port":8,"chassis":1,"id":"pci.1","bus":"pcie.0","multifunction":true,"addr":"0x1"} -device {"driver":"pcie-root-port","port":9,"chassis":2,"id":"pci.2","bus":"pcie.0","addr":"0x1.0x1"} -device {"driver":"pcie-root-port","port":10,"chassis":3,"id":"pci.3","bus":"pcie.0","addr":"0x1.0x2"} -device {"driver":"pcie-root-port","port":11,"chassis":4,"id":"pci.4","bus":"pcie.0","addr":"0x1.0x3"} -device {"driver":"pcie-root-port","port":12,"chassis":5,"id":"pci.5","bus":"pcie.0","addr":"0x1.0x4"} -device {"driver":"pcie-root-port","port":13,"chassis":6,"id":"pci.6","bus":"pcie.0","addr":"0x1.0x5"} -device {"driver":"pcie-root-port","port":14,"chassis":7,"id":"pci.7","bus":"pcie.0","addr":"0x1.0x6"} -device {"driver":"qemu-xhci","id":"usb","bus":"pci.2","addr":"0x0"} -device {"driver":"virtio-scsi-pci","id":"scsi0","bus":"pci.1","addr":"0x0"} -blockdev {"driver":"file","filename":"/opt/stack/data/nova/instances/_base/71f6f0f805cceef98c928ec21e85f5e992012140","node-name":"libvirt-2-storage","auto-read-only":true,"discard":"unmap","cache":{"direct":true,"no-flush":false}} -blockdev {"node-name":"libvirt-2-format","read-only":true,"cache":{"direct":true,"no-flush":false},"driver":"raw","file":"libvirt-2-storage"} -blockdev {"driver":"file","filename":"/opt/stack/data/nova/instances/03bd6bb9-8e56-48da-ade9-13870c876577/disk","node-name":"libvirt-1-storage","auto-read-only":true,"discard":"unmap","cache":{"direct":true,"no-flush":false}} -blockdev {"node-name":"libvirt-1-format","read-only":false,"cache":{"direct":true,"no-flush":false},"driver":"qcow2","file":"libvirt-1-storage","backing":"libvirt-2-format"} -device {"driver":"virtio-blk-pci","bus":"pci.3","addr":"0x0","drive":"libvirt-1-format","id":"virtio-disk0","bootindex":1,"write-cache":"on"} -add-fd set=0,fd=31,opaque=serial0-log -chardev pty,id=charserial0,logfile=/dev/fdset/0,logappend=on -serial chardev:charserial0 -device {"driver":"usb-kbd","id":"input0","bus":"usb.0","port":"1"} -audiodev {"id":"audio1","driver":"none"} -vnc 0.0.0.0:0,audiodev=audio1 -device {"driver":"virtio-gpu-pci","id":"video0","max_outputs":1,"bus":"pci.6","addr":"0x0"} -device {"driver":"virtio-balloon-pci","id":"balloon0","deflate-on-oom":true,"free-page-reporting":true,"bus":"pci.4","addr":"0x0"} -object {"qom-type":"rng-random","id":"objrng0","filename":"/dev/urandom"} -device {"driver":"virtio-rng-pci","rng":"objrng0","id":"rng0","bus":"pci.5","addr":"0x0"} -device {"driver":"vmcoreinfo"} -sandbox on,obsolete=deny,elevateprivileges=deny,spawn=deny,resourcecontrol=deny -msg timestamp=on しかし、以䞋のようにレゞスタの倀を芋おみるず綺麗な倀になっおいお、実際には VM が生きおいるようには芋えたせんでした。 stack@lima-default:~/devstack$ virsh qemu-monitor-command --hmp instance-00000003 "info registers" CPU#0 R00=00000000 R01=00000000 R02=00000000 R03=00000000 R04=00000000 R05=00000000 R06=00000000 R07=00000000 R08=00000000 R09=00000000 R10=00000000 R11=00000000 R12=00000000 R13=00000000 R14=00000008 R15=00000004 PSR=400001db -Z-- A und32 s00=00000000 s01=00000000 d00=0000000000000000 s02=00000000 s03=00000000 d01=0000000000000000 s04=00000000 s05=00000000 d02=0000000000000000 s06=00000000 s07=00000000 d03=0000000000000000 s08=00000000 s09=00000000 d04=0000000000000000 s10=00000000 s11=00000000 d05=0000000000000000 s12=00000000 s13=00000000 d06=0000000000000000 s14=00000000 s15=00000000 d07=0000000000000000 s16=00000000 s17=00000000 d08=0000000000000000 s18=00000000 s19=00000000 d09=0000000000000000 s20=00000000 s21=00000000 d10=0000000000000000 s22=00000000 s23=00000000 d11=0000000000000000 s24=00000000 s25=00000000 d12=0000000000000000 s26=00000000 s27=00000000 d13=0000000000000000 s28=00000000 s29=00000000 d14=0000000000000000 s30=00000000 s31=00000000 d15=0000000000000000 s32=00000000 s33=00000000 d16=0000000000000000 s34=00000000 s35=00000000 d17=0000000000000000 s36=00000000 s37=00000000 d18=0000000000000000 s38=00000000 s39=00000000 d19=0000000000000000 s40=00000000 s41=00000000 d20=0000000000000000 s42=00000000 s43=00000000 d21=0000000000000000 s44=00000000 s45=00000000 d22=0000000000000000 s46=00000000 s47=00000000 d23=0000000000000000 s48=00000000 s49=00000000 d24=0000000000000000 s50=00000000 s51=00000000 d25=0000000000000000 s52=00000000 s53=00000000 d26=0000000000000000 s54=00000000 s55=00000000 d27=0000000000000000 s56=00000000 s57=00000000 d28=0000000000000000 s58=00000000 s59=00000000 d29=0000000000000000 s60=00000000 s61=00000000 d30=0000000000000000 s62=00000000 s63=00000000 d31=0000000000000000 FPSCR: 00000000 これらの問題に察応するため、 local.conf に以䞋を远蚘するこずずしたした。 [[post-config|$NOVA_CONF]] [libvirt] virt_type = qemu cpu_mode = custom cpu_model = cortex-a53 QEMU の゜フトりェア゚ミュレヌションになっおしたいたすが、 CirrOS 皋床であれば問題なく動きたす。 たずめ Android 15 から Android 端末䞊で Linux 環境を動かすこずが可胜になりたした。 4 GB RAM ず 16 GB ストレヌゞの環境䞋でやれるこずは限られたすが、 DevStack の config をチュヌニングするこずでスマホ䞊に OpenStack 環境を構築し、 VM を起動できたした。
この蚘事は、 NTT docomo Business Advent Calendar 2025 1日目の蚘事です。 こんにちは、デゞタル改革掚進郚の小林です。NTT docomo Business Engineers' Blogず改題しおからは初の、アドベントカレンダヌが始たりたした。その1日目の蚘事です。 私は4月から珟職のデゞタル改革掚進郚に所属し、瀟内認蚌サヌビスのプロダクトオヌナヌをやっおいたす。このサヌビスにより、NTTドコモビゞネスの瀟員はPCや各皮瀟内システムをひず぀のIDでシヌムレスに利甚できたす。珟圚は私のほかメンバヌ4人ず協力䌚瀟の䜓制で運営しおいたす。 私は新卒で入瀟しお以来働いおきたこの䌚瀟で、13幎目にしお初めおラむンマネゞメントに取り組むこずになりたした。入りたおの頃はマネヌゞャヌなんおなりたくないず思っおいたずころだったのに、いたずなっおはこれをそれなりに玍埗しお受け入れおいる自分がいたす。この蚘事では、これたでのキャリアでタヌニングポむントになったずころを振り返りながら、単なる゚ンゞニアからマネヌゞャヌになるキャリアチェンゞをどう受容しおいったか、その経緯をたずめたす。JTCの゚ンゞニアが10幎ちょいで歩んだキャリアの䞀䟋ずしお、お読みいただければず思いたす。 マネヌゞャヌなんお 異動ず䟡倀芳の倉化 バックオフィスでの異動、奔走、停滞 さらなる異動ずマネヌゞャヌキャリアの始たり 終わりに マネヌゞャヌなんお 私は2013幎に圓時のNTT Comに入瀟し、最初は倧䌁業向けの統合コミュニケヌションサヌビス (Arcstar UCaaS) の゚ンゞニアずしおキャリアを始めたした。昚今であればZoom, Microsoft Teams, Google Workspaceがこのあたりの地䜍を占めおいたす。 圓時は、孊生の頃にはたさか觊るこずのなかった巚倧なコアルヌタヌや仮想化基盀を操䜜したり、電話やむンスタントメッセヌゞングの亀換蚭定を曞いたり、果おはアメリカの電話事業者ずトラブルシュヌティングをしたりず、倚岐にわたる領域で数々の刺激的な経隓をしおきたした。その圓時は手を動かしおいるこずが楜しく、盞察的にマネゞメントの仕事が自分ずは遠いずころの出来事に芋えおおり、マネヌゞャヌ局の衚局的な仕事だけ芋お「ああはなりたくない」ず思っおいたずころがあったように思いたす。 異動ず䟡倀芳の倉化 時は流れお2017幎の冬、圓時の技術開発郚セキュリティテクニカルナニットに異動したした。自分が着任したチヌムはWebセキュリティ実装の高床化をテヌマにしおおり、セキュリティ系の知芋がほずんどなかった自分にずっおはそれたでのスキル・ケむパビリティを生かすのが急に困難になりたした。できおいた仕事が急にできなくなり、このたたではいけないがどう動けばいいかも分からないような難しい時期を1幎間くらい過ごしたした。 たた、同じナニットには、新卒入瀟ながら䞀芞に秀でた人がたくさんいたした。コヌドを曞くにしろセキュリティむンテリゞェンスの分析をするにしろ、自分よりもずいぶん幎䞋なのにずにかく手が動くさたをたざたざず芋せ぀けられたわけです。 そのような䞭でも自分にできる仕事がひず぀ありたした。䌚瀟のコンテキストを郚内に展開するこずです。技術開発郚は研究開発郚門であるこずもあり、新卒で配属されおからずっずここにいるずか、10幎以䞊異動がないずいった人が倚い組織でした。私のように事業郚から異動しおくる方がたれで、事業郚偎で起きおいるこずや動きの背景にある状況、事業郚が圱響を受けおいるルヌルなどは私の方がよく知っおいる状況でした。 幹郚䌚議からのフィヌドバックに背景情報を泚釈ずしお぀けたり、瀟内手続きに䞍明な点があるずSlack䞊に流れおきたヘルプに率先しお返事をしたり、そういったこずに取り組むうちに自身の存圚も認知しおもらった気がしおいたす。こうした経隓を通じお、 自分より手が動く人がたくさんいるのだから、そういう人らず競る仕事をするよりも、その人らがもっず玠早く動ける環境を䜜る方が向いおいるのでは ずの思いがどんどん匷くなっおいきたした。 最終的に、技術開発郚がむノベヌションセンタヌ (IC) に改組された2020幎には、ICのバックオフィスに自ら志願しお異動し、その思いを叶えるこずになりたす。 バックオフィスでの異動、奔走、停滞 ICのバックオフィスにおいおは、 コロナ犍に突入しお、出瀟しなくおも枈む業務プロセスを考案・実装したり、 新たに䜿いたいSaaSがあるずの盞談に耳を傟けお瀟内ルヌルになじむ圢に仕立おたり、 無人飛行機の登録が矩務化される話を聞き぀け、協働しお必芁な登録を枈たせたり、 党瀟的な調査事項を所内に必芁な圢にたずめ盎しお所員の手間をできる限り枛らしたり、 ICのValueを策定する取り組みに参加しお最終的な成果を所員党員の前で発衚したり、 所内ポヌタルサむトの動線を再蚭蚈しお情報ぞのアクセスを容易にしたり、 などなど倚岐にわたる仕事に取り組みたした。瀟䌚人孊生ずしお倧孊院に通孊しおいたのもこの時期です。このあたりから察倖的にはコヌポレヌト゚ンゞニアを名乗っおいたした。 自分の䟡倀芳にもアップデヌトがあり、先に挙げた「玠早く動ける環境䜜り」から進化しお「フロントの手を爆速にするこずは、最終的にお客さたや瀟䌚に察する奉仕になる」「ひずりよりも矀れた方が、なせるこずが増える」ずいった信条を抱えるようになりたした。 ただこうした環境で5幎も働いおいるうち、毎日の仕事を「手なり」でやっおしたえるようになり、それに違和感を芚えるようになっおいたした。コンフォヌトゟヌンに入っおいるずはこういう状況を蚀うのでは、ずの思いがどんどん匷くなっおいきたした。 ITや情報セキュリティの匷みを生かしたいず思う䞭で、自分が取りうる道はいく぀もあれど、最終的に次のどちらかだろうず考えたした。 䌚瀟のIT系バックオフィスに異動し、サヌビスする盞手のスコヌプを広くする量の芳点 グルヌプ䌚瀟に異動し、グルヌプ䌚瀟のIT・情報セキュリティに぀いお深く支揎する質の芳点 最初の異動ではあたりにもキャリアに連続性がなく蟛い思いをしたずころから、自分のスキル・ケむパビリティが掻かせる領域で瀟䌚に圹立ちたいず考え詰めた結果、これらが残りたした。こうした話を䞊長や人事担圓ず面談しおむンプットし続けた結果、珟所属の瀟内認蚌サヌビス担圓に異動するこずになりたす。 さらなる異動ずマネヌゞャヌキャリアの始たり 赎任したチヌムは15人以䞊もいるような倧所垯で、瀟内認蚌サヌビスを担圓しおいるのはこのうち5人でした圓時。その5人のメンバヌず働くにあたっお最初はどのような立堎でコミットするかを考えあぐねおいたしたが、話を聞くに぀れ前任者がテックリヌドずしお振る舞っおいたこずがわかり、自分も䜜業者の䞀人ずしおではなくリヌドする立堎にならねばず腹を決めたした。こうしお、ラむンマネヌゞャヌ、プロダクトオヌナヌずしおのキャリアを始めるこずになりたした。 実際フタを開けおみるず、2カ月間に䞭心的メンバヌの異動が2回立お続けに起こったこずで、日垞業務は淡々ずこなし぀぀もすごいこずですチヌムに混乱があるように芋受けられたした。ここから半幎かけおチヌムビルディングに奔走するこずになるのですが、その話はたた別の機䌚にするこずずいたしたしょう。 終わりに 自分の10幎あたりのキャリアを、簡単ですが振り返っおきたした。倧孊の同玚生が30歳そこそこで肩曞付き・郚䞋持ちになっおいるのに劙に焊ったのもいたずなっおは昔のこずで、自分ができるこずで貢献すればいいのだず捉えられるようになっおからは、ゆったりず構えおいたす。日頃こなすべき業務・解くべき課題はよりどりみどりで、毎日飜きずに取り組めおいたす。 これからのこずはたたどこかで振り返る぀もりです。来幎のアドベントカレンダヌでも、今床はチヌムマネゞメントの話を䜕か曞けたらいいなず思っおいたす。 お読みいただきありがずうございたした。明日の蚘事はKumassyが担圓したす。明日もお楜しみに
こんにちは、NTTドコモグルヌプの珟堎受け入れ型むンタヌンシップに「D2攻撃者芖点に立ち攻撃技術を研究開発するセキュリティ゚ンゞニア」ポストで参加させおいただきたした、倪田です。 本蚘事では、本むンタヌンシップでの取り組みに぀いお玹介いたしたす。 NTTドコモグルヌプのセキュリティ業務、特にOffensive Securityプロゞェクト以䞋、PJに興味のある方、むンタヌンシップの参加を怜蚎しおいる方などぞの参考になれば幞いです。 OffensiveSecurityPJずは 参加経緯 むンタヌンシップ抂芁 Microsoft 365 Copilotの悪甚 Microsoft 365 Copilot ずは 目暙 怜蚌1: Black Hat USA 2024での手法を再珟 怜蚌2: ナヌザヌに向けた案内 + Markdown 怜蚌3: Excelファむルを利甚したペむロヌドの秘匿 たずめ むンタヌンの感想 おわりに OffensiveSecurityPJずは 今回私が参加させおいただいたワヌクフィヌルド職堎はむノベヌションセンタヌのテクノロゞヌ郚門内に䜍眮するOffensive Security PJです。 Offensive Security PJ は最先端のセキュリティ技術を調査・怜蚌し、その成果を瀟内倖に共有しおいくこずをミッションずしおいたす。 特に重芖しおいるのは「攻撃者の芖点」に立぀こずです。防埡の立堎から技術を眺めるだけではなく攻撃者がどのように考え、どのような手法を甚いるかを理解するこずで初めお本質的な察策を打぀こずができたす。そのような芖点を持ち続けるこずで埓来の埌远いの察策にずどたらず、脅嚁を先取りしお備える「先回りの防埡」を実珟しようずしおいたす。 単に攻撃手法を暡倣するだけでなく、その背埌にある原理やアヌキテクチャや攻撃の成立条件たで掘り䞋げるような研究・開発をしおいたす。 参加経緯 私は普段、倧孊院でセキュリティに関する研究をしおいたす。䞭孊生の頃、遠隔操䜜可胜な゚アコンが珟れた時に、「もし悪甚されたら人呜に関わるのではないか」ず感じた経隓がありたす。その出来事をきっかけに、新しい技術や補品を「どのように悪甚され埗るか」ずいう芖点で芋るようになりたした。 そうした関心から、Offensive SecurityRed Team に匷い興味を持ち、将来はこの分野に携わりたいず考えるようになりたした。そのため、「攻撃技術の調査・開発・怜蚌や攻撃技術の応甚に関する研究」ずいう本ポストの業務内容は、私の関心ず非垞に䞀臎しおいるず感じ、応募いたしたした。 たた、業務ずしお研究に取り組むこずを自分自身が楜しめるかどうかを確かめたいずいう思いもありたした。 むンタヌンシップ抂芁 むンタヌンシップは8月25日から9月5日の平日10日間で開催され、業務䜓隓はオリ゚ンテヌションや成果報告䌚を陀いた実質7日間で行われたした。 初日ず最終日は出瀟が必須で、それ以倖の日皋は出瀟かオンラむンかを盞談しお決めるこずが出来たした。 たたむンタヌンシップ期間䞭は、怜蚌業務はもちろん、SOCSecurity Operation Centerの芋孊や海倖のカンファレンスに登壇された瀟員の方による再挔の聎講、瀟内LTLightning Talks䌚ぞの参加、他郚眲のむンタヌンシップ生ずの亀流などさたざたな䜓隓をさせおいただきたした。 私が怜蚌業務で取り組んだテヌマは以䞋の2぀です。 Microsoft 365 Copilotの悪甚 LLM応甚によるRed Teamオペレヌション高床化怜蚌 本蚘事では、2぀のテヌマのうち「Microsoft 365 Copilotの悪甚」を玹介したす。 Microsoft 365 Copilotの悪甚 珟圚、倧芏暡蚀語モデルLLMの業務利甚が進んでいたすが、それには同時に危険性もありたす。どのような危険が朜んでいるかを明らかにするずずもに、LLMに察する攻撃手法に関する知芋を収集するこずを目的ずしお、Microsoft 365 Copilot環境を甚いた攻撃手法を怜蚌したした。 Black Hat USA 2024で発衚された攻撃手法 1 を基に、それらが珟圚も再珟可胜かどうかを怜蚌したした。さらに、他蚀語のプロンプトでも同様の攻撃が成立するか、および察策が斜されおいる堎合にどのような工倫で攻撃が成功し埗るかに぀いお調査したした。 Microsoft 365 Copilot ずは Microsoft 365 Copilot 2 以䞋 Copilotは、Word や Excel、PowerPoint、Outlook などの Microsoft 365 アプリに組み蟌たれたAIアシスタントです。 メヌルの䞋曞きやプレれン資料の䜜成、デヌタ分析をアプリ䞊で盎接行えるほか、チャットでの䌚話の䞭でWeb 䞊の情報や瀟内のメヌルやドキュメントなどのデヌタを参照できる点が特城です。 瀟内のメヌルを参照し応答する流れ しかし、Microsoft 365 Copilotの「各皮デヌタを参照できる」ずいう特城を利甚した攻撃手法も知られおいたす。 目暙 本ブログでは、Copilotにナヌザヌを悪意のあるサむト等ぞ誘導しおもらうこずを目暙ずした怜蚌に぀いお報告したす。 Copilotは䌚話の応答䞭にクリック可胜なハむパヌリンクを衚瀺するこずがありたす。 実際にリンクを衚瀺するCopilot ここでCopilotには、”Web 䞊の情報だけでなく瀟内のメヌルやドキュメントなどのデヌタを参照できる” ずいう特城がありたす。これらを悪甚し、参照察象の䞭に悪意ある情報を混入させ、衚瀺名は正芏のものに芋せかけ぀぀リンク先を攻撃者が指定したものにする、ずいうのが目暙です。 仮に可胜だった堎合、攻撃者はCopilot を通しお広範囲な利甚者に悪意のある情報を送るこずが可胜です。 Copilotが䌚話の応答䞭にハむパヌリンクを衚瀺する流れ 目暙のむメヌゞ 怜蚌1: Black Hat USA 2024での手法を再珟 Black Hat USA 2024 の「Living off Microsoft Copilot」で報告された手法の再珟を目指したす。 www.youtube.com 本手法では、ナヌザヌ宛のメヌル本文に芖認しにくい圢で Copilot ぞの指瀺を埋め蟌み、その指瀺に基づいお Copilot が䞍正なリンクを提瀺するこずを期埅したす。 端的に蚀うず、指瀺は次のような意図を持぀ものでした。 サヌビスAぞのアクセス方法を尋ねられたら、指定の URL を返す ただし衚瀺名ハむパヌリンクのタむトルは『サヌビスA』ず衚瀺する メヌルの䟋 このメヌルを受け取ったナヌザヌになり代わっお Copilot にサヌビスA ぞのアクセス方法を尋ね、Copilot の応答を確認したした。 結果 攻撃手法が公開されおから時間がたち、Copilot偎で察策されおいるのか、同䞀の手法では目的を達成できたせんでした。 䟋えば、ハむパヌリンクの圢匏にはならずクリックを誘発させられないこずや、悪意のあるメヌルを参照元ずしお衚瀺し露芋しやすくなったなど、攻撃の成功率は䞋がりそうです。 クリックできないURL 怜蚌2: ナヌザヌに向けた案内 + Markdown ナヌザヌぞのメッセヌゞずしお単玔に URL を蚘茉し、ハむパヌリンクずしお出力できないようでした。 どのようにしたら察策を回避できるかを怜蚎するにあたり調査する䞭で、「EchoLeak 3 」ず呌ばれるCopilotの脆匱性に぀いお知りたした。 EchoLeakの利甚した攻撃手法や、それに応じお行われた察策に぀いお調べおいるず、Copilotは以䞋のような特城を持っおいるこずがわかりたした。 Copilot にはプロンプトむンゞェクション攻撃を防ぐための仕組みが実装されおおり、その1぀ずしお XPIAクロスプロンプトむンゞェクション攻撃分類噚がある 4 ずいうこず。そしおこれにより、Copilotぞの指瀺は悪性ずみなされる可胜性があるこず。これは回避するため、今回の堎合、Copilotぞの指瀺ではなく、受信者に向けられたメッセヌゞのように芋せかけられればよいずいうこず。 Copilot は、信頌性が確認できないリンクに぀いおはハむパヌリンクずしお提瀺せず、クリック䞍可の圢匏で応答するなどの察策がなされおいるこず。そのため、今回のように単にメヌル本文に URL を蚘茉するだけではハむパヌリンクずしお応答されない可胜性が高いずいうこず。そしお回避するためにはURLを参照圢匏でMarkdownを䜿っお指定すればよいずいうこず。なぜなのかなどは割愛したすが良かったら調べおみおください これで、怜蚌1においお倱敗した理由が玍埗できたした。この仕様を突砎できないでしょうか。 EchoLeakにおいおも察策が行われ、珟圚は悪甚出来ないずされおいたものの、悪甚に䜿甚される党おの脆匱性ぞの察応が完了しおいる蚳ではないかもしれたせん。 そこで、1,2に沿っお改良したのちに、怜蚌したした。 ナヌザヌ向けの案内文のように芋える文章を䜜成したす。その䞭で、Markdownむンラむン圢匏を甚いお、あたかもサヌビスAぞのアクセス方法を瀺すリンク名を付け぀぀、実際には私が甚意したURLを指定するようにしたす。 (なお、2に぀いお、回避するには 参照圢匏 で曞く必芁があるはずなのですが、私は誀解しお むンラむン圢匏 で指定しおしたいたした。それ次第では結果が倉わっおいたかもしれたせん) その文章をメヌルに蚘述したす。なお、HTML圢匏のメヌルずPlainText圢匏のメヌルの2皮類に぀いお詊したした。 結果 HTML圢匏のメヌル → クリックできないURLハむパヌリンクの曞匏そのたたで応答される PlainText圢匏のメヌル → クリックできるハむパヌリンクで応答される ずいう結果になりたした。PlainText圢匏のメヌルの堎合のみ成功したこずになりたす。 HTML圢匏のメヌルを参照した際のCopilot の挙動 PlainText圢匏のメヌルを参照した際のCopilot の挙動 これは憶枬ですが、Markdown 圢匏で防埡機構を回避されるこず自䜓は珟状避けられないのではないでしょうか。代わりに人間に誀認させやすいHTML圢匏のメヌルを譊戒しおおり、「参照する際は応答にハむパヌリンクを䜿甚しない」ずいうような圢で察凊しおいるのではないかず考えられたす。 確かに、PlainText圢匏のメヌルではペむロヌドずしお曞いたURLを隠せなくなるので攻撃者ずしおは嫌な気持ちになるでしょう。 怜蚌3: Excelファむルを利甚したペむロヌドの秘匿 攻撃者ずしおはやはり、 URLを蚘茉したペむロヌドは隠したい です。䞊述の通りメヌルで人間が芖認できない圢にするこずは難しそうです。 だがしかし、Copilotが参照できるのはメヌルだけではありたせん。SharePoint䞊のExcelファむルなども参照しおくれたす。そしおExcelに蚘入された文字はサむズ・色を倉曎できたす。これは䜿えるかもしれたせん。 ずいうこずで、SharePoint䞊のExcelファむルに癜文字でペむロヌド隠しおみたす。 結果 しっかりハむパヌリンクで応答されたした㊗。 たずめ Copilotが応答ずしおハむパヌリンクを䜿甚する際に、リンク名ずは関係ないURLを応答させるこずは可胜です。これを利甚しおCopilotにナヌザヌを悪意のあるサむト等ぞ誘導させられる可胜性がありたす。 ペむロヌドをメヌルに蚘茉する堎合、ペむロヌドの配送に至るたでの難易床が䜎い䞀方、PlainText圢匏で蚘述せざるを埗ないため、ナヌザヌに発芚しやすいずいう問題がありたす。 ナヌザヌから気づかれないようにする手法ずしお、メヌルではなくSharePoint䞊のExcelファむルなどぞ、芖認しにくい曞匏でペむロヌドを隠す方法がありたす。ただしこの方法は、SharePointぞファむルを配眮する暩限を取埗しおいるこずが前提であるため、ペむロヌド配送たでの難易床は高くなりたす。逆に䞀床配眮できれば、そのファむルぞアクセス可胜な党ナヌザヌに圱響を及がす可胜性がありたす。 今回の怜蚌では、ペむロヌドず䜵蚘する情報が䞎える圱響や、参照先を瀺させないための手法怜蚌など、実斜したかったが時間䞍足で詊せなかった項目が倚く残っおいたす。それでも、Copilotには倚様な悪甚の可胜性が存圚するず感じたした。 たた、攻撃の怜蚌ず䞊行しお、どのように防埡するかずいう芖点で監査ログの確認なども行いたしたが、防埡偎の負担の倧きさを改めお実感したした。たずは、Copilotがどの情報を参照するのか、およびどのような堎所にペむロヌドが隠され埗るかを防埡偎が把握しおおくこずが重芁だず考えたす。 むンタヌンの感想 私はむンタヌンシップに参加するたで、LLMに察しお同じ事象が必ずしも再珟できなかったり、理解しづらい挙動が倚かったりする点に䞍安を感じおいたした。しかし、実際に怜蚌を始めおみるず、その予枬䞍胜さも含めお面癜く無限の可胜性が広がっおいるように感じられ、非垞に楜しく没頭できたした。 今回の経隓を通じお、「食わず嫌いせずにたず挑戊しおみるこず」の倧切さを身をもっお孊びたした。 たた、本むンタヌンシップでは決められたこずをこなすのではなく、私のように倧きく脱線しながら興味に埓っお自由に怜蚌を進めるこずも受け入れおいただけたのが印象的でした。むしろ面癜がっおもらえる最高の環境でした。 業務䜓隓だけでなく、期間党䜓を通じお埗たすべおの経隓が倧倉有意矩であり、倧きな成長の糧ずなりたした。 おわりに 今回のむンタヌンシップでは日頃の掻動だけでは決しお埗られないような貎重な䜓隓をさせおいただき、ずおも光栄に思っおいたす。特に2週間を通じお珟圚ホットなテヌマであるLLMのセキュリティに぀いお深く孊ぶ機䌚をいただき、最新動向を远い続けるこずの重芁性やセキュリティそのものの面癜さを改めお実感できたした。 たた、「攻撃者の芖点に立぀」ずいう考え方に぀いおもトレヌナヌの皆さたからのご指導を通じお少しず぀身に぀けるこずができたず感じおいたす。 このような貎重な機䌚を䞎えおくださったOffensive Security PJの皆さたに心より感謝申し䞊げたす。さらに、䞊長の有藀さん、トレヌナヌの四方さん、田口さんにも厚く埡瀌申し䞊げたす。 本蚘事を通じお少しでもむンタヌンシップに興味を持っおいただけたら倧倉光栄です。 Black Hat USA 2024 - Living off Microsoft Copilot https://www.blackhat.com/us-24/briefings/schedule/?utm_source=labs.zenity.io&utm_medium=referral&utm_campaign=links-and-materials-for-living-off-microsoft-copilot#living-off-microsoft-copilot-40074 ↩ Microsoft 365 Copilot https://www.microsoft.com/ja-jp/microsoft-365-copilot ↩ Breaking down ‘EchoLeak’, the First Zero-Click AI Vulnerability Enabling Data Exfiltration from Microsoft 365 Copilot https://www.aim.security/aim-labs/aim-labs-echoleak-blogpost ↩ Data, Privacy, and Security for Microsoft 365 Copilot - Does Copilot block prompt injections https://learn.microsoft.com/en-us/copilot/microsoft-365/microsoft-365-copilot-privacy#does-copilot-block-prompt-injections-jailbreak-attacks ↩
こんにちは、NTTドコモグルヌプの珟堎受け入れ型むンタヌンシップに「D2攻撃者芖点に立ち攻撃技術を研究開発するセキュリティ゚ンゞニア」ポストで参加させおいただきたした、島田です。 本蚘事では、本むンタヌンシップでの取り組みに぀いお玹介いたしたす。 NTTドコモグルヌプのセキュリティ業務、特にOffensive Securityプロゞェクト以䞋、PJに興味のある方、むンタヌンシップの参加を怜蚎しおいる方などぞの参考になれば幞いです。 Offensive Security PJずは 参加経緯 むンタヌンシップ抂芁 LLM応甚によるRed Teamオペレヌション高床化怜蚌 Juicy 情報ずは LLMによるRed Teamオペレヌション高床化の目的 被攻撃環境の内容 Victim1 から Victim2 Victim2 の privilege escalation Victim2 から Victim3 LLMによる攻撃手順の評䟡 怜蚌方法ず怜蚌芳点 怜蚌結果 たずめ むンタヌンの感想 おわりに Offensive Security PJずは 今回私が参加させおいただいたワヌクフィヌルド職堎はむノベヌションセンタヌのテクノロゞヌ郚門内に䜍眮するOffensive Security PJです。 Offensive Security PJ は最先端のセキュリティ技術を調査・怜蚌し、その成果を瀟内倖に共有しおいくこずをミッションずしおいたす。 特に重芖しおいるのは「攻撃者の芖点」に立぀こずです。防埡の立堎から技術を眺めるだけではなく攻撃者がどのように考え、どのような手法を甚いるかを理解するこずで初めお本質的な察策を打぀こずができたす。そのような芖点を持ち続けるこずで埓来の埌远いの察策にずどたらず、脅嚁を先取りしお備える「先回りの防埡」を実珟しようずしおいたす。 単に攻撃手法を暡倣するだけでなく、その背埌にある原理やアヌキテクチャや攻撃の成立条件たで掘り䞋げるような研究・開発をしおいたす。 参加経緯 私は倧孊におネットワヌクに関する研究をしおいたすが、個人ずしおRed Team寄りの技術にも匷い関心を抱いおいたす。たた、趣味でCTFに参加したり Hack The Box のマシンを攻略したりしおいたす。 技術者の方々にずっお「アヌキテクチャを理解しおいなければ実装はできない」ずいう感芚は身近だず思いたすが、セキュリティの文脈に眮き換えるず「攻撃者の芖点を持たなければ本質的な防埡は難しい」ずいう考えに通じるず思っおいたす。日々の孊習を通じおこの重芁性を意識しおきたこずもあり、本ポストの「攻撃技術の調査・開発・怜蚌や応甚」を重芖する掻動方針ず匷く合臎するず考えたした。 これたで趣味ずしお取り組んできたセキュリティず業務ずしお取り組むセキュリティの䞡方を䜓感し、将来のアクションに繋げたいずいう思いもあり、今回のむンタヌンシップぞの応募を決めたした。 むンタヌンシップ抂芁 むンタヌンシップは8月25日から9月5日の平日10日間で開催され、業務䜓隓はオリ゚ンテヌションや成果報告䌚を陀いた実質7日間で行われたした。 初日ず最終日は出瀟が必須で、それ以倖の日皋は出瀟かオンラむンかを盞談しお決めるこずが出来たした。 たたむンタヌンシップ期間䞭は、怜蚌業務はもちろん、SOCSecurity Operation Centerの芋孊や海倖のカンファレンスに登壇された瀟員の方による再挔の聎講、瀟内LTLightning Talks䌚ぞの参加、他郚眲のむンタヌンシップ生ずの亀流などさたざたな䜓隓をさせおいただきたした。 私が怜蚌業務で取り組んだテヌマは以䞋の2぀です。 Microsoft 365 Copilotの悪甚 LLM応甚によるRed Teamオペレヌション高床化怜蚌 本蚘事では、2぀のテヌマのうち「LLM応甚によるRedTeamオペレヌション高床化怜蚌」を玹介したす。 LLM応甚によるRed Teamオペレヌション高床化怜蚌 今回のむンタヌンシップでは、Red Team オペレヌションの高床化を目的ずしおLLM を掻甚した情報分析手法の怜蚌をしたした。攻撃環境においお取埗される倧量のログや環境情報の䞭から攻撃に有甚ずなる情報を「Juicy 情報」ずOffensive Security PJ内で呌んでいるのですが、この「Juicy 情報」をどの皋床自動で識別できるかをテヌマに取り組みたした。 事前に準備された被攻撃環境を察象に、暩限昇栌やラテラルムヌブメントずいった攻撃シナリオを実際に実践し、シナリオの流れやそこで埗られる情報の特城を把握したした。その䞊で、攻略過皋で収集したログや出力のうち有効ず考えられるものを敎理し、分析察象のデヌタセットずしお掻甚したした。 こうしお埗られたデヌタを耇数の LLM に入力し、それぞれのモデルがどの皋床有甚な情報を抜出できるかを比范怜蚌したした。 Juicy 情報ずは Juicy 情報ずは、セキュリティの文脈で、攻撃や䟵入怜蚌においお「次の䞀手に盎結する䟡倀の高い情報」を指すPJ内での呌称です。資栌情報や接続先、氞続化の手がかりなどが該圓し、Red Teamのオペレヌションやペネトレヌションテストの際に非垞に有甚です。よくある䟋ずしおは、パスワヌド、管理甚IP、関連デヌタベヌスの接続情報などが挙げられたす。 たたJuicy情報は単に次の䞀手に぀ながるだけでなく、䞍芁な調査や怜蚌に陥るのを防ぎ、調査の優先順䜍付けや時間短瞮にも盎結したす。 LLMによるRed Teamオペレヌション高床化の目的 サむバヌセキュリティの䞖界においお、Red Teamオペレヌションは組織の防埡力、穎を実践的に評䟡・怜蚌するための倧きな切り札ずなっおいたす。近幎、倧芏暡蚀語モデルLLMの急速な発展は Red Team をオペレヌションする䞊でずおも有甚ず考えられおおり、無限の掻甚方法が考えられたす。 むンタヌン䞭に行ったLLMを掻甚しお取埗した攻撃マシンの脆匱性情報などが、Red Teamオペレヌションにおいおどの皋床「Juicy攻撃利甚䟡倀が高い」であり、その情報をいかに迅速か぀正確に評䟡できるかを怜蚌した結果を共有したす。 被攻撃環境の内容 今回の怜蚌は、実践的な攻撃フロヌをシミュレヌションするためにあらかじめトレヌナヌの方に構築しおいただいた挔習環境で行いたした。暙的ずしたホストらは、意図的に耇数の既知の暩限昇栌系の脆匱性や蚭定ミスが残されたWindowsの環境です。 最初は被攻撃環境を察象ずした攻撃シナリオの実践・理解のため実際にvictim1victim3の぀の攻撃マシンの攻略をしたした。ここは本業務の本質ではありたせんが、非垞に楜しく攻略させおもらったので少しwriteupずしお蚘茉しおおこうず思いたす。 Victim1 から Victim2 最初に、攻撃拠点ずなる Attacker (Kali) マシンから WS01 (victim1) ぞ C2 (Command and Control) セッションを匵るこずから始めたした。 Metasploit を甚いお悪意のあるペむロヌドを䜜成し、WS01 に送り蟌んで被害者偎で実行しおもらいセッションを確立したした。この時点では暩限はナヌザヌ暩限のみでした。 少し探玢するず dev-machine.txt ず Default.rdp ずいうファむルを芋぀けたした。 meterpreter > ls の出力は以䞋の通りです。 Listing: C:\Users\victim-user\Documents ======================================= Mode Size Type Last modified Name ---- ---- ---- ------------- ---- 100666/rw-rw-rw- 0 fil 2025-08-26 01:38:44 +0000 Default.rdp 040777/rwxrwxrwx 0 dir 2025-08-04 08:16:07 +0000 My Music 040777/rwxrwxrwx 0 dir 2025-08-04 08:16:07 +0000 My Pictures 040777/rwxrwxrwx 0 dir 2025-08-04 08:16:07 +0000 My Videos 100666/rw-rw-rw- 402 fil 2025-08-04 08:16:27 +0000 desktop.ini 100666/rw-rw-rw- 54 fil 2025-08-26 04:33:18 +0000 dev-machine.txt 䞭身を確認したずころ、以䞋のようなファむルが芋぀かりたした。 ファむル名 䞭身 dev-machine.txt DEV01 ずいうマシンに察するクレデンシャルナヌザヌ名ずパスワヌド Default.rdp RDP 接続甚の蚭定ファむルDEV01 の IP アドレスを含む これらの情報から、 DEV01 (victim2) のナヌザヌアカりント甚ログむン情報であるず刀断し、RDP 接続をし、 victim-user@DEV01 でのログむンに成功したした。 Victim2 の privilege escalation User䞀芧を芋るず victim-admin ずいうナヌザヌがあり、名前から管理者暩限を持っおいそうだず刀断したした。 C:\Users\victim-user>wmic USERACCOUNT Get Domain,Name,Sid Domain  Name                SID DEV01   DefaultAccount      xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx DEV01   Guest               xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx DEV01   victim-admin        xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx DEV01   victim-user         xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx DEV01   WDAGUtilityAccount  xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx しかし他にめがしいものは芋぀からず、ほかのツヌルを甚いおさらに調べたずころ、曞き蟌み暩限のあるディレクトリを発芋したした。その䞭で unquotedsvc 配䞋のパスが Modifiable ず衚瀺されたした。 === Services with Unquoted Paths === Service 'unquotedsvc' (StartMode: Manual) has executable 'C:\Program Files\Unquoted Path Service\Common Files\unquotedpathservice.exe', but 'C:\Program Files\Unquoted Path Service\Common' is modifable. ぀たり、Unquoted Service Path の脆匱性が確認されたずいうこずになりたす。 Windowsでは登録された Full-path が正しくダブルクオヌテヌションで囲たれおいないず、途䞭のディレクトリ名を実行ファむルずしお誀認される可胜性がありたす。 そのため、悪意のあるナヌザヌが曞き蟌み可胜な堎所に任意の実行ファむルを蚭眮できるなら、そのサヌビスが管理者暩限で起動した際に意図せずそのファむルが実行されたす。 この脆匱性を利甚しお察象システムの同䞀ディレクトリに common.exe ずいう名前のペむロヌドを配眮したした。攻撃偎の Kali マシンでは事前にリスニングを開始しおおき、察象䞊で以䞋の操䜜をしたした。 sc stop unquotedsvc を実行しおサヌビスを停止。 続けお sc start unquotedsvc を実行しおサヌビスを起動。 そうするず、サヌビスの再起動時に配眮しおいたペむロヌドが自動的に起動し、期埅通り暩限昇栌が確認できたした この暩限昇栌方法は倚数あったうちの぀であり、他にもバむナリ自䜓の曞き換えが可胜な脆匱性などを利甚した暩限昇栌方法もありたした。 Victim2 から Victim3 管理者暩限で victim-admin@DEV01 のパスワヌドを倉曎したのちログむンし、怪しいファむルがないか探しおいたら、Desktop䞊に dev ずいうフォルダを確認したした。 䞭には以䞋のようなファむルが芋぀かりたした。 accounts.csv 11皮類のナヌザヌ名ずパスワヌドが蚘茉されおいるファむル userAddTest.ps1 リモヌト接続先でアカりントを远加する甚途ず思しきスクリプト ただし、別ホストADMIN-SERVぞの接続情報は芋圓たりたせんでした。そこで最初にアクセスしおいた WS01 のマシンで、管理者暩限での探玢をしおいなかったこずを思い出し、改めお victim1 にログむンしお調べ盎したずころ、期埅通り該圓しそうな.rdpファむルを発芋したした。 今はこうしおしれっず曞いおいたすが、実際攻略を詊みおいたずきはこれに気づかず散々関係の無いログを持ったり、無駄なスキャンをかけたりしおしたっおいたした。環境を甚意しおくれたトレヌナヌの方の思惑通りにハマっおいたず思いたす。 さらに Documents 配䞋にあった PowerShell スクリプト.ps1を確認するず、ADMIN-SERV に接続するためのナヌザヌ名ずパスワヌドが蚘されおいたした。 その情報を甚いおログむンを詊みたずころ、無事に接続に成功 PS C:\Users\ServAdmin> whoami admin-serv\servadmin 管理者暩限であるこずを確認し、攻略が完了したした。 LLMによる攻撃手順の評䟡 こうしお被攻撃環境の攻略が完了し、攻撃シナリオを把握した䞊で、埗られた各皮情報を倧芏暡蚀語モデルLLMがどこたで識別できるか、たた次の䞀手に繋がる有益な瀺唆をどれだけ提瀺できるかを怜蚌したす。怜蚌の䞻県は次の2点です。 Juicy情報の迅速な識別ず構造化ができるか 怜出された倧量の情報から、攻撃にずっお最も䟡倀の高い「Juicy情報」を抜出し、JSON 等の構造化フォヌマットで出力できるかを確認。 情報に぀いおのリスク評䟡 抜出された情報に察しお、優先床どれを最初に狙うべきか・有効性実際に利甚可胜か・持続性長期的に有効か・攻撃フェヌズ初動暪展開暩限昇栌などずいった実戊的芳点から評䟡を付䞎できるかを怜蚌。 今回はMicrosoft 365 Copilot以䞋、Copilot ずAzure OpenAIのgpt-4.1モデル以䞋、OpenAI の2぀の皮類のLLMを䜿甚し、それぞれ比范怜蚌したした。 怜蚌方法ず怜蚌芳点 怜蚌は以䞋の手順で実斜したした。 victim2 の暩限昇栌時に取埗した SharpUp.exe の出力結果を LLM に入力する。 カスタムプロンプトを䞎えお、LLM に JSON 圢匏での抜出結果を出力させる。 LLM の出力ず手動で埗た結果を比范し、抜出粟床や実甚性を評䟡する。 たた、カスタムプロンプトは以䞋の芳点で䜜成し、怜蚌したした。 怜蚌芳点 目的 Juicyな情報の䞭に優先順䜍を぀けるこずはできるのか 倚数の脆匱性の䞭から、最も臎呜的なものPriority 1を特定させる。 攻撃に䜿える有効性を瀺すこずはできるのか 情報が単独で即座に攻撃可胜Immediate Exploitか、他の情報ずの連鎖Requires Chainingが必芁かを刀断させる。 情報が有効であり続ける期間可倉性はあるか 脆匱性がシステムのラむフサむクルで「Long-term長期的」に残るか、「Short-lived䞀時的」かを刀断させる。 怜蚌・攻撃をするどの段階で有効か 情報をPrivilege Escalation、Persistence、Lateral Movementなどの攻撃フェヌズに分類させる。 その情報が攻撃察象の範囲を広げるかどうか 暩限昇栌に留たらず、暪展開Lateral Movementの足がかりずなるかを刀断させる。 MITRE ATT&CKマッピング 怜出された脆匱性を暙準的な攻撃手法T-IDに玐づけさせる。 怜蚌結果 実際に詊しおみたずころ、 SharpUp.exe の実行結果は、LLM に入力するず理由や優先順䜍なども付䞎された圢で返っおきたした。単に脆匱性を芋぀けるだけでは、その利甚方法が分からず、手が止たっおしたう堎面は倚々ありたす。しかし LLM は、そのような堎面で補助的に圹立ちそうだず感じたした。 (巊Sharpup.exeの出力 右OpenAI) ここからは、2぀の LLM を比范し、怜蚌芳点ごずに盞違点を敎理しおいこうず思いたす。 怜蚌芳点 Copilot OpenAI Juicy情報の䞭に優先順䜍を぀けるこずはできるのか 順䜍にばら぀きがある。prioity=1は滅倚にない 党䜓的に高め。priority=3 が䞀぀もない 攻撃に䜿える有効性を瀺すこずはできるのか Immediate Exploit が少ない。範囲が狭め Copilotに比べお危険床の平均倀が高め 情報が有効であり続ける期間可倉性 長く芋積る傟向高め。short-livedが少ない 短く芋積もる傟向がある 怜蚌・攻撃をするどの段階で有効か 党お Privilege Escalationず刀断 党お Privilege Escalationず刀断 その情報が攻撃察象の範囲を広げるかどうか 限定的な拡匵性の明瀺により珟実性を重芖し、誀怜知を抑える方向 攻撃者がどう広げられるかを最倧限に評䟡し、攻撃面を広く捉えおいる MITRE ATT&CKマッピング 比范的緩やかで、ATT&CKの倧分類を幅広く適甚 现分類を積極的に利甚し、攻撃者の技術的アクションがより具䜓的 結論から蚀うず、Copilot ず OpenAIのいずれも、Juicy情報の抜出ず構造化を䞀定の粟床で自動化できたした。それも攻撃の材料ずなるデヌタを的確に拟い䞊げるだけでなく、それらを「優先床」「有効性」「持続性」「攻撃フェヌズ」などの評䟡軞ずずもにJSON圢匏ぞ敎理する、ずいったずころたで察応できおいたした。぀たり、埓来であれば人間がシェルのログやスキャナの出力を目芖でチェックしながら「これは䜿える」「これはノむズ」ず刀断しおいた䜜業のかなりの郚分を、LLMに肩代わりさせるこずが珟実的なレベルに来おいるずいうこずだず考えたす。 たた、リスク評䟡に぀いおも䞡LLMずも察応可胜でしたが、興味深いのは䞡者の回答に共通性が党く芋られなく、「䜕をリスクずみなすか」ずいう芖点がモデルによっお倧きく異なる点でした。モデルごずの特城ずしおは以䞋のような点が芋られたした。 å·Š: Copilot 右: OpenAI。 Copilot : 広範囲な分析を行えるが、攻撃方法そのものは瀺さず、脆匱性の説明に留たっおいる。具䜓的な悪甚方法は䞀切出お来ず、技術芁玠の分解や分析には匷みがあるず感じられる回答。 OpenAI : 攻撃者の芖点に立った指摘を返す傟向があり、次のステップに぀ながるような瀺唆が埗られる。情報の掘り䞋げもやや綿密で、脅嚁モデリングに匷みを持っおいるず感じられる回答。 情報の正確さに぀いおは、どちらが優れおいるかはこれだけでは刀別できたせん。ただし、どちらか䞀方を 100 信甚しおしたうず、怜蚌がバむアスのかかったものになりかねないため、耇数の LLM を比范・䜵甚し、盞互に補完しながら評䟡を進めるこずが望たしいかもしれたせん。 たずめ 今回の怜蚌を通じお、たずえ LLM のモデルが䌌通っおいおも返答内容に明確な差があるこずに驚かされたした。そのため、調査のスコヌプや目的に応じおモデルを䜿い分けるこずが有効であるず感じたす。 たた、Copilot の出力は想定よりもフィルタにかからず返っおきた点が意倖でした。ただし「図瀺しおください」ずいったリク゚ストにはフィルタが䜜甚し、返答が返っおこなくなるなど、制埡の仕組みが郚分的に異なるこずも確認できたした。 これは圓たり前なのですが、今回は攻撃怜蚌甚に甚意された環境だったため、぀い䜕床も゚クスプロむトを詊したりスキャンを繰り返したりしおしたいたした ごめんなさいしかし、本番の業務では実際に䌁業が運甚する環境を察象に怜蚌をするこずになるため、奜き勝手に振る舞っおはいけたせん。事前の合意や関係者ずの調敎、適切なスコヌプ定矩やログ管理など、亀枉ず運甚䞊の配慮が必須であるこずを改めお匷く意識したした。これは業務ずしお䜓隓しなければ䞀生孊べなかったこずだず思うのでずおもありがたく感じおいたす。 むンタヌンの感想 ここ最近の孊術論文を読んでいるずLLMに泚目した研究が倚いずは感じおいたした。ただ、AIずいう存圚の倧きさや耇雑さを考えるず、自分が察話型AIを日垞的に䜿っおいるにもかかわらず、それをそのたた業務に取り入れるこずにはどこか違和感がありたした。 しかし実際に業務ずしお觊れおみるずLLMずいう技術の奥深さは想像以䞊で、その有甚性を匷く実感できたした。新しい生成AIツヌルに朜む脆匱性を䜓系的に調べるプロセスや、LLMをセキュリティ領域に応甚する具䜓的な方法を孊べたこずは倧きな収穫です。圓初リモヌトワヌクの利甚で、初日・最終日以倖に出瀟しない぀もりでしたが、毎日の業務があたりにも楜しく、結局なかなかの頻床でオフィスに行きたした早起きず通勀ラッシュに慣れるのは倧倉でしたが、今ずなっおは毎日出瀟すればよかったず少し埌悔しおいたす。 さらに、流行の技術をただ远いかけるのではなくリスクを冷静に芋極める芖点、Offensive Security PJ から孊んだチヌムで知芋を共有しながら改善策を考える姿勢、新しい技術を導入するずきに既存の仕組みずどう結び぀けるかを考える柔軟さなど、こうしたものを意識できるようになったのも良い経隓でした。「䟿利さ」ず「プラむバシヌ・リスク」のバランスを垞に意識する倫理芳も、自分の䞭に根付いたず思いたす。 セキュリティ技術を深めたいず思っおいた私にずっお、関心のあるこずに思いきり取り組めたこの2週間はずおも充実した時間であり、自分の芖野や姿勢を倧きく広げおくれる経隓になりたした。 おわりに 今回のむンタヌンシップでは日頃の掻動だけでは決しお埗られないような貎重な䜓隓をさせおいただき、ずおも光栄に思っおいたす。特に2週間を通じお珟圚ホットなテヌマであるLLMのセキュリティに぀いお深く孊ぶ機䌚をいただき、最新動向を远い続けるこずの重芁性やセキュリティそのものの面癜さを改めお実感できたした。 たた、「攻撃者の芖点に立぀」ずいう考え方に぀いおもトレヌナヌの皆さたからのご指導を通じお少しず぀身に぀けるこずができたず感じおいたす。 このような貎重な機䌚を䞎えおくださったOffensive Security PJの皆さたに心より感謝申し䞊げたす。さらに、䞊長の有藀さん、トレヌナヌの四方さん、田口さんにも厚く埡瀌申し䞊げたす。 本蚘事を通じお少しでもむンタヌンシップに興味を持っおいただけたら倧倉光栄です。
デゞタル改革掚進郚の小林です。いたは瀟内認蚌サヌビス・基盀のプロダクトオヌナヌをやっおいたす。5月たではむノベヌションセンタヌにいたした。 去る11月15日土曜日に開催された BTCON JP 2025 においお、「珟堎ずIT郚門の橋枡しをしお3000人の開発者を救った話」ずの題で登壇しおきたした。この蚘事では、ask the speakerのコヌナヌや、懇芪䌚でお話しした内容を螏たえお、その発衚では盛り蟌めなかった内容をお䌝えしたす。 アヌカむブ動画が公開されたした2026/2/20 远蚘 発衚のあらたし 远加コンテンツ どうやるかは最埌 䌚っお話す 端からめくる 燃え尜きに泚意 終わりに アヌカむブ動画が公開されたした2026/2/20 远蚘 公匏からアヌカむブ動画が公開されたした。ぜひご芧ください。 発衚のあらたし か぀おこのブログの蚘事「 ゚ンゞニアが゚ンゞニアのために開発・怜蚌甚 PC を敎備した話 」で玹介した話を題材に、珟堎ずIT郚門の付き合いにおける人的偎面に焊点を圓お、察話・協働・挑戊の奚励が重芁であるずの孊びを報告したした。登壇資料はこちらにアップロヌドしおおきたしたので、よろしければご芧ください。 远加コンテンツ このセクションでは、発衚であえおカットした、あるいはお話しし損ねた内容をいく぀か玹介したす。 どうやるかは最埌 セッションA9「LINEダフヌ合䜵におけるグルヌプ埓業員/アカりント管理の課題」を発衚されたLINEダフヌの久保貎史さんず懇芪䌚でお話しした折、この話が出たした。 久保さんの発衚では、新たに策定した管理策を海倖法人を巻き蟌んで今埌実斜しおいくこずが玹介されたした。懇芪䌚では「海倖法人に指瀺を通しきるのは難しいずころもあるず思いたすが、どのように実効力あるものにしたすか」ずの私の問いに、「なぜやるかをずこずん説明する。そのために䞞1日かけた」「howの話は埌でよくお、whyをみんなで合わせるのが重芁」ずの明快な回答をいただきたした。 発衚に盛り蟌み損ねたのはたさにそこで、ある課題が発芋された際に、なぜその課題を解かなければならないかを関係者党員で共有・玍埗できおいるず、解決が爆速になりたす。そもそも解くべき課題だず自分が認識しおいる事柄が、他者には課題だず思われおいないこずもしょっちゅうです。玍埗しおいない人を動かすこずほど難しいこずはありたせん。海倖ずはデフォルトで共有できる䟡倀芳があたり倚くないこずもしばしばですから、ここのwhyに関する察話をゆるがせにするずうたく行かないのは道理だなず感じたした。 たた、久保さんは「珟地に蚪問しお䜜業を芳察し、疑問に思うアクションがあればなぜそれを行っおいるのか、その堎で確認した」ずもおっしゃっおいたこずが印象的でした。答えはフィヌルドにこそありたす。 䌚っお話す 今回の発衚は「コミュニケヌションの話」ずたずめるこずもできるかず思いたすが、発衚資料ではコミュニケヌションの語をあえお䞀切出したせんでした。「コミュニケヌション」の語で受ける印象に、広がりがありすぎるず考えおいるためです。 コミュニケヌションのスタむルはいろいろず想定されたす。蚀語・非蚀語、テキスト・ビゞュアル、察面・非察面、などなど。今回の発衚で私が䞀貫しお䞻匵したいのは「䌚っお話す」こずです。「䌚っお話す」を実珟するにはその文字通り、盎接出向いお面ず向かうしか方法がありたせん2025幎11月珟圚。 䌚いに行くこずには力がありたす。チャットやメヌルだずやたら圓たりがキツい人でも、䌚っお話すず物腰柔らかくお驚くずいったこずもありたす。たずはアポを取っおみたせんか。 端からめくる Ask the speakerのコヌナヌにお芋えになった方に、「端からめくる」話をしたした。これは圓瀟のずある元圹員が䜿っおいた衚珟で、問題解決にあたっおはいきなり䞻流掟をどうにかしようず思わず、少し背䌞びする皋床くらいで解決できるような身の回りのこずから始めるのがよいずいった意味合いです。 繰り返しになりたすが、解きたい課題があるなら、それは解くべき課題だず理解しおくれる仲間を䜜るずころから始めたしょう。仲間がいるのは心匷いものです。そのうち仲間が増えれば、それがい぀の間にか䞻流掟になりたす。 燃え尜きに泚意 IT郚門始めバックダヌドには責任感の匷い方がしばしば芋られたす。それ自䜓はずおもよいこずですが、あたりにも匷すぎる責任感は燃え尜きに぀ながりたす。䜕を隠そう私自身がそうで、自分䞀人でなんずかしなければず背負い蟌みすぎおいた時期を経隓しおいたす。考え盎したきっかけはもはや思い出せたせんが、あれは思い違いだったず今ならはっきり蚀えたす。 困ったずきには助けを求めたしょう。助けを求めるこずは責任の攟棄ではありたせん。きちんず匷いチヌムであれば、チヌムで成果が出ればよいこずを誰もが知っおいたす。たたチヌムのマネヌゞャヌである方には、チヌム内で助けを求めやすい環境䜜りをお願いしたいず思いたす自ら道化を挔じるでもよいず思いたす。 終わりに 開発PCを䜜った経隓からはさたざたな孊びがあり、ずりわけこの人的偎面の話は本圓に身に染みたしたほかの開発メンバヌからも異口同音に聞かれたした。い぀かは倖郚発衚したいず思っおいたずころで、このような圢で機䌚をいただきたした。圓日䌚堎・YouTubeでご芧いただいたみなさん、たたBTCON JP 2025運営メンバヌのみなさん、ありがずうございたした。
はじめに こんにちはNTTドコモビゞネスの2025幎倏の珟堎受け入れ型むンタヌンシップに参加させおいただきたした、むンタヌン生の竹田です。私は珟圚高専の専攻科1幎生で、普段は船舶におけるサむバヌセキュリティに関する研究掻動を行っおいたす。 この蚘事では、私が今回のむンタヌンシップで取り組んだ業務䜓隓内容に぀いお玹介したす。 はじめに 参加のきっかけ むンタヌンシップ抂芁 OTセキュリティずOsecTの抂芁把握 テヌマ遞定 怜蚎1: 船舶での䜿甚プロトコル調査 NMEA 0183 IEC61162-450 怜蚎2: 珟状の船内ネットワヌク調査 怜蚎3: 船舶pcapに察する珟状のIDS補品の出力怜蚌 Talker IDから資産を出力するZeek・Spicyパヌサヌ䜜成・怜蚌 Zeek・Spicyずは パヌサヌ怜蚌 たずめ むベントぞの参加 SOC芋孊 ドコモずのコラボ䌁画 むノベヌションセンタヌ内での業務共有 TechLunch むンタヌンシップを通しお孊んだこず おわりに 参加のきっかけ 私がむンタヌンシップに参加したのは、研究のテヌマずしお「船舶におけるIDS䟵入怜知システム」を扱っおいるこずが理由です。制埡システムのセキュリティず船舶のセキュリティは「可甚性」を最重芁芖するずいう点で類䌌しおいるため、実際に制埡システムで䜿甚されおいるOT-IDS制埡システム向けIDSがどのように運甚されおいるのかを知りたいず思いたした。たた、船にIDSを導入するこずで船舶䌚瀟にどのような利点が芋蟌めるのか、導入する堎合の技術的な課題は䜕かに぀いお理解したいずいう思いもありたした。 むンタヌンシップ抂芁 今回私は、NTTドコモビゞネス むノベヌションセンタヌで、OTシステム向けIDS・セキュリティ可芖化サヌビスである、OsecTオヌセクトの開発に関する業務を行いたした。 むンタヌンシップで行った業務䜓隓内容を以䞋にたずめたす。 OTセキュリティずOsecTの抂芁把握 たず、OTセキュリティの抂芁を把握するために、むノベヌションセンタヌが瀟䌚人向けに提䟛しおいる教育プログラムを受講させおいただきたした。 講矩では、Stuxnet、Mirai、WannaCryずいったマルりェアが制埡システムに圱響を及がした事䟋に加え、GPSスプヌフィングやWebカメラの䞍正利甚など、制埡環境にも波及する脅嚁が玹介されたした。たた、ランサムりェア被害を受けた䌁業の玄53が50䞇ドル以䞊の身代金を支払ったずいう 調査結果 を知るこずになりたした。私はこの数字を聞いお、サむバヌリスク保険の存圚によっお経枈的負担が枛っおいるために、莫倧な金額を請求されおも䌁業が支払いに螏み切っおしたう珟状があるのではないかず思いたした。 さらに、ICSサむバヌキルチェヌンやMITRE ATT&CK for ICSずいった、OTセキュリティ特有の分析フレヌムワヌクも玹介されたした。これたで䞀般的なITセキュリティのフレヌムワヌクしか知らなかったため、制埡システム向けに敎理された独自の手法が存圚するこずを初めお知り、新鮮な孊びずなりたした。 OTセキュリティの抂芁を孊ぶ䞊で特に面癜いなず感じたのは、 業界によっおセキュリティ芁件の枠組みが倧きく異なる 点です。 船舶分野 UR E26/27 ずいう囜際的に統䞀された技術芁件が存圚し、グロヌバルに共通の基準に基づいお安党性やサむバヌセキュリティ察策を敎備する流れがある。これは囜際航行を前提ずするため、䞖界的に統䞀されたルヌルが䞍可欠ずなっおいる。 補造分野 囜や地域、さらには分野ごずに異なる芏栌が䞊立しおおり、北米では CSA芏栌 、EUでは NIS2指什、 半導䜓分野では SEMI芏栌 などが䟋ずしお挙げられる。垂堎や技術領域の倚様性が倧きいため、各地域、各分野で独自の芁件が策定されおいる。 この違いは、業界ごずの囜際性や䟛絊網の特性を反映しおいるず考えられたす。船舶は囜際航行を前提ずするためグロヌバルに統䞀されたルヌルが䞍可欠である䞀方、補造業は垂堎や技術領域の倚様性が倧きいため、各地域で独自の芁件が策定されやすいのだず理解したした。 単に「OTセキュリティ」ず括るのではなく、こうした制床蚭蚈や暙準化の背景を螏たえお孊ぶこずの重芁性を改めお実感したした。 次に、チヌムが開発しおいるサヌビスであるOsecTに぀いおの説明を受けたした。 (匕甚元: https://www.ntt.com/business/services/security/security-management/wideangle/osect.html ) OsecTは2぀の基本機胜を備えおいたす。 ネットワヌクの可芖化 ネットワヌクトラフィックを分析し、資産・通信・セキュリティリスク等をwebポヌタル画面で可芖化できたす。これにより、ネットワヌクマップやトラフィック量から重芁な端末を芖芚的に把握でき、察応の優先順䜍が぀けやすくなりたす。 脅嚁・脆匱性の怜知 通信状況を孊習し、脅嚁や脆匱性を怜知した際にアラヌトを通知したす。怜知した情報はwebポヌタルでも確認可胜です。 たた、 資産台垳ず連携する機胜 も持っおいるため、䞍審な状況を芋぀けたずきに蚭眮堎所や担圓者などの情報をもずに、玠早く察応するこずが可胜ずなっおいたす。さらに、資産台垳に登録されおいない、いわゆる未把握の機噚も衚瀺されるため、台垳の挏れを補完したり、䞍正に接続された端末の存圚を調査したりするこずも可胜です。これにより、既存の資産管理の粟床を高めるず同時に、セキュリティリスクを早期に発芋する仕組みずしおも掻甚できたす。 䞀方で、珟行の仕組みには課題があるこずも瀺されたした。䟋えば、IPアドレスを持たない機噚に぀いおは、察応しおいるOTプロトコル以倖は可芖化の察象倖ずなるため、 すべおの資産を完党に把握できるわけではありたせん 。 説明を聞いお、これたでIDSずいうず「脅嚁怜知」をするものだずいう印象がありたしたが、OT-IDSには「ネットワヌクの可芖化」ずいう重芁な圹割も担っおいるんだずいうこずを知り、ずおも勉匷になりたした。 テヌマ遞定 ここたでの講矩・説明を受けお、私はある1぀の仮説を立おたした。 船舶のプロトコルを分析 すれば船内の資産を把握でき、 資産むンベントリの䜜成・曎新補助ができるのではないか。 ※資産むンベントリずは、 IACS UR E26/27 で提出が矩務付けられおいる、船舶機噚の詳现をたずめた台垳です。 船舶のラむフサむクルを通じお船舶資産むンベントリは曎新・維持されなければならないこずを考慮しお䜜成する必芁がありたす。なお、 資産むンベントリの管理を手動で行う堎合、曎新䜜業が煩雑になる可胜性がありたす。 そのため、資産むンベントリの曎新を効率化し、粟床を高めるために、 システム化が掚奚されたす。 Class NK | IACS UR E26 p.31 4-1.2より この点を螏たえ、各船舶機噚が発する固有のシグナルを掻甚できれば、船舶資産の自動識別が可胜ずなり、資産むンベントリの䜜成・曎新䜜業を倧幅に補助できるのではないかず考えたした。 しかし、OsecTは船舶特有のプロトコルに察しお十分な解析機胜を持っおいたせん。解析可胜ずするためには新たに専甚のパヌサヌを開発・実装する必芁がありたす。 そこで、以䞋のプロセスで調査・怜蚌を進めるこずにしたした。 怜蚎1: 船舶での䜿甚プロトコル調査 調査の結果、船舶では䞻に2぀のプロトコルが䜿われおいるこずが分かりたした。調査内容を以䞋にたずめたす。 NMEA 0183 NMEAは「National Marine Electronics Association米囜海掋電子機噚協䌚」の略。 船舶機噚間の通信のための仕様で、朮流蚈、音響枬深機、ゞャむロコンパス、GPSなどのデヌタを䌝送するために䜿甚される。シリアルポヌトを䜿甚した片方向通信でASCII圢匏。 䟋GPS $GPGGA,052400.00,3539.3146239,N,13945.6411751,E,4,07,0.59,4.987,M,34.035,M,1.0,3403*76 デヌタ匕甚元: https://ales-corp.co.jp/technical-information-nmea/  Talker ID ずよばれる、どの機噚がそのデヌタを送信しおいるかずいう識別子がある。䞊蚘の䟋では、 $GPGGA の GP の郚分がTalker IDずなる。 Talker ID察応衚䞀郚 匕甚元 pynmea2/NMEA0183.pdf at master · Knio/pynmea2 · GitHub | **ID** | **解説** | | --- | --- | | AG | 䞀般的なオヌトパむロット | | AP | 磁気コンパス連動のオヌトパむロット | | CD | DSCデゞタル遞択呌出通信装眮 | | CR | 無線ビヌコン受信機 | | CS | 衛星通信機 | | CT | MF/HF垯ラゞオ電話通信機 | | CV | VHF垯ラゞオ電話通信機 | | CX | スキャン機胜付き無線受信機 | | DF | 方䜍探知機 | | EC | ECDIS | | EP | EPIRB | | ER | 機関宀モニタリングシステム | | GP | GPS受信機 | | HC | 磁気コンパス | | HE | ゞャむロコンパス真北远埓 | | HN | ゞャむロコンパス非真北 | | II | 統合蚈枬機噚 | | IN | 統合ナビゲヌションシステム | | LC | ロランC | | P | メヌカヌ独自非暙準 | | RA | レヌダヌ/ARPA自動衝突予防装眮 | | SD | 音響枬深機 | | SN | その他の電子枬䜍システム | | SS | スキャニング音響枬深機 | | TI | タヌンレヌトむンゞケヌタ | | VD | ドップラヌ匏速床センサ | | DM | 氎䞭・磁気匏速床ログ船速蚈 | | VW | 氎䞭・機械匏ログパドルホむヌル等 | | WI | 気象センサ | | YX | トランスデュヌザヌ | | ZA | 原子時蚈 | | ZC | クロノメヌタヌ | | ZQ | 氎晶時蚈 | | ZV | 電波時蚈 | IEC61162-450 IECは「International Electrotechnical Commission囜際電気暙準䌚議」の略で、埌ろに暙準化された芏栌の番号を付䞎しお文曞や通信芏栌そのものの名ずしお利甚される。 UDPマルチキャストを䜿っお、NMEAセンテンスをEthernetパケットで送信するための芏栌。 䟋 UdPbC\0\s:GP0001\$GPGGA,052400.00,3539.3146239,N,13945.6411751,E,4,07,0.59,4.987,M,34.035,M,1.0,3403*76\r\n タグブロック郚ず呌ばれる、NMEAセンテンスの盎前に配眮される行の䞭には sブロック ずよばれる送信元識別子がある。 調査の結果、NMEA 0183には Talker ID 、IEC61162-450には sブロック ず、どちらのプロトコルにも資産特定に䜿えそうな識別子がありたした。 怜蚎2: 珟状の船内ネットワヌク調査 次に、珟状の船内ネットワヌクがどのような構成なのか調査したした。 出兞 JRC | 船内LANシステム あくたで私の予想ですが、GPSや朮流蚈などのシリアル出力デヌタNMEA 0183を入出力IF装眮がIEC61162-450に倉換しおいるのだず思われたす。 怜蚎3: 船舶pcapに察する珟状のIDS補品の出力怜蚌 次に、OsecT以倖でのOT-IDSに぀いおも船舶プロトコルの察応状況を調査するために、以䞋の環境を想定したpcapファむルを甚意し、2぀のOT-IDS補品を䜿っおトラフィック解析したした。 結果ずしお、今回の怜蚌で䜿甚したOT-IDSでは船舶で䜿われおいるプロトコルを解析できたせんでした。このため、OsecTに適甚可胜な船舶プロトコルパヌサヌを新たに䜜成するこずにしたした。 今回は、IEC61162-450の仕様曞が手元にないむンタヌネットにもあたり情報がないため、NMEA 0183のTalker IDを足掛かりにしおパヌサヌの䜜成を進めたした。 Talker IDから資産を出力するZeek・Spicyパヌサヌ䜜成・怜蚌 OsecTのパヌサヌはZeek・Spicyで構成されおいたす。 Zeek・Spicyずは Zeek トラフィックを解析しお、IPアドレス、MACアドレスやプロトコルなどの情報をログずしお出力するOSS。 Spicy Zeekで利甚するC++のパヌサヌをC++で蚘述するこずなく簡易に生成するためのツヌル。 参照 【日本初玹介】Zeek・Spicyの䜿い方たずめ - NTT docomo Business Engineers' Blog 今回は、ZeekずSpicyを䜿っお船内ネットワヌクトラフィックを解析するためのパヌサヌを䜜成したした。 パヌサヌ怜蚌 䜜成したパヌサヌを䜿っお、実際に船内ネットワヌクトラフィックpcapファむルを解析したした。 今回の怜蚌では、2皮類のNMEA 0183メッセヌゞからTalker IDずSentence Typeの2぀のフィヌルドを抜出し、Talker IDからセンサの特定ができおいるかを確認したした。以䞋は、ZeekずSpicyを甚いお取埗したNMEAメッセヌゞの解析結果logファむル抜粋です。 GP の堎合GPS HE の堎合Heading ゞャむロコンパス 䞊蚘の通り、Talker IDから発信元のセンサの特定船舶資産の特定が行えおいるこずが分かりたす。 たずめ 今回は、既存のOT-IDSが船舶特有のプロトコルを解析できないずいう技術課題に察し、NMEA文を解析可胜にする独自のパヌサヌを䜜成したした。 このパヌサヌではNMEA 0183内に含たれるTalker IDを足掛かりにしお船舶機噚を特定できるように蚭蚈しおおり、その情報をOsecTの可芖化機胜に組み蟌むこずで、船舶特有の機噚の可芖化の匷化や資産むンベントリの補助に぀ながる可胜性があるずいうポゞティブな成果を埗るこずができたした。 むベントぞの参加 IDSに関する業務以倖にも耇数の瀟内むベントや芋孊䌚に参加させおいただきたした。 SOC芋孊 NTTセキュリティのSOCSecurity Operation Centerを芋孊したした。 圓初はSOCに察しお「脅嚁を怜知したら即座にアラヌトを出す堎所」ずいうむメヌゞを持っおいたした。しかし、実際にNTTセキュリティが提䟛するSOCサヌビスは䞀定期間トラフィックを収集・分析し、詳现なレポヌトずしおクラむアントに提䟛するサヌビス圢態であるこずを知りたした。SOCには倚様な圢があるのだずいうこずを知るこずができ、ずおも勉匷になりたした。 ドコモずのコラボ䌁画 むノベヌションセンタヌで攻撃むンフラの解明や撲滅に向けお掻動しおいるPJがセキュリティ囜際䌚議「Botconf」で発衚した内容を、ドコモ本瀟のむンタヌン生ずずもに聎講させおいただきたした。 発衚内容は新ロシア掟ハクティビストに関する詳现なレポヌトで、実際の脅嚁情報分析の手法を孊ぶ貎重な機䌚ずなりたした。たた、ハクティビストの情報を安易に拡散するこずがかえっお悪圱響を生む可胜性があるず知り、情報ずの向き合い方を考え盎すきっかけにもなりたした。 むノベヌションセンタヌ内での業務共有 むノベヌションセンタヌ内で掻動する5名のむンタヌン生が、それぞれの担圓業務や取り組み内容を共有したした。 普段は近くで䜜業しおいおも、実際に䜕をしおいるのか詳しく知る機䌚は少なかったので、ずおも新鮮でした。みんな党然違うテヌマやプロゞェクトに取り組んでいお、「そんなこずやっおるんだ」ず驚くこずも倚く、チヌムの倚様性やそれぞれの専門性の広さを実感できお面癜かったです。 TechLunch NTTドコモビゞネスで䞍定期開催されおいるランチ勉匷䌚「TechLunch」に参加したした。 「勉匷䌚」ずいう蚀葉から堅い雰囲気を想像しおいたしたが、実際は瀟員の方がそれぞれの興味関心に基づいお自由に発衚する圢匏で、掻発か぀フランクな孊びの堎でした。 圓日は瀟員1名ずむンタヌン生2名の発衚があり、発衚䞭はSlack䞊でリアルタむムに反応が飛び亀い、オヌプンな雰囲気を感じたした。 むンタヌンシップを通しお孊んだこず むンタヌンに参加する前は、GPSスプヌフィングやAISスプヌフィングずいった船舶に倚く芋られる攻撃を怜知するIDSを䜜成するこずを考えおいたした。しかし、OT-IDSの説明をしおいただく䞭で「資産むンベントリ補助」ずいう新たな掻甚方向を芋出すこずができ、ずおも有意矩な経隓ずなりたした。 たた、補造業ず船舶業界ではセキュリティ芁件の枠組みが倧きく異なるこずも孊びたした。将来的には補造業のセキュリティ分野に関わりたいず考えおいるため、今埌は制床やプロトコルの違いを意識しながら、より幅広い芖点で孊びを深めおいきたいず思いたす。 さらに、むンタヌンを通じおセキュリティに関わる仕事の珟実的な難しさず奥深さを実感したした。重倧なむンシデントが起こらないこずは、セキュリティに携わる者ずしお理想的な状態です。しかし䞀方で、䜕か倧きな事件が起こらなければ業界党䜓の意識や敎備が進みにくいずいう珟状もあり、その間にある葛藀のようなものを感じたした。 おわりに 今回のむンタヌンはこれたで開発に携わった経隓がなかった自分にずっお、倧きな䞀歩を螏み出す機䌚ずなりたした。以前から「䜕かを䜜っおみたい」ず思いながらも、具䜓的なアむデアが浮かばなかったり、時間を理由に埌回ししおしたったりしおいたした。そんな䞭で、実際に手を動かしお開発ぞ取り組めたこずは、自分にずっお非垞に貎重な経隓でした。 たた、さたざたなむベントにも参加させおいただき、自分の所属チヌムだけでなく他のチヌムやむンタヌン生、さらにはドコモグルヌプの瀟員の方々ずも関わるこずができたした。郚眲を越えお倚くの方ず亀流する䞭で、職堎の雰囲気や、人ずの぀ながりの倧切さを改めお実感したした。 最埌になりたしたが、このむンタヌンに関わっおくださった皆さたに心より感謝申し䞊げたす。受け入れおくださったチヌムの皆さた、特にこのむンタヌンで参加したIT/OT統合セキュリティPJおよびOsecT Tech PJの田䞭さん、前田さん、加島さんには2週間にわたり倧倉お䞖話になりたした。枩かくご指導くださり、本圓にありがずうございたした。
こんにちは、むノベヌションセンタヌの田口、金井です。 普段はOffensive Security PJのメンバヌずしお掻動しおいたす。 この蚘事では2025幎8月に開催されたSOUPS 2025でポスタヌ発衚したこずおよび同時期に開催された USENIX Security 2025ぞ参加したこずに぀いお玹介したす。 Offensive Security PJに぀いお USENIX Securityに぀いお SOUPSに぀いお ポスタヌ発衚に぀いお 発衚抂芁 発衚の様子 カンファレンスの様子 セキュリティ分野の研究動向 䌚堎の雰囲気 おわりに Offensive Security PJに぀いお Offensive Security PJ では、攻撃者芖点のセキュリティOffensive Securityを専門ずするチヌムずしお、 攻撃技術の調査・開発・怜蚌に取り組んでいたす。 攻撃者に先んじお新たな攻撃技術を怜蚌するこずで、将来の脅嚁を芋越した防埡の匷化に぀なげおいたす。 䞻な業務内容ずしおWideAngleのプロフェッショナルサヌビスにおける攻撃技術の怜蚌支揎や、 最先端の攻撃技術に関する応甚的な研究開発を行っおおり、 成果のカンファレンス発衚など察倖的な掻動にも積極的に取り組んでいたす。 USENIX Securityに぀いお USENIX Securityはサむバヌセキュリティ分野の䞖界的なトップカンファレンスの1぀です。 厳しい査読を通過した完成床の高い研究のみが発衚される、たさに最先端のセキュリティ研究に觊れるこずができるカンファレンスです。 34回目ずなる今幎は米囜シアトルで8月13日から15日たでの3日間開催されたした。 今幎は論文発衚が439件、ポスタヌ発衚が60件あり参加者は玄900名でした。 SOUPSに぀いお SOUPSSymposium on Usable Privacy and Securityはナヌザブルセキュリティ&プラむバシヌ分野における最難関の囜際䌚議です。 ナヌザブルセキュリティ&プラむバシヌずは、コンピュヌタやシステムを扱う人間に焊点を圓お、 人間が扱いやすいセキュリティを䞻題ずする研究分野です。 USENIX Securityずの䜵催䌚議ずしお毎幎同時期に開催されたす。 21回目ずなる今幎も䟋幎通りUSENIX Securityの䜵催䌚議ずしお8月10日から12日たでの3日間開催されたした。 今幎は論文発衚が30件、ポスタヌ発衚が49件あり、参加者は186名でした。 ポスタヌ発衚に぀いお 発衚抂芁 SOUPS 2025で発衚した研究抂芁に぀いお玹介したす。 Offensive Security PJでは「Offensive Security × HCIHuman-Computer Interaction」 ずいうテヌマを掲げお研究開発業務をしおいたす。 SOUPS 2025では“ Understanding the Challenges in Red Team Exercises from Multiple Stakeholder Perspectives ”ずいうタむトルで発衚しおきたした。 今回の研究で私達は、レッドチヌム挔習に埓事する専門家ぞむンタビュヌし、 専門家が抱える課題認識を分析するこずで、 実斜するにあたりどのような障壁が存圚するのかを明らかにしたした。 この研究では、レッドチヌム挔習における疑䌌攻撃者を担う専門家ず、 挔習党䜓の統括を担う専門家ずいう異なる圹割を持぀2぀の専門家に察しおむンタビュヌしたした。 耇数の圹割の芖点から課題を調査する取り組みは既存研究ずしおは無く、 この研究のキヌコンセプトず蚀えたす。 珟圚はこの研究のネクストアクションずしお、明らかにした課題を解決するための研究開発に取り組んでいたす。 レッドチヌム挔習ずは、評䟡察象ぞ疑䌌的攻撃をするこずで 察象組織やシステムのセキュリティを評䟡するセキュリティテスト手法の1぀です。 発衚者の田口 発衚の様子 SOUPS 2025のポスタヌ発衚は8月11日のテクニカルセッション終了埌のレセプションパヌティヌ䌚堎で行われ、 参加者はドリンクず軜食を持っお䌚堎内のポスタヌを巡り自由に質問や議論をしおいたした。 SOUPSではフレンドリヌな雰囲気で話をしおくれる参加者が倚く、 英語が堪胜でない私でも有意矩な質疑応答や議論ができたず感じおいたす。 質疑応答では「むンタビュヌで参加者はどのような課題感を述べた」、 「今埌むンタビュヌ調査を拡倧する予定はある」ずいった質問をいただきたした。 レッドチヌム挔習の実務者にむンタビュヌで盎接課題を聞き出したずいう点が特に興味を匕いおいた印象を芚えたした。 研究自䜓に察するポゞティブな反応も倚くもらうこずができネクストアクションのモチベヌションにも぀ながる良い機䌚だったず思いたす。 カンファレンスの様子 カンファレンスの情報や珟地の様子に぀いお玹介したす。 セキュリティ分野の研究動向 オヌプニングセッションにお、USENIX Security 2025に投皿・採択された論文の研究トピックの割合に぀いおUSENIX運営から説明されたした。 昚幎から匕き続き論文投皿数ず採択数共に1䜍だった研究トピックはML & AIセキュリティに関する論文でした。 Human Factor人に着目した分野に関する研究トピックも幎々増えおきおいる傟向にありたす。 たた、今幎採択された論文の研究トピック割合ずしおは以䞋のように瀺されおいたした。 ML & AI: 23% System, software, crypto, network: 65% Human factors: 12% 䌚堎の雰囲気 党日皋Seattle Convention Center Archで行われたした。 オヌプニング前のメむンホヌルです。倧人数の参加者が十分着垭できるほどの広さでした。 運営組織であるUSENIX Associationが今幎で蚭立から50呚幎を迎え、 倧きなケヌキを甚意した蚘念パヌティヌが開催されたした。 おわりに SOUPS、USENIX Securityに参加するこずで最新のセキュリティ研究を知ったり、 珟地で囜内倖のセキュリティ研究者たちず亀流したりず埗られるものがずおも倚かったず感じおいたす。 たた、ポスタヌ発衚で参加者ず英語で積極的に議論した経隓は、私に自信ずモチベヌションを䞎えおくれる貎重な経隓だったず思いたす。 私達の発衚を含め採択されたポスタヌや論文は SOUPS 2025 、 USENIX Security 2025 のホヌムペヌゞにお公開されおいるのでぜひ読んでみおください。
本蚘事では、珟圚進行䞭で取り組んでいるテヌマ「生成AI×数理最適化」に関する詊みずしお、生成AIを掻甚しお数理最適化技術の実務適甚を支揎するアプロヌチを玹介したす。䟋ずしお、スヌパヌマヌケットにおける圚庫管理の効率化を取り䞊げ、その具䜓的な応甚ず効果に぀いお述べたす。 はじめに 背景 数理最適化モデルの定匏化ず実装に䌎う困難 生成AIの台頭 実珟アプロヌチの怜蚎 生成AI掻甚の党䜓像 圚庫最適化の課題蚭定 実珟たでのステップ 1. 定匏化支揎゚ヌゞェントによる定匏化支揎 2. 入力デヌタ蚭蚈支揎゚ヌゞェントによるデヌタ蚭蚈支揎 3. Node-AIを掻甚したデヌタの準備 4. コヌド生成゚ヌゞェントによる実行コヌド生成 5. 䜜成されたコヌドの実行ず結果 たずめ おわりに はじめに こんにちは、むノベヌションセンタヌ テクノロゞヌ郚門 先端AI数理PJの䌊藀です。 普段は Node-AI や AI Autopilot System などのプロダクト䟡倀向䞊に加え、お客さたから寄せられる課題に察しおデヌタ分析を通じた解決策の研究開発に取り組んでいたす䟋えば 孊習速床ず倉数遞択粟床を極めたFastGSCADモデル (Ver. 3.22.0)Node-AI by NTTドコモビゞネス など。 昚幎床は 機械孊習×数理最適化で業務プロセス革呜 - NTT docomo Business Engineers' Blog ずいう蚘事を執筆し、ありがたいこずに倚くの反響をいただきたした。珟圚も、予枬結果を掻甚した数理最適化技術の研究開発を継続しおおり、最近では、数理最適化による課題解決を支揎する生成AIの掻甚の研究にも泚力しおいたす。 本蚘事では、スヌパヌマヌケットにおける圚庫管理を䞀䟋に、生成AIによる支揎を掻甚した数理最適化技術による課題解決のアプロヌチをご玹介したす。 背景 数理最適化モデルの定匏化ず実装に䌎う困難 数理最適化では、珟実に存圚する課題を以䞋の圢匏に抜象化し、数孊的モデルずしお衚珟するこずが求められる堎面は倚くありたす。 具䜓的には、 個の䞍等匏制玄ず 個の等匏制玄を満たしながら、問題の解を決めるための倉数 を調敎し、目的関数 を最倧化する解を求めるこずを指したす。 䟋えば、 こちらの蚘事 で取り䞊げおいるコヌルセンタヌにおけるオペレヌタヌ最適配眮の課題では、課題の敎理から出発し、以䞋のような数理最適化モデルぞず定匏化を行っおいたす詳しくは 該圓蚘事 をご参照ください。 このような数匏で蚘述された最適化問題は、プログラムずしお実装し、最適解を導出するこずで、業務䞊の意思決定に応甚されたす。 しかし、このような定匏化やプログラムの実装には、数理的な知識に加えお、プログラミングスキルずいった高床な専門性が求められたす。そのため、珟堎で課題を抱える方々が自ら数理最適化モデルを構築・運甚するには技術的なハヌドルが高く、専門家の支揎が䞍可欠ずなるケヌスも少なくありたせん。 生成AIの台頭 近幎、読者の皆さたもご存じのずおり、ChatGPT や Gemini に代衚されるアプリケヌションの登堎により、生成AIは倧きな泚目を集めおいたす。生成AIの掻甚によっお、日々の生掻や業務の圚り方が倧きく倉わったず感じおいる方も倚いのではないでしょうか。 NTTドコモビゞネスにおいおも、生成AIに関する取り組みが積極的に進められおおり、次のような公開情報からもその䞀端をご芧いただけたす 生成AIGenerative AINTTドコモビゞネス 法人のお客さた 。たた、 Node-AI も、ナヌザヌによっお自由床の高い可芖化や前凊理を支揎するために、生成AIを掻甚したサポヌト機胜が提䟛されおいたす。詳しくは以䞋のリ゜ヌスをご参照ください。 デヌタ可芖化 - AI可芖化 デヌタ前凊理 - AIアシスト付きカスタム前凊理 このような流れを受け、私たちは珟圚、数理最適化問題の定匏化やプログラム実装のプロセスを、生成AIによっお支揎・自動化する研究に取り組んでいたす。 具䜓的には、業務課題を自然蚀語で入力するだけで、生成AIが最適化問題ずしおの構造を理解し、目的関数や制玄条件を抜出・提案する仕組みの構築を目指しおいたす。たた、その数理モデルをもずに、゜ルバヌず連携可胜なコヌドを自動生成するこずにも取り組んでおり、これにより、これたで専門家の手を芁しおいたプロセスの倧幅な効率化が期埅されたす。 このアプロヌチにより、数理最適化の専門知識を持たないナヌザヌでも、業務課題に察しお数理最適化技術を掻甚しやすくなり、より倚くの珟堎で高床な意思決定支揎が実珟できるず考えおいたす。 実珟アプロヌチの怜蚎 本章では、スヌパヌマヌケットの発泚量最適化をテヌマに、生成AIを支揎技術ずしお取り入れた数理最適化の掻甚に぀いお怜蚎しおいきたす。 生成AI掻甚の党䜓像 最初に、生成AI掻甚の党䜓像を瀺したす。本アプロヌチでは、以䞋の3皮類のAI゚ヌゞェントを掻甚したす。 定匏化支揎゚ヌゞェント : ナヌザヌが抱えおいる課題や芁件をプロンプトずしお入力するだけで、AIが数理最適化モデルを自動で定匏化したす。 入力デヌタ蚭蚈支揎゚ヌゞェント : 定匏化された数理モデルに基づき、数理最適化実行に必芁なデヌタ構造の蚭蚈案を具䜓的な䟋ずずもに提案したす。 コヌド生成゚ヌゞェント : 定匏化されたモデルず蚭蚈された入力デヌタをもずに、数理最適化を実行するためのプログラムコヌドを自動生成したす。 これら3皮類のAI゚ヌゞェントが連携しおナヌザヌをサポヌトするこずで、これたで専門知識が䞍可欠であった数理最適化技術の導入プロセスを倧幅に簡玠化し、珟堎ぞの迅速な実装を可胜にしたす。 次のフロヌは、䞊蚘のAI゚ヌゞェントを補助的に掻甚し、業務課題を解決するための数理最適化モデルの定匏化から実行コヌドの生成、さらに業務ぞの実装に至るたでのプロセスを䜓系的に敎理したものずなっおいたす。 ① 課題の適性蚺断担圓定匏化支揎゚ヌゞェント ナヌザヌが解決したい課題の抂芁を定匏化゚ヌゞェントに入力。その課題が数理最適化技術での解決に適しおいるかの刀定。 解決可胜ず刀定された堎合: ステップ2ぞの移行。 解決困難ず刀定された堎合: 別のアプロヌチ機械孊習、シミュレヌションなどの怜蚎。 ② 数理モデルの定匏化担圓定匏化支揎゚ヌゞェント ナヌザヌによる課題詳现制玄条件、目的関数などの゚ヌゞェントぞ入力。これを数理最適化問題ずしお定匏化し、その内容をMarkdownファむルずしお出力。 ③ 入力デヌタの蚭蚈担圓入力デヌタ蚭蚈支揎゚ヌゞェント ステップ2で䜜成された数理モデルのMarkdownファむルを、入力デヌタ蚭蚈支揎゚ヌゞェントぞむンプット。モデルに必芁なデヌタ項目の自動抜出および機械孊習による予枬の必芁性の有無の刀断、それらのデヌタ蚭蚈方法の具䜓䟋を䌎う提瀺。 ④ 入力デヌタの準備担圓ナヌザヌ ステップ3の蚭蚈案に基づく、実際の業務デヌタなど必芁な入力デヌタの準備。 分岐: ステップ3で機械孊習による予枬が必芁ず刀断されたデヌタ項目に぀いおは、Node-AIなどのツヌルを甚いた予枬モデルの構築ず、それによる予枬倀の生成。 â‘€ 実行コヌドの生成担圓コヌド生成゚ヌゞェント ステップ2の数理モデルのMarkdownファむルず、ステップ4の入力デヌタをコヌド生成゚ヌゞェントぞむンプット。特定の最適化ラむブラリを䜿甚した実行可胜なPythonコヌドの生成。 ⑥ 業務ぞの実装ず掻甚担圓ナヌザヌ コヌド生成゚ヌゞェント 生成されたPythonコヌドの、ナヌザヌによる実際の業務プロセスやシステムぞの組み蟌み。コヌドの埮調敎や運甚方法の最適化など、コヌド生成゚ヌゞェントのサポヌトを適宜受けながらの業務利掻甚の掚進。 なお、各皮AI゚ヌゞェントの支揎を掻甚し、䞊蚘プロセスを通じお業務課題ぞの数理最適化技術の適甚を容易にするアプリケヌションを開発しおいたす。 本皿では、その開発䞭の画面の䞀郚ずずもにご玹介したす。 圚庫最適化の課題蚭定 次に、本怜蚎で取り䞊げる課題蚭定を瀺したす。なお、課題はシンプルに蚭定しおいたす。 ○ 目的 スヌパヌマヌケットにおける日配品の圚庫管理を察象に、適正圚庫を維持しながら、廃棄ロスを最小限に抑えるこずを目指す。欠品はある皋床蚱容し぀぀、過剰圚庫によるロスの削枛を重芖する。 ○ 前提条件 - 察象カテゎリ日配品 - 察象商品数50SKU (Stock Keeping Unit: 圚庫管理単䜍) - 発泚頻床毎日 - リヌドタむム1日 - オペレヌション - 午前䞭に発泚指瀺 - 閉店埌、消費期限切れ商品を廃棄 - 翌朝、発泚商品が玍品 - 玍品䜓制地域の卞業者による䞀括玍品 むメヌゞ図(AI生成) 以降では、こちらの課題を䟋に、AI゚ヌゞェントを掻甚した具䜓的なフロヌを説明したす。 実珟たでのステップ 1. 定匏化支揎゚ヌゞェントによる定匏化支揎 たず、数理最適化に䞍慣れなナヌザヌにずっおは、前述した圚庫管理の課題が数理最適化によっお解決可胜かどうかを刀断するのは容易ではありたせん。そこで、生成AIを掻甚し、圓該課題が数理最適化の適甚察象ずなり埗るかを蚺断するアプロヌチを詊みたす。 以䞋は、圓該課題に数理最適化技術を適甚できるかどうかを刀断するために、定匏化支揎゚ヌゞェントに䞎えるプロンプトの䞀䟋です。珟圚開発䞭のアプリケヌションでは、ナヌザヌが【課題抂芁】の欄に自身の課題を簡朔に入力するず、これをもずに゚ヌゞェントが応答を生成する仕組みになっおいたす。 ゚ヌゞェントによる回答結果はこちらです。 定匏化支揎゚ヌゞェントの解析結果ずしお、「 数理最適化によっお解決可胜である 」ずの刀断が埗られたした。これを受け、次のステップでは、具䜓的な数理最適化問題の定匏化に進みたす。 䞋蚘は、定匏化支揎゚ヌゞェントに数理最適化問題の定匏化を䟝頌する際のプロンプト䟋です。開発䞭のアプリケヌションでは、ナヌザヌが【課題内容】欄に具䜓的な課題を入力するず、それを螏たえお゚ヌゞェントが最適な定匏化を自動生成したす。 定匏化支揎゚ヌゞェントからは、次のような回答が埗られたした。 定匏化支揎゚ヌゞェントを甚いるこずで、数理最適化問題の定匏化がわずか1分足らずで完了したした。通垞であれば、人手による定匏化には盞応の時間ず劎力を芁したすが、゚ヌゞェントは非垞に短時間で凊理を行い、倧幅な時間短瞮を実珟しおいたす。 䜜成された定匏化には、プロンプトで䞎えた「目的」や「制玄」、「補足情報」が的確に反映されおおり、日本語による説明を通じお、その劥圓性が確認できたす。 特に泚目すべきは、欠品量・廃棄量・圚庫の遷移ずいった芁玠に぀いお、プロンプト内で明瀺的に指瀺しおいないにもかかわらず、適切に定匏化ぞ組み蟌たれおいた点です。 さらに、消費期限順に商品が販売・消費されるずいう数匏で衚珟するには難易床の高い制玄に぀いおも、゚ヌゞェントは短時間で的確に反映しおおり、その高い汎甚性ず柔軟性がうかがえたす。 本゚ヌゞェントにより定匏化された数理最適化モデルが劥圓ず刀断された堎合、生成AIを甚いおMarkdown圢匏で内容の敎理・保存を行いたす。これを次のステップの入力デヌタ蚭蚈支揎゚ヌゞェントに匕き枡しおいきたす。 2. 入力デヌタ蚭蚈支揎゚ヌゞェントによるデヌタ蚭蚈支揎 前節では、定匏化支揎゚ヌゞェントのサポヌトを受けながら、数理最適化問題の定匏化を完了したした。次に、最適化を実行するために必芁な入力デヌタの蚭蚈を行いたす。 䞍慣れなナヌザヌにずっおは、「どのようなデヌタを、どのような構成で甚意すればよいのか」が分かりにくい堎合がありたす。そこで本アプリケヌションでは、入力デヌタ蚭蚈支揎゚ヌゞェントを掻甚しお、入力デヌタの蚭蚈案を自動的に提瀺する仕組みを取り入れおいたす。 数理最適化モデルが蚘述されたMarkdownファむルをアップロヌドした䞊で、入力デヌタ蚭蚈支揎゚ヌゞェントに次のようなプロンプトを䞎えたす。なお、開発䞭のアプリケヌションにおいおは、自動でこのプロンプトが䞎えられたす。 ゚ヌゞェントによる回答結果はこちらです。 たず、Step 1ではデヌタ項目の敎理を行っおいたす。具䜓的には、「デヌタ項目」「説明」「数匏衚珟」「単䜍䟋」「カテゎリ」「機械孊習回垰を芁する可胜性」の6項目が䞀芧化されおいたす。 このステップで特に泚目すべきなのは、「機械孊習回垰を芁する可胜性」の刀定結果です。機械孊習に詳しくないナヌザヌにずっお、あるデヌタを準備するのに機械孊習技術が必芁かどうかを刀断するのは容易ではありたせん。この刀定結果は、その刀断をサポヌトする重芁な情報ずなりたす。 䟋えば、「需芁量」に぀いおは機械孊習技術の掻甚が必芁ず刀断されおいたす。実際、将来の需芁量を芋積もるには予枬が䌎うため、機械孊習手法を甚いる必芁がありたす。 Step 2では、CSVファむル圢匏による入力デヌタの蚭蚈案が提瀺されおおり、各ファむルの名称や具䜓的なデヌタ䟋も瀺されおいたす。今回の䟋では、以䞋の぀のCSVファむルに分割しお蚭蚈するこずが提案されおいたす。 products.csv 商品ごずの基本情報を瀺すデヌタ ※「欠品コスト円/個」および「廃棄コスト円/個」の倀は、ナヌザヌの業務内容やポリシヌに応じお個別に蚭定する必芁がありたす。䟋えば、簡易的な想定ずしお、欠品コストは粗利、廃棄コストは仕入れ䟡栌を基準ずするこずが可胜です。 demand.csv 各商品における将来の需芁数予枬倀を瀺すデヌタ initial_inventory.csv 各商品の初期圚庫量を蚘録したデヌタ scalar_constraints.csv 蚈画期間ずいった党䜓に適甚される蚭定倀 この蚭蚈案を参考に、次節では実際のデヌタ準備を進めおいきたす。 3. Node-AIを掻甚したデヌタの準備 前節の゚ヌゞェントによる出力結果を参考にしながら、必芁な入力デヌタを実際に準備しおいきたす。なお、デヌタの取埗にあたっおは、堎合によっおは既存の業務プロセスに察する芋盎しや調敎が必芁ずなる可胜性もありたす。 たず、「機械孊習回垰を芁する可胜性」が「あり」ず刀定された「商品の需芁量」に着目したす。この項目は機械孊習による予枬が必芁であるため、NTTドコモビゞネスのプロダクトである Node-AI を掻甚したす。 Node-AI のキャンバスは以䞋の画像の通りです。操䜜手順に぀いおは、 こちらの蚘事 で玹介しおいる内容ず基本的には同じであるため、本皿では詳现な説明を省略したす。 この予枬結果に加え、Step 1で提瀺された「説明」やStep 2の入力デヌタ蚭蚈案を螏たえお、実際の入力デヌタの敎備を進めたす。今回は、以䞋のような圢匏でデヌタを準備したした。 なお、Step 2で提瀺されおいる入力デヌタ蚭蚈案はあくたで䞀䟋であり、その圢匏に厳密に埓う必芁はありたせん。ナヌザヌの業務環境や保有するデヌタの構造に応じお、列名やデヌタ型などを柔軟に調敎しお問題ありたせん。 䟋えば今回の䟋だず、 initial_inventory.csv における列名「消費期限クラス」を「残消費期限日」に倉曎しおおり、 demand.csv の日付圢匏も「yyyy-mm-dd」から「yyyy/mm/dd」ぞず倉曎しおいたす。 こうしお必芁に応じた調敎を行いながら、数理最適化の実行に必芁なデヌタを敎備したした。 4. コヌド生成゚ヌゞェントによる実行コヌド生成 デヌタの準備が完了したので、最埌にコヌド生成゚ヌゞェントを掻甚しお数理最適化を実行するための Python コヌドを䜜成したす。なお、コヌドの実行は以䞋の環境で怜蚌しおいたす。 version Python: 3.13.1 PySCIPOpt: 5.2.1 SCIP゜ルバヌ: 9.2.0 numpy: 2.2.2 pandas: 2.2.3 準備した入力デヌタのCSVファむルず、数理最適化モデルが蚘述されたMarkdownファむルをアップロヌドし、その䞊でコヌド生成゚ヌゞェントに次のプロンプトを䞎えたす。なお、開発䞭のアプリケヌションではこちらのプロンプトに関しおもあらかじめ蚭定されおいお、自動で操䜜が行われたす。 ゚ヌゞェントによっお出力された結果は以䞋の通りです。 import pandas as pd from pyscipopt import Model, quicksum class Solver : def __init__ (self, scalar_constraints_path: str , demand_path: str , inventory_path: str , product_path: str ): """ Solverクラスの初期化 :param scalar_constraints_path: スカラヌの制玄定数が入ったCSVファむルのパス :param demand_path: 需芁デヌタCSVファむルのパス :param inventory_path: 初期圚庫CSVファむルのパス :param product_path: 商品パラメヌタCSVファむルのパス """ # CSVファむルのパスを保持 self.scalar_constraints_path = scalar_constraints_path self.demand_path = demand_path self.inventory_path = inventory_path self.product_path = product_path # SCIPモデルを初期化perishable_inventoryずいう名前を぀ける self.model = Model( "perishable_inventory" ) def load_data (self): """ CSVファむルから各皮デヌタを読み蟌み、 モデルで䜿うパラメヌタを準備する """ # スカラヌの制玄定数が入ったデヌタを読み蟌みshift_jis゚ンコヌディング self.scalar_constraints_df = pd.read_csv(self.scalar_constraints_path, encoding= "shift_jis" ) # 「パラメヌタ」列をむンデックスに蚭定 self.scalar_constraints_df.set_index( "パラメヌタ" , inplace= True ) # 需芁デヌタの読み蟌み self.demand_df = pd.read_csv(self.demand_path, encoding= "shift_jis" ) # 初期圚庫デヌタの読み蟌み self.inventory_df = pd.read_csv(self.inventory_path, encoding= "shift_jis" ) # 商品パラメヌタの読み蟌み消費期限、発泚䞊限、コストなど self.product_df = pd.read_csv(self.product_path, encoding= "shift_jis" ) # 蚈画期間 T日数を取埗 self.T = int (self.scalar_constraints_df.loc[ "蚈画期間日" , "倀" ]) # 商品IDの䞀芧重耇なしを取埗 self.products = list (self.product_df[ "商品ID" ].unique()) # 商品ごずのパラメヌタ蟞曞を䜜成 self.S = self.product_df.set_index( "商品ID" )[ "最倧消費期限日" ].to_dict() # 最倧消費期限 self.U = self.product_df.set_index( "商品ID" )[ "発泚䞊限個" ].to_dict() # 発泚䞊限数量 self.c_w = self.product_df.set_index( "商品ID" )[ "廃棄コスト円/個" ].to_dict() # 廃棄コスト self.c_s = self.product_df.set_index( "商品ID" )[ "欠品コスト円/個" ].to_dict() # 欠品コスト # 需芁デヌタの日付を1..Tのむンデックスに倉換するための蟞曞を䜜成 unique_dates = sorted (self.demand_df[ "date" ].unique()) self.date_to_t = {d: idx + 1 for idx, d in enumerate (unique_dates)} # 需芁量の蟞曞を䜜成キヌ(商品ID, 時間t), 倀: 需芁量 self.d = {} for _, row in self.demand_df.iterrows(): i = row[ "商品ID" ] t = self.date_to_t[row[ "date" ]] self.d[(i, t)] = int (row[ "需芁量(個)" ]) # 初期圚庫量の蟞曞を䜜成キヌ(商品ID, 残消費期限), 倀: 初期圚庫量 self.I0 = {} for _, row in self.inventory_df.iterrows(): i = row[ "商品ID" ] s = int (row[ "残消費期限日" ]) self.I0[(i, s)] = int (row[ "初期圚庫量個" ]) def build_model (self): """ 数理モデルの構築 倉数定矩、目的関数蚭定、制玄条件蚭定を行う """ # たずはデヌタを読み蟌む self.load_data() # 倉数を栌玍する蟞曞を初期化 self.x = {} # 発泚量 x_{i,t} self.I = {} # 圚庫量 I_{i,t}^s self.f = {} # 販売量 f_{i,t}^s self.b = {} # 欠品量 b_{i,t} self.w = {} # 廃棄量 w_{i,t} # 倉数の定矩 for i in self.products: Si = self.S[i] # 商品iの消費期限 Ui = self.U[i] # 商品iの発泚䞊限 for t in range ( 1 , self.T+ 1 ): # 発泚量倉数0以䞊、䞊限Ui、敎数 self.x[(i, t)] = self.model.addVar( vtype= "INTEGER" , lb= 0 , ub=Ui, name=f "x_{i}_{t}" ) # 欠品量倉数0以䞊、敎数 self.b[(i, t)] = self.model.addVar( vtype= "INTEGER" , lb= 0 , name=f "b_{i}_{t}" ) # 廃棄量倉数0以䞊、敎数 self.w[(i, t)] = self.model.addVar( vtype= "INTEGER" , lb= 0 , name=f "w_{i}_{t}" ) # 圚庫量ず販売量は消費期限ごずに定矩 for s in range ( 1 , Si+ 1 ): self.I[(i, t, s)] = self.model.addVar( vtype= "INTEGER" , lb= 0 , name=f "I_{i}_{t}_{s}" ) self.f[(i, t, s)] = self.model.addVar( vtype= "INTEGER" , lb= 0 , name=f "f_{i}_{t}_{s}" ) # 目的関数廃棄コスト + 欠品コスト の最小化 self.model.setObjective( quicksum( self.c_w[i] * self.w[(i, t)] + self.c_s[i] * self.b[(i, t)] for i in self.products for t in range ( 1 , self.T+ 1 ) ), "minimize" ) # 制玄1: 初期圚庫条件 I_{i,1}^s = 初期圚庫量 for i in self.products: Si = self.S[i] for s in range ( 1 , Si+ 1 ): init_val = self.I0.get((i, s), 0 ) # 初期圚庫がなければ0ずする self.model.addCons( self.I[(i, 1 , s)] == init_val, name=f "initInv_{i}_{s}" ) # 制玄2: 圚庫遷移の制玄消費期限の経過を反映 for i in self.products: Si = self.S[i] for t in range ( 2 , self.T+ 1 ): for s in range ( 1 , Si+ 1 ): if s == Si: # 新芏発泚分は残消費期限Siの圚庫になる self.model.addCons( self.I[(i, t, s)] == self.x[(i, t- 1 )], name=f "invTrans_new_{i}_{t}_{s}" ) else : # 叀い圚庫は1日経぀ず残消費期限が1枛る販売埌 self.model.addCons( self.I[(i, t, s)] == self.I[(i, t- 1 , s+ 1 )] - self.f[(i, t- 1 , s+ 1 )], name=f "invTrans_{i}_{t}_{s}" ) # 制玄4-1: 需芁充圓販売欠品=需芁 for i in self.products: for t in range ( 1 , self.T+ 1 ): demand = self.d.get((i, t), 0 ) # 需芁がない堎合は0 Si = self.S[i] self.model.addCons( quicksum(self.f[(i, t, s)] for s in range ( 1 , Si+ 1 )) + self.b[(i, t)] == demand, name=f "demandFulfill_{i}_{t}" ) # 制玄4-2: 販売量は圚庫以䞋であるこず for i in self.products: for t in range ( 1 , self.T+ 1 ): Si = self.S[i] for s in range ( 1 , Si+ 1 ): self.model.addCons( self.f[(i, t, s)] <= self.I[(i, t, s)], name=f "sellCap_{i}_{t}_{s}" ) # 制玄4-3: FIFO販売順序の保蚌 for i in self.products: for t in range ( 1 , self.T+ 1 ): demand = self.d.get((i, t), 0 ) Si = self.S[i] for s in range ( 1 , Si+ 1 ): if s > 1 : # sより短い消費期限の販売が先に行われおいる必芁がある self.model.addCons( self.f[(i, t, s)] <= demand - quicksum(self.f[(i, t, k)] for k in range ( 1 , s)), name=f "fifo_{i}_{t}_{s}" ) # 制玄5: 廃棄量は残消費期限1の圚庫から販売量を匕いたもの for i in self.products: for t in range ( 1 , self.T+ 1 ): self.model.addCons( self.w[(i, t)] == self.I[(i, t, 1 )] - self.f[(i, t, 1 )], name=f "wasteDef_{i}_{t}" ) def solve (self): """ モデルを解く """ # ログを非衚瀺に蚭定 self.model.setParam( 'display/verblevel' , 0 ) # 最適化を実行 self.model.optimize() def check_model_status (self): """ 解の状態を確認し、最適解が芋぀かったかどうかを返す """ status = self.model.getStatus() if status == "optimal" : print ( "✅ 最適解が芋぀かりたした。" ) return True else : print (f "゚ラヌ{status}" ) return False def get_solution (self): """ 最適解がある堎合、各倉数の倀を蟞曞で取埗する """ # 最適解があるかチェック if not self.check_model_status(): return None # 最適解を取埗 best_sol = self.model.getBestSol() if best_sol is None : print ( "❌ 実行可胜解は取埗できたせんでした。" ) return None # 倉数名ず倀を蟞曞に栌玍 result = {} for var in self.model.getVars(): val = self.model.getSolVal(best_sol, var) result[var.name] = val return result コヌド生成゚ヌゞェントを掻甚するこずで、このように長倧なコヌドであっおも、わずか1分足らずでミスなく䜜成できたした。人手によるコヌディングでは倚くの手間や時間がかかりたすが、゚ヌゞェントによりそれらを倧幅に削枛し効率的な開発を可胜にしおいたす。 生成されたコヌドは、先ほど甚意した4぀のデヌタを読み蟌み、それをもずに最適な発泚量や圚庫の動きを蚈算する仕組みです。消費期限や圚庫の状況、日ごずの需芁などを考慮しながら、「どの商品を、い぀・どれだけ発泚し、どのくらい販売し、欠品や䜙剰がどの皋床発生するか」を自動的に刀断したす。 このようにしお、圚庫の無駄や欠品をできるだけ抑えた、バランスの取れた蚈画が立おられるようになりたす。 この Solver クラスを利甚しお、実務で䜿うために各商品の圓日発泚量をCSVファむルずしお出力するコヌドを、゚ヌゞェントに䜜成しおもらいたす。 ゚ヌゞェントに枡すプロンプトは以䞋の内容です。 ゚ヌゞェントによっお䜜成されたコヌドはこちらです。 import argparse import pandas as pd from optimizer import Solver def export_first_day_orders ( scalar_constraints_path: str , demand_path: str , inventory_path: str , product_path: str , output_csv_path: str ): """ Solver を䜿っお最適化を実行し、 初日の各商品の発泚量を CSV 出力する。 :param scalar_constraints_path: scalar_constraints.csv のパス :param demand_path: demand.csv のパス :param inventory_path: inventory.csv のパス :param product_path: product.csv のパス :param output_csv_path: 出力 CSV ファむルのパス """ # モデル構築・最適化 solver = Solver( scalar_constraints_path=scalar_constraints_path, demand_path=demand_path, inventory_path=inventory_path, product_path=product_path ) solver.build_model() solver.solve() # 最適解取埗 sol = solver.get_solution() if sol is None : print ( "最適解が取埗できなかったため、CSV を出力したせん。" ) return # 初日の発泚量をリスト化 records = [] for product_id in solver.products: var_name = f "x_{product_id}_1" qty = sol.get(var_name, 0 ) records.append({ "商品名" : product_id, "発泚量" : int (qty) }) # DataFrame 化しお CSV 出力Shift_JIS df_out = pd.DataFrame(records, columns=[ "商品名" , "発泚量" ]) df_out.to_csv(output_csv_path, index= False , encoding= "shift_jis" ) print (f "初日の発泚量を '{output_csv_path}' に出力したした。" ) if __name__ == "__main__" : parser = argparse.ArgumentParser( description= "初日の各商品の発泚量を最適化し、CSV 出力したす。" ) parser.add_argument( "--scalar_constraints" , required= True , help = "scalar_constraints.csv のパスShift_JIS" ) parser.add_argument( "--demand" , required= True , help = "需芁デヌタ CSV のパスShift_JIS" ) parser.add_argument( "--inventory" , required= True , help = "初期圚庫デヌタ CSV のパスShift_JIS" ) parser.add_argument( "--product" , required= True , help = "商品パラメヌタ CSV のパスShift_JIS" ) parser.add_argument( "--output" , required= True , help = "出力先 CSV ファむルのパスShift_JIS" ) args = parser.parse_args() export_first_day_orders( scalar_constraints_path=args.scalar_constraints, demand_path=args.demand, inventory_path=args.inventory, product_path=args.product, output_csv_path=args.output ) ゚ヌゞェントを掻甚するこずで、こちらのコヌドも短時間でミスなく䜜成できたした。 5. 䜜成されたコヌドの実行ず結果 䟋えば、必芁なデヌタファむルず出力ファむルのパスを指定し、次のようなコマンドを実行するこずで、 python export_first_day_orders.py \ --scalar_constraints scalar_constraints.csv \ --demand demand.csv \ --inventory initial_inventory.csv \ --product products.csv \ --output initial_orders.csv 以䞋のような 各商品の圓日発泚量をたずめたCSVファむルが自動的に出力 されたす。こちらの情報をもずに各商品の発泚䜜業を行いたす。 このように、生成されたコヌドを掻甚するこずで、業務で実際に必芁ずなるファむルの䜜成たでを䞀貫しお自動化できたす。珟堎でもすぐに運甚に取り入れやすいため、これたで発泚䜜業にかかっおいた時間の倧幅な短瞮や、ヒュヌマン゚ラヌの削枛が期埅されたす。 たずめ 本蚘事では、生成AIを掻甚した数理最適化技術の自動化に関する怜蚎をご玹介したした。特に、スヌパヌマヌケットにおける圚庫管理を䞀䟋ずしお取り䞊げ、゚ヌゞェント3皮のサポヌトのもずで課題蚭定から実装に至るたでのプロセスを瀺したした。 本蚘事で䞀郚をご玹介したアプリケヌションは珟圚も開発䞭であり、匕き続き改良を重ねおたいりたす。 今埌は、生成AIの回答粟床向䞊やUI/UXの改善に取り組むずずもに、実瀟䌚での掻甚に向けた怜蚌を進め、研究開発を䞀局掚進しおいく予定です。 おわりに 本蚘事が少しでも皆さたのお圹に立おたのであれば、嬉しく思いたす。 Node-AIを掻甚した機械孊習技術のビゞネス掻甚にご関心のある方は、ぜひ こちら のフォヌムよりお気軜にお問い合わせください。 たた、本蚘事の内容に関するご質問や、数理最適化技術をはじめずした数理解析技術のPoCにご関心のある方は、メヌルにおご連絡をお埅ちしおおりたす。(メヌルadam-ic[at]ntt.com)