Windows標準機能で出来る、FTPを用いたAIエージェントでのデプロイ体験

  • 2026-04-17
  • 2026-04-17
  • Infra
  • 24回
  • 0件

はじめに

こんにちは。GMOグローバルサイン・ホールディングスのCTO室の吉澤です。

昨今のWeb開発では、GitHub Actionsなどを用いたCI/CDが当たり前になっていますが、レガシーな環境や共用サーバーなど、「デプロイ手段がFTPしかない」というケースに遭遇することも少なくありません。Linux環境であれば .netrcファイルとアクセス権の設定で自動化することもありますが、Windows環境で標準のftp.exeでは通常、パスワードを平文でファイルに保存する必要があり、また暗号化通信(FTPSなど)にも対応しておらず、セキュリティ面に不安が残ります。

そこで今回は、AI(LLM)との対話を通じて構築した、PowerShellによる安全かつセキュアなFTP自動デプロイ環境の構築方法をご紹介します。

安全面への配慮

自動化において最も懸念されるのが「認証情報の管理」です。Linuxの .netrc は非常に便利ですが、パスワードが平文で保存されるため、ファイルが流出した際のリスクがあります。

今回採用したPowerShellの手法では、Windows標準の暗号化技術であるDPAPI(Data Protection API) を活用します。具体的には、Export-Clixmlというコマンドレットを使用し、以下の特性を持たせています。

  • ユーザー特定の暗号化: 作成したWindowsユーザーアカウント本人しか復号できません。
  • マシン特定の暗号化: ファイルを別のPCにコピーしても、他のPCでは読み取ることができません。

これにより、万が一設定ファイルが外部に漏れたとしても、第三者にパスワードを盗み見られるリスクを極限まで抑えています。

構築手順

下記を実行することで、AIエージェントからFTPサーバーへのアップロードが可能になります。

  • PowerShellスクリプトの設置
  • 認証情報の暗号化と保存
  • 接続先FTPサーバーの設定
  • Skillsの生成

PowerShellスクリプトの設置

FTPサーバーへのアップロードを行うPowerShellスクリプトをローカルの任意のディレクトリに設置します。スクリプトは下記Gitリポジトリからダウンロードできます。
FTPアップロードスクリプト

  • FTPS用のスクリプト: ftps_upload.ps1
  • FTP用のスクリプト: ftp_upload.ps1

※PowerShellのスクリプトの文字コードはShift-JISになります。

接続先FTPサーバーの設定

接続先のFTPサーバー情報を設定ファイルftp_settings.jsonに記述します。内容は下記です。ファイルはスクリプトと同じディレクトリに設置してください。

{
    "FtpServer": "ftp.example.com"
}

認証情報の暗号化と保存

まず、PowerShellを起動します。
powershell とスタートメニューから検索して起動してください。

次に、以下のコマンドを実行してFTPサーバーの認証情報を安全に保存します。
Get-Credential | Export-Clixml -Path ".\ftp_cred.xml"

コマンドを実行すると、ユーザー名とパスワードの入力ダイアログが表示されます。FTPの認証情報を入力してください。入力後、同じディレクトリに ftp_cred.xml というファイルが生成されます。ファイルにはパスワードが暗号化された状態で保存されており、セキュリティが確保されています。ファイルはスクリプトと同じディレクトリに設置してください。


私の環境だと、ダイアログが表示されない現象が見られました。その時は、Windowsに再ログインすると直りました。

Skillsの生成

Webアプリのプロジェクト内にSkillsを設置します。私はAIエージェントにSkillsを生成・設置してもらいました。その際のプロンプトは下記です。

このプロジェクトのディレクトリに置かれたファイルを、PowerShellを使ってアップロードするスキルを作って欲しいです。コマンド例は下記です。
スキルに、隠しファイルはアップロードしないよう、記述してください。

ドキュメントルートの、`index.html`をアップロードする場合:
powershell -ExecutionPolicy Bypass -File "C:\Users\<YourUsername>\Documents\FTPCoding\ftps_upload.ps1" -RemoteDir "/" -LocalFile ".\index.html"

サブディレクトリ `/assets/img` 内の `sample.jpg` をアップロードする場合:
powershell -ExecutionPolicy Bypass -File "C:\Users\<YourUsername>\Documents\FTPCoding\ftps_upload.ps1" -RemoteDir "/assets/img/" -LocalFile ".\assets\img\sample.jpg"

※参考として、私の環境で生成されたスキルをTips(後述)に記載します。

使い方

「~をアップロードして」 といった指示をAIエージェントに与えると、FTPサーバーへのアップロードが自動で行われます。コンテンツを全てアップロードしたり、更新されたファイルのみアップロードする指示も、私の環境(Github Copilot + Codex5.3)では受け付けてくれました。

注意事項

  • アップロードされてはならないファイルが無いか、十分にご注意ください。
  • FTPなので、上書きアップロードされます。
  • FTPはパスワードが平文で送信されるため、FTPSなどの安全なプロトコルをご利用ください。

Tips

DPAPIについて

特徴

DPAPIの最大の特徴は、暗号化・復号するための「鍵(キー)」をユーザーが用意する必要がないことです。代わりに、以下の2つの情報を組み合わせてWindowsが自動的に鍵を生成します。

  • 現在ログインしているWindowsユーザーのアカウント情報
  • 実行しているPC本体(システム)の情報

なぜ安全なのか?

  • ファイルが盗まれても安全
    万が一 ftp_cred.xml をUSBメモリなどで盗み出され、別のPCにコピーされたとしても、PC環境が異なるため復号(パスワードの読み取り)ができません。
    • ActiveDirectory環境下で移動ユーザープロファイルが有効な場合を除く
  • 同じPCの別のユーザーからも安全
    同じPCを使っている別のWindowsユーザー(例えば同僚や家族など)がこのXMLファイルを開こうとしても、ユーザーアカウントが異なるため復号できません。
  • スクリプト内に「鍵」を書かなくてよい
    独自の暗号化方式を使うと「暗号化を解くためのパスワード(鍵)」自体をスクリプト内に書かなければならず、それが漏洩の原因になりがちですが、DPAPIはその弱点を克服しています。

スキルの例(.github/skills/upload-web-files/SKILL.md)

---
name: upload-web-files
description: "Use when: プロジェクトのファイルをPowerShellでアップロードしたい、FTPアップロードを実行したい、ftps_upload.ps1を使ってファイル送信したい"
---

# Web Files Upload (PowerShell)

このスキルは、プロジェクトのファイルを PowerShell スクリプト経由でアップロードするときに使用します。

## 目的

- ディレクトリ内の対象ファイルを選ぶ
- `ftps_upload.ps1` を使ってアップロードする
- 失敗時に原因を特定しやすい形で実行する

## 前提

- PowerShell が利用可能
- アップロードスクリプトが存在する
    - `C:\Users\<YourUsername>\Documents\FTPCoding\ftps_upload.ps1`
- 対象ファイルが存在する

## 手順

1. 対象ファイルがあることを確認する。
2. アップロード先ディレクトリ(例: `/`)を決める。
3. 以下の形式でコマンドを実行する。

`powershell -ExecutionPolicy Bypass -File "C:\Users\<YourUsername>\Documents\FTPCoding\ftps_upload.ps1" -RemoteDir "/<dir>/" -LocalFile ".\<dir>\<filename>"`

## 実行例

`powershell -ExecutionPolicy Bypass -File "C:\Users\<YourUsername>\Documents\FTPCoding\ftps_upload.ps1" -RemoteDir "/" -LocalFile ".\index.html"`

`powershell -ExecutionPolicy Bypass -File "C:\Users\<YourUsername>\Documents\FTPCoding\ftps_upload.ps1" -RemoteDir "/assets/img/" -LocalFile ".\assets\img\sample.jpg"`

## 運用ルール

- 既定では `-RemoteDir "/"` を使う。必要時のみ変更する。
- `-LocalFile` は必ず対象ファイルのパスを指定する。
- 隠しファイルはアップロードしない。
    - 先頭が `.` のファイル(例: `.env`)を除外する。
    - Windows の Hidden 属性を持つファイルを除外する。
- ファイル名に空白がある場合は `-LocalFile` の値を必ず二重引用符で囲む。
- 実行前に対象ファイルの存在確認を行う。

## トラブルシュート

- `Cannot find path` が出る場合:
    - カレントディレクトリがプロジェクトルートか確認する。
    - 対象ファイルのパスが正しいか確認する。
- `File not found` が出る場合:
    - `ftps_upload.ps1` の配置場所を確認する。
- 認証エラーが出る場合:
    - `ftps_upload.ps1` 内の接続設定を確認する。