本記事には広告(アフィリエイトリンク)が含まれます。

IaCテンプレートをAIと共同作成する

📚 シリーズ:インフラ運用 × 生成AI 実践レシピ集
障害対応の初動をAIで加速する
構成管理ドキュメントをAIで自動生成する
監視アラートをAIでトリアージする
IaCテンプレートをAIと共同作成する(本記事)← ★今ここ

🔗 前シリーズ:生成AIを武器にするインフラエンジニアへの道(全3記事)

この記事について

この記事は生成AI(Claude)を活用して執筆し、運営者が内容を確認・編集しています。


はじめに

サーバーの構築や設定変更を手作業で行うと、手順の抜け漏れや設定ミスが起きやすくなります。担当者ごとに微妙に異なる設定が入ることもあり、再現性のない環境が生まれる原因になります。

IaC(Infrastructure as Code)は、インフラの構築・設定をコードとして管理する手法です。シェルスクリプトやAnsible Playbookでサーバー設定をコード化すれば、「誰が実行しても同じ結果」が得られます。しかし、IaCを書き始めるハードルは低くありません。Ansibleの構文、YAMLのインデントルール、冪等性の考慮など、習得すべき知識が多く、最初の1本を書き上げるまでに時間がかかります。

この記事では、AIを「ペアプログラミングの相手」として活用し、IaCテンプレートの作成を効率化する方法を扱います。ゼロからコードを書くのではなく、要件をAIに伝えてたたき台を生成させ、人間がレビュー・修正するアプローチです。

AIが得意なこと・苦手なことを整理すると以下の通りです。

AIが得意なことAIが苦手なこと
構文が正確なコードの生成環境固有のIPアドレス・ホスト名・パスワード
ベストプラクティスの適用(エラーハンドリング、セキュリティ設定)組織固有のポリシー・命名規則
既存コードの改善点の指摘バージョン依存の仕様変更(AIの学習データが古い場合)

この記事で扱う3つのステップは以下の通りです。

  1. シェルスクリプトをAIで生成する ― サーバー初期設定スクリプトのたたき台を作成する
  2. Ansible PlaybookをAIで生成する ― 手順書からPlaybookに変換する
  3. AIにコードレビューさせる ― セキュリティ・可読性の問題点を指摘させ、改善する

手作業とAI活用の比較は以下の通りです。

項目手作業AI活用
シェルスクリプト作成1〜2時間15〜30分(生成 + レビュー)
Ansible Playbook作成(手順書から変換)2〜4時間30分〜1時間(生成 + レビュー)
コードレビュー30分〜1時間(レビュアーの確保が必要)5〜10分(即座にレビュー可能)

※AI活用の時間はプロンプト送信・AI応答・人間のレビュー・修正を含む目安です。


前提条件

この記事は、以下の前提知識を持つ方を対象としています。

  • 記事①のプロンプト設計の基礎知識(4要素の理解)
  • Linuxのコマンドライン操作ができる(ユーザー作成、パッケージ管理、サービス管理等)
  • Ansible / シェルスクリプトの経験は不要(記事内で必要な範囲を説明します)

この記事で前提とする知識

この記事は記事① 障害対応の初動をAIで加速するのプロンプト設計の基礎知識を前提としています。プロンプトの4要素(役割・状況・ログ・出力形式)を確認したい場合は①を先にお読みください。

検証環境

項目内容
OSAlmaLinux 10 minimal
AIモデルClaude Sonnet 4.6(Anthropic公式Web UI)
Ansibleansible-core(dnf install ansible-core でインストール)
Bashデフォルトで利用可能

記事中のプロンプト例はすべてClaude Sonnet 4.6で動作確認しています。ChatGPTなど他のモデルでも基本的な考え方は共通ですが、XMLタグによる構造化はClaude固有の強みであるため、他モデルでは効果が異なる場合があります。

機密情報のマスキング

IaCテンプレートにはIPアドレス・パスワード・鍵情報などの機密情報が含まれます。AIに送信する前にマスキングが必要です。マスキングの方法は記事① 障害対応の初動をAIで加速するで解説しています。

Ansibleの基本用語

この記事で使用するAnsibleの用語を簡潔に説明します。

  • Playbook ― 実行する処理をYAML形式で記述したファイル。「手順書のコード版」に相当する
  • Task ― Playbook内の1つ1つの処理ステップ
  • Module ― タスクで使用する機能部品(例:ansible.builtin.dnf はパッケージのインストール/削除を行うモジュール)
  • Handler ― 特定のタスクで変更が発生したときだけ実行される処理(例:設定ファイル変更時にサービスを再起動)
  • 冪等性(べきとうせい) ― 同じPlaybookを何度実行しても結果が同じになる性質。Ansibleの最も重要な特徴

シェルスクリプトをAIで生成する

Before/After: スクリプト作成方法の比較

Before(手作業でゼロから作成)

サーバー初期設定スクリプトを一から書く場合、以下の問題が起きやすくなります。

  • 構文ミス(引用符の閉じ忘れ、変数展開の誤り)で実行時エラーが発生する
  • エラーハンドリングを入れ忘れ、途中で失敗しても後続処理が実行される
  • セキュリティ設定(SSH強化、不要サービスの停止)が漏れる
  • 担当者によって書き方が異なり、チーム内で統一されない

改善ポイント: 要件をプロンプトで構造化してAIに渡し、エラーハンドリング・セキュリティ設定を含むたたき台を生成させます。

After(AIでたたき台を生成 → 人間がレビュー)

要件をAIに構造化して渡し、たたき台を生成させます。

  • エラーハンドリング・セキュリティ設定をプロンプトで指示するため、漏れが減る
  • AIが生成するスクリプトにはコメントが付き、各処理の目的が明確になる
  • 生成後に人間がレビューし、環境固有の値やポリシーに合わない部分を修正する

プロンプト設計

シェルスクリプト生成用のプロンプトです。記事①の4要素(役割・状況・ログ・出力形式)をベースにしています。IaCの生成では「ログ」の代わりに「要件」を渡します。

<role>
あなたはLinuxサーバーのシェルスクリプト作成を支援するアシスタントです。
本番環境で使用するスクリプトを作成するため、エラーハンドリングと
セキュリティのベストプラクティスに従ってください。
</role>

<requirements>
以下の要件に基づいて、サーバー初期設定用のBashスクリプトを作成してください。

【対象OS】AlmaLinux 10
【実行ユーザー】root(初回セットアップ時のみ)

【実施内容】
1. 運用ユーザー「operator」の作成(sudo権限付与)
2. SSH設定の強化
   - パスワード認証の無効化
   - rootログインの無効化
3. firewalld設定
   - SSHのみ許可(デフォルトゾーン: public)
4. タイムゾーン設定(Asia/Tokyo)

【制約】
- スクリプト冒頭に set -euo pipefail を記述すること
- 各処理の前にコメントで「何をしているか」と「なぜそうするか」を記載すること
- 環境固有の値(ユーザー名等)は変数として冒頭で定義すること
- パスワードはスクリプト内にハードコーディングしないこと
</requirements>

<output_format>
以下の形式で出力してください:
1. 実行可能なBashスクリプト(shebang付き)
2. スクリプトの実行方法
3. 実行後の確認コマンド(各設定が正しく反映されたかの検証用)

推測で設定値を決めないでください。
要件に記載のない設定項目は含めないでください。
不明な点は「確認が必要な項目」として列挙してください。
</output_format>

【実演】サーバー初期設定スクリプトの生成

上記のプロンプトをAIに送信すると、以下のようなスクリプトが生成されます。

AIの期待出力例:

1. サーバー初期設定スクリプト

#!/bin/bash
#
# サーバー初期設定スクリプト
# 対象OS: AlmaLinux 10
# 用途: 新規サーバーの初期セットアップ
#

set -euo pipefail

# ==============================================================================
# 変数定義
# 環境固有の値をここで一元管理する
# ==============================================================================
OPERATOR_USER="operator"
SSH_CONFIG="/etc/ssh/sshd_config"
TIMEZONE="Asia/Tokyo"

# ==============================================================================
# 1. 運用ユーザーの作成
# 理由: rootで日常運用を行うとオペミスの影響範囲が大きいため、
#       一般ユーザーにsudo権限を付与して運用する
# ==============================================================================
echo ">>> 運用ユーザー '${OPERATOR_USER}' を作成します"

if id "${OPERATOR_USER}" &>/dev/null; then
    echo "ユーザー '${OPERATOR_USER}' は既に存在します。スキップします。"
else
    useradd -m -s /bin/bash "${OPERATOR_USER}"
    echo "ユーザー '${OPERATOR_USER}' を作成しました。"
fi

# sudo権限の付与
# 理由: 管理作業にはroot権限が必要だが、常時rootで作業するリスクを避ける
echo ">>> sudo権限を付与します"
usermod -aG wheel "${OPERATOR_USER}"
echo "ユーザー '${OPERATOR_USER}' をwheelグループに追加しました。"

# パスワードの設定を促す(ハードコーディングしない)
echo ">>> 運用ユーザーのパスワードを設定してください"
passwd "${OPERATOR_USER}"

# ==============================================================================
# 2. SSH設定の強化
# 理由: パスワード認証とrootログインを無効化し、不正アクセスのリスクを低減する
# ==============================================================================
echo ">>> SSH設定を強化します"

# 設定変更前にバックアップを取得
cp "${SSH_CONFIG}" "${SSH_CONFIG}.bak.$(date +%Y%m%d%H%M%S)"

# パスワード認証の無効化
sed -i 's/^#*PasswordAuthentication.*/PasswordAuthentication no/' "${SSH_CONFIG}"

# rootログインの無効化
sed -i 's/^#*PermitRootLogin.*/PermitRootLogin no/' "${SSH_CONFIG}"

# 設定の反映
systemctl restart sshd
echo "SSH設定を変更し、sshdを再起動しました。"

# ==============================================================================
# 3. firewalld設定
# 理由: 不要なポートを閉じ、SSHのみ許可することで攻撃対象面を最小化する
# ==============================================================================
echo ">>> firewalldを設定します"

systemctl enable --now firewalld
firewall-cmd --set-default-zone=public
firewall-cmd --permanent --zone=public --add-service=ssh
firewall-cmd --reload
echo "firewalld設定が完了しました。"

# ==============================================================================
# 4. タイムゾーン設定
# 理由: ログのタイムスタンプを日本時間で統一し、障害調査時の時刻照合を容易にする
# ==============================================================================
echo ">>> タイムゾーンを ${TIMEZONE} に設定します"
timedatectl set-timezone "${TIMEZONE}"
echo "タイムゾーンを ${TIMEZONE} に設定しました。"

# ==============================================================================
# 完了メッセージ
# ==============================================================================
echo ""
echo "=============================="
echo " 初期設定が完了しました"
echo "=============================="
echo ""
echo "【確認事項】"
echo "1. 運用ユーザー '${OPERATOR_USER}' でSSH公開鍵認証の設定を行ってください"
echo "2. 公開鍵認証でログインできることを確認してから、このセッションを終了してください"
echo "3. rootでのSSHログインが無効化されているため、ロックアウトに注意してください"

2. 実行方法

chmod +x server_init.sh
sudo ./server_init.sh

3. 実行後の確認コマンド

# ユーザーが作成されたか
id operator

# sudo権限があるか
groups operator

# SSH設定が反映されているか
grep -E "^PasswordAuthentication|^PermitRootLogin" /etc/ssh/sshd_config

# firewalldの状態
firewall-cmd --list-all

# タイムゾーンの確認
timedatectl

人間がレビューすべきポイント

AIが生成したスクリプトを受け取ったら、以下の4点を確認してください。

#確認項目確認の理由
1環境固有の値(ユーザー名、ポート番号等)が自組織のルールに合っているかAIはプロンプトの要件通りに生成するが、組織の命名規則までは把握していない
2SSH設定変更後にロックアウトされないかパスワード認証を無効化する前に、公開鍵認証の設定が完了している必要がある
3set -euo pipefail が先頭にあるかエラー発生時にスクリプトが停止することを保証する
4冪等性があるか(2回実行しても問題ないか)ユーザー作成の重複チェックなど、再実行時にエラーにならないか確認する

AI生成スクリプトを本番環境で直接実行しない

AIが生成したスクリプトは、必ずテスト環境(検証用VM等)で動作確認してから本番に適用してください。とくにSSH設定の変更は、設定ミスでサーバーにログインできなくなるリスクがあります。テスト環境で公開鍵認証 → パスワード認証無効化の手順を検証してください。


Ansible PlaybookをAIで生成する

Ansibleの基本構造

Ansible Playbookは、サーバーに対する操作をYAML形式で記述したファイルです。基本的な階層構造は以下の通りです。

  • Playbook ― 1つ以上のPlayを含むYAMLファイル
  • Play ― 「どのホストに」「何をするか」を定義する単位
  • Task ― 1つ1つの処理ステップ(Moduleを呼び出す)
  • Handler ― タスクで変更が発生したときだけ実行される処理

Ansibleの最大の特徴は冪等性です。同じPlaybookを何度実行しても、結果が同じになります。例えば「nginxをインストールする」というタスクは、既にインストール済みであればスキップされます。シェルスクリプトでは if 文で存在チェックを書く必要がありますが、Ansibleのモジュールはこの判断を自動で行います。

Before/After: Playbook作成方法の比較

Before(手順書を見ながら手動でPlaybook化)

記事②で作成した作業手順書を見ながら、Ansible Playbookを手作業で書く場合:

  • YAMLのインデントミスで構文エラーが頻発する(スペース2つ vs 4つの混在等)
  • 適切なモジュールの選択に公式ドキュメントの参照が必要(所要時間: 2〜4時間)
  • 冪等性を壊すタスクを書いてしまう(ansible.builtin.shell の安易な使用等)

After(手順書をAIに渡してPlaybookに変換)

記事②で生成した手順書をそのままAIに渡し、Playbookに変換させます。

  • AIが適切なモジュールを選択し、YAMLの構文も正しく生成する
  • 手順書の各ステップがPlaybookのどのタスクに対応するかが明確になる
  • 人間はモジュール名が最新か、冪等性が担保されているかのレビューに集中できる(所要時間: 30分〜1時間)

記事②の手順書との連携

記事②で「構成管理ドキュメントをAIで自動生成する」方法を扱いました。②で生成した作業手順書は、この記事のPlaybook変換の入力としてそのまま使えます。手順書 → Playbookへの変換は、IaC化の最も実践的なアプローチの一つです。

プロンプト設計(手順書 → Playbook変換)

以下は、手順書をAnsible Playbookに変換するためのプロンプトです。

<role>
あなたはAnsible Playbookの作成を支援するアシスタントです。
以下の手順書をAnsible Playbookに変換してください。
</role>

<requirements>
【対象OS】AlmaLinux 10
【Ansible バージョン】ansible-core 2.17以降
【モジュール】ansible.builtin.* および ansible.posix.* のFQCN形式
(Fully Qualified Collection Name: コレクション名を含む完全修飾モジュール名)を使用すること

【変換ルール】
1. 各手順をAnsibleの適切なモジュールにマッピングすること
2. ansible.builtin.shell / ansible.builtin.command は、
   専用モジュールが存在しない場合のみ使用すること
3. 変数化すべき値(パッケージ名、設定値等)は vars セクションで定義すること
4. 設定ファイルの変更時はハンドラーでサービスを再起動すること
5. 各タスクに name を付け、処理内容がわかるようにすること
</requirements>

<procedure>
(ここに手順書を貼り付け)
</procedure>

<output_format>
以下の形式で出力してください:
1. Ansible Playbook(YAML形式、コメント付き)
2. 必要な前提条件(ansible-galaxy collection install 等)
3. 実行方法(ansible-playbook コマンド)
4. 各タスクの解説(手順書のどのステップに対応するか)

推測で設定値を決めないでください。
手順書に記載のないステップは含めないでください。
不明な点は「確認が必要な項目」として列挙してください。
</output_format>

【実演】nginx設定Playbookの生成

以下の手順書をAIに渡して、Playbookに変換します。

入力する手順書(抜粋):

<procedure>
作業手順書: nginx Webサーバーのセットアップ

1. nginxパッケージをインストールする
   コマンド: dnf install -y nginx

2. nginx設定ファイルを配布する
   - /etc/nginx/nginx.conf を所定の設定に書き換える
   - worker_processes: auto
   - server_tokens: off(バージョン情報の非表示)

3. nginxサービスを起動し、自動起動を有効にする
   コマンド: systemctl enable --now nginx

4. firewalldでHTTP/HTTPSを許可する
   コマンド: firewall-cmd --permanent --add-service=http
   コマンド: firewall-cmd --permanent --add-service=https
   コマンド: firewall-cmd --reload

5. 動作確認
   コマンド: curl -I http://localhost
   期待結果: HTTP/1.1 200 OK
</procedure>

AIの期待出力例:

1. Ansible Playbook

---
# nginx Webサーバーセットアップ Playbook
# 対象OS: AlmaLinux 10
# 用途: nginxのインストール・設定・起動

- name: nginx Webサーバーのセットアップ
  hosts: webservers
  become: true

  vars:
    # 変数定義: 環境に応じて変更する値をここで管理
    nginx_worker_processes: "auto"
    nginx_server_tokens: "off"
    nginx_service_name: "nginx"

  handlers:
    # 設定ファイル変更時にnginxを再起動するハンドラー
    - name: Restart nginx
      ansible.builtin.systemd_service:
        name: "{{ nginx_service_name }}"
        state: restarted

  tasks:
    # ------------------------------------------------------------------
    # 手順1: nginxパッケージのインストール
    # ------------------------------------------------------------------
    - name: nginxパッケージをインストールする
      ansible.builtin.dnf:
        name: nginx
        state: present

    # ------------------------------------------------------------------
    # 手順2: nginx設定ファイルの配布
    # server_tokensをoffにし、バージョン情報を非表示にする
    # ------------------------------------------------------------------
    - name: nginx設定ファイルを配布する
      ansible.builtin.copy:
        dest: /etc/nginx/nginx.conf
        content: |
          user nginx;
          worker_processes {{ nginx_worker_processes }};
          error_log /var/log/nginx/error.log;
          pid /run/nginx.pid;

          events {
              worker_connections 1024;
          }

          http {
              include       /etc/nginx/mime.types;
              default_type  application/octet-stream;

              log_format main '$remote_addr - $remote_user [$time_local] '
                              '"$request" $status $body_bytes_sent '
                              '"$http_referer" "$http_user_agent"';

              access_log /var/log/nginx/access.log main;

              sendfile        on;
              keepalive_timeout 65;

              server_tokens {{ nginx_server_tokens }};

              include /etc/nginx/conf.d/*.conf;
          }
        owner: root
        group: root
        mode: '0644'
        backup: yes
      notify: Restart nginx

    # ------------------------------------------------------------------
    # 手順3: nginxサービスの起動と自動起動の有効化
    # ------------------------------------------------------------------
    - name: nginxサービスを起動し自動起動を有効にする
      ansible.builtin.systemd_service:
        name: "{{ nginx_service_name }}"
        state: started
        enabled: true

    # ------------------------------------------------------------------
    # 手順4: firewalldでHTTP/HTTPSを許可する
    # ------------------------------------------------------------------
    - name: firewalldでHTTPサービスを許可する
      ansible.posix.firewalld:
        service: http
        permanent: true
        immediate: true
        state: enabled

    - name: firewalldでHTTPSサービスを許可する
      ansible.posix.firewalld:
        service: https
        permanent: true
        immediate: true
        state: enabled

2. 前提条件

# ansible.posix コレクションのインストール
ansible-galaxy collection install ansible.posix

3. 実行方法

# 構文チェック
ansible-playbook nginx_setup.yml --syntax-check

# ドライラン(実際には変更を加えない)
ansible-playbook nginx_setup.yml --check --diff

# 実行
ansible-playbook nginx_setup.yml -i inventory.ini

4. 各タスクの解説

手順書のステップPlaybookのタスク使用モジュール
1. nginxインストールnginxパッケージをインストールするansible.builtin.dnf
2. 設定ファイル配布nginx設定ファイルを配布するansible.builtin.copy
3. サービス起動nginxサービスを起動し自動起動を有効にするansible.builtin.systemd_service
4. firewalld設定HTTP/HTTPSサービスを許可するansible.posix.firewalld
5. 動作確認Playbookには含めない(手動で実施)

人間がレビューすべきポイント

#確認項目確認の理由
1モジュール名がFQCN形式(ansible.builtin.dnf 等)になっているか短縮形(dnf)は将来非推奨になる可能性がある
2YAMLのインデントが正しいかスペース2つの統一が崩れると構文エラーになる
3冪等性が担保されているかansible.builtin.shell / ansible.builtin.command を使っている箇所は冪等性が壊れる可能性がある
4設定ファイルの内容が自環境に合っているかAIが生成したnginx.confは汎用的な設定のため、自環境の要件と照合する
5ハンドラーが正しく定義されているかnotify の名前と handlers の名前が一致しないと動作しない

AIが間違いやすいポイント

#間違いの種類具体例対処方法
1インデント崩れタスクのインデントが2スペースと4スペースで混在するansible-playbook --syntax-check で検出
2廃止モジュールの使用yum モジュールを使用(AlmaLinux 10では ansible.builtin.dnf が正しい)公式ドキュメントでモジュール名を確認
3冪等性の欠如ansible.builtin.shell: firewall-cmd --add-service=http と記述(専用モジュール ansible.posix.firewalld を使うべき)shell / command を使っている箇所を専用モジュールに置き換え
4ファイルパスの環境依存CentOS 7のパスを出力する(例:/etc/sysconfig/ 配下の設定ファイル)AlmaLinux 10でのパスを確認
5ハンドラー名の不一致notify: restart nginxname: Restart Nginx で大文字小文字が異なるnotifyhandlers の名前を完全一致させる

AIが生成するPlaybookは「たたき台」

AIが生成したPlaybookは、ansible-lint で構文チェックを行い、--check --diff モードで安全に確認してください。本番環境への直接適用は避けてください。

# ansible-lintのインストール
pip install ansible-lint

# 構文チェック
ansible-lint nginx_setup.yml

# ドライラン
ansible-playbook nginx_setup.yml --check --diff

AIにコードレビューさせる

AIをコードレビュアーとして活用する

自分が書いたスクリプトやPlaybookを、他のエンジニアにレビューしてもらう前にAIでチェックできます。AIはセキュリティ・可読性・保守性の観点で機械的にチェックするのが得意です。人間のレビュアーの時間を使う前に、AIで基本的な問題を洗い出しておくと効率的です。

プロンプト設計(コードレビュー用)

<role>
あなたはLinuxインフラのコードレビュアーです。
以下のスクリプトをレビューし、問題点と改善案を提示してください。
</role>

<review_criteria>
以下の観点でレビューしてください:
1. セキュリティ(認証情報のハードコーディング、不要な権限等)
2. エラーハンドリング(異常時の動作、ロールバック)
3. 可読性(コメント、変数名、構造化)
4. 保守性(変数化、再利用性、設定値の外部化)
5. 冪等性(再実行時に問題が発生しないか)
</review_criteria>

<code>
(ここにレビュー対象のコードを貼り付け)
</code>

<output_format>
以下の形式で出力してください:

問題点ごとに:
- 重大度: 高 / 中 / 低
- 該当箇所: 問題のあるコード行
- 問題の内容: 何が問題か
- 修正案: どう修正すべきか(修正後のコードを含む)

最後に、修正をすべて反映した改善後のスクリプト全文を出力してください。

推測で環境情報を補完しないでください。
コードに記載のない要件は追加しないでください。
不明な点は「不明」と回答してください。
</output_format>

【実演】問題を含むシェルスクリプトのレビュー

以下は、意図的に問題を含むサーバー初期設定スクリプトです。このスクリプトをAIにレビューさせます。

レビュー対象スクリプト(問題あり):

#!/bin/bash

# サーバー初期設定スクリプト

# ユーザー作成
useradd operator
echo "P@ssw0rd123" | passwd --stdin operator
usermod -aG wheel operator

# SSH設定
sed -i 's/PasswordAuthentication yes/PasswordAuthentication no/' /etc/ssh/sshd_config
sed -i 's/#PermitRootLogin yes/PermitRootLogin no/' /etc/ssh/sshd_config
systemctl restart sshd

# firewalld
firewall-cmd --permanent --add-service=ssh
firewall-cmd --reload

# パッケージインストール
dnf install -y $PACKAGES

# 設定ファイルのコピー
cp /tmp/app.conf /etc/myapp/app.conf
chown root:root /etc/myapp/app.conf

# タイムゾーン
timedatectl set-timezone Asia/Tokyo

echo "完了"

AIの期待出力例:

問題1

  • 重大度:
  • 該当箇所: echo "P@ssw0rd123" | passwd --stdin operator
  • 問題の内容: パスワードがスクリプト内にハードコーディングされている。スクリプトがGit管理されている場合、パスワードが履歴に残る。また ps コマンドでプロセス一覧を見ると、パスワードが表示される
  • 修正案: スクリプト実行時に対話的にパスワードを入力させるか、SSH公開鍵認証のみ使用する構成にする

問題2

  • 重大度:
  • 該当箇所: スクリプト全体
  • 問題の内容: set -euo pipefail がない。コマンドが失敗しても後続の処理が実行されるため、途中で失敗した場合に中途半端な状態になる
  • 修正案: スクリプト冒頭に set -euo pipefail を追加する

問題3

  • 重大度:
  • 該当箇所: dnf install -y $PACKAGES
  • 問題の内容: 変数 $PACKAGES がクォートされていない。変数が未定義の場合、set -u があればエラーになるが、set -u がないため空文字列として展開される。また、変数にスペースが含まれる場合、意図しないワード分割が発生する
  • 修正案: 変数の定義をスクリプト冒頭で行い、複数パッケージを渡す場合は配列を使用する

問題4

  • 重大度:
  • 該当箇所: useradd operator
  • 問題の内容: ユーザーが既に存在する場合、エラーが発生する。冪等性がない
  • 修正案: id コマンドで存在チェックを行い、存在しない場合のみ作成する

問題5

  • 重大度:
  • 該当箇所: cp /tmp/app.conf /etc/myapp/app.conf
  • 問題の内容: /etc/myapp/ ディレクトリが存在しない場合、コピーが失敗する。また /tmp/app.conf が存在しない場合もエラーになる
  • 修正案: ディレクトリの存在確認とファイルの存在確認を追加する

問題6

  • 重大度:
  • 該当箇所: スクリプト全体
  • 問題の内容: rootで直接実行する前提になっている(sudoなし)。実行ユーザーの確認がない
  • 修正案: スクリプト冒頭でroot権限の確認を追加する

改善後のスクリプト

AIのレビュー結果を反映した改善後のスクリプトは以下の通りです。

#!/bin/bash
#
# サーバー初期設定スクリプト(改善版)
# 対象OS: AlmaLinux 10
#

set -euo pipefail

# ==============================================================================
# 変数定義
# ==============================================================================
OPERATOR_USER="operator"
SSH_CONFIG="/etc/ssh/sshd_config"
TIMEZONE="Asia/Tokyo"
PACKAGES=(vim wget curl)
APP_CONFIG_SRC="/tmp/app.conf"
APP_CONFIG_DST="/etc/myapp/app.conf"

# ==============================================================================
# root権限の確認
# ==============================================================================
if [[ "$(id -u)" -ne 0 ]]; then
    echo "エラー: このスクリプトはroot権限で実行してください" >&2
    exit 1
fi

# ==============================================================================
# 1. 運用ユーザーの作成
# ==============================================================================
echo ">>> 運用ユーザー '${OPERATOR_USER}' を作成します"

if id "${OPERATOR_USER}" &>/dev/null; then
    echo "ユーザー '${OPERATOR_USER}' は既に存在します。スキップします。"
else
    useradd -m -s /bin/bash "${OPERATOR_USER}"
    echo "ユーザー '${OPERATOR_USER}' を作成しました。"
fi

usermod -aG wheel "${OPERATOR_USER}"

# パスワードは対話的に設定(ハードコーディングしない)
echo ">>> 運用ユーザーのパスワードを設定してください"
passwd "${OPERATOR_USER}"

# ==============================================================================
# 2. SSH設定の強化
# ==============================================================================
echo ">>> SSH設定を強化します"

cp "${SSH_CONFIG}" "${SSH_CONFIG}.bak.$(date +%Y%m%d%H%M%S)"

sed -i 's/^#*PasswordAuthentication.*/PasswordAuthentication no/' "${SSH_CONFIG}"
sed -i 's/^#*PermitRootLogin.*/PermitRootLogin no/' "${SSH_CONFIG}"

systemctl restart sshd
echo "SSH設定を変更し、sshdを再起動しました。"

# ==============================================================================
# 3. firewalld設定
# ==============================================================================
echo ">>> firewalldを設定します"

systemctl enable --now firewalld
firewall-cmd --permanent --add-service=ssh
firewall-cmd --reload
echo "firewalld設定が完了しました。"

# ==============================================================================
# 4. パッケージインストール
# ==============================================================================
echo ">>> パッケージをインストールします: ${PACKAGES[*]}"
dnf install -y "${PACKAGES[@]}"

# ==============================================================================
# 5. 設定ファイルのコピー
# ==============================================================================
echo ">>> 設定ファイルを配布します"

if [[ ! -f "${APP_CONFIG_SRC}" ]]; then
    echo "警告: ${APP_CONFIG_SRC} が存在しません。スキップします。" >&2
else
    mkdir -p "$(dirname "${APP_CONFIG_DST}")"
    cp "${APP_CONFIG_SRC}" "${APP_CONFIG_DST}"
    chown root:root "${APP_CONFIG_DST}"
    chmod 644 "${APP_CONFIG_DST}"
    echo "設定ファイルを配布しました。"
fi

# ==============================================================================
# 6. タイムゾーン設定
# ==============================================================================
echo ">>> タイムゾーンを ${TIMEZONE} に設定します"
timedatectl set-timezone "${TIMEZONE}"

# ==============================================================================
# 完了
# ==============================================================================
echo ""
echo "=============================="
echo " 初期設定が完了しました"
echo "=============================="

AIレビューと人間レビューの使い分け

AIによるコードレビューと人間によるコードレビューは、得意な領域が異なります。両方を組み合わせると効果的です。

観点AIが得意人間が得意
構文チェック構文エラー・タイプミスの検出
セキュリティハードコーディング・権限設定の問題組織のセキュリティポリシーとの整合性
ベストプラクティス一般的なベストプラクティスの適用チーム固有のコーディング規約
業務ロジック業務要件との整合性、運用上の懸念
保守性コードの重複・変数化の提案将来の拡張計画を踏まえた設計判断

推奨フロー: AIレビュー → 指摘を反映 → 人間レビュー → 最終修正


生成 → レビュー → 改善のワークフロー

IaCテンプレート作成の全体フロー

IaCテンプレートをAIと共同で作成する際の全体的な流れは以下の通りです。

ステップ作業内容担当
1要件定義(何をコード化するかを明確にする)人間
2AIにたたき台を生成させる(プロンプトで要件を構造化して伝える)AI
3人間がレビュー(環境固有の値・セキュリティ設定・冪等性を確認)人間
4AIにコードレビューを依頼(セキュリティ・可読性・保守性を確認)AI
5指摘を反映して修正人間
6テスト環境で実行・検証(--check --diff / ShellCheck)人間
7本番環境に適用人間

ステップ2と4でAIを活用し、ステップ1・3・5・6・7は人間が担います。AIが関与するのは「たたき台の生成」と「レビュー」の2箇所であり、要件定義・最終判断・本番適用は人間の責任です。

シリーズ全体の振り返り

このシリーズでは、4つの記事を通じてインフラ運用の主要タスクにAIを組み込む方法を扱いました。

記事テーマAIの役割人間の役割
障害対応の初動(ログ解析)ログの分類・原因候補の提示最終的な原因の特定・対処の実行
構成管理ドキュメント生成手順書・構成図のたたき台作成内容の正確性確認・組織ルールへの適合
監視アラートのトリアージ重要度分類・初期対処方針の提案最終的な優先度判断・対応実行
IaCテンプレート作成(本記事)スクリプト/Playbookのたたき台生成・コードレビュー環境固有の設定・テスト・本番適用

4つの記事に共通する原則は以下の通りです。

AIは「下書き・分類・提案」を担い、「最終判断と責任」は人間が担う。

AIの出力はすべて「提案」であり、採用するかどうかを判断するのは人間です。この原則はインフラ運用に限らず、AIを業務に組み込む際の基本的な考え方です。


注意点とベストプラクティス

AI生成コードの検証は必須

生成されたスクリプト・Playbookは、必ずテスト環境で動作確認してから本番に適用してください。

ツール用途コマンド例
ShellCheckシェルスクリプトの静的解析shellcheck server_init.sh
ansible-lintPlaybookの静的解析ansible-lint nginx_setup.yml
–check –diffPlaybookのドライランansible-playbook nginx_setup.yml --check --diff
–syntax-checkPlaybookの構文チェックansible-playbook nginx_setup.yml --syntax-check
# ShellCheckのインストール(AlmaLinux 10、EPELリポジトリが必要)
dnf install -y epel-release
dnf install -y shellcheck

# ansible-lintのインストール
pip install ansible-lint

バージョン依存の問題

Ansibleのモジュールは頻繁に変更・廃止されます。AIが古いバージョンの構文を出力する場合があるため、公式ドキュメントで確認してください。

旧モジュール新モジュール(FQCN形式)備考
yumansible.builtin.dnfAlmaLinux 10では dnf を使用
serviceansible.builtin.systemd_servicesystemd環境では systemd_service を推奨
firewalldansible.posix.firewalldansible.posix コレクションが必要

ベストプラクティス

#項目内容
1Git管理するAI生成コードもGitで管理し、変更履歴を追跡する
2レビュー済みのタグを付けるAI生成 → 人間レビュー済みの状態を明確にする(コミットメッセージ、コメント等)
3プロンプトもGit管理する生成に使用したプロンプトをコードと同じリポジトリで管理し、再現性を確保する
4チーム内でルールを定めるAI活用のルール(レビュー基準、プロンプトテンプレートの共有場所)を決める
5要件定義を丁寧に行うAIの出力品質は入力(要件の明確さ)に比例する。曖昧な要件は曖昧なコードを生む

AI生成コードは「参考コード」

AI生成コードの実行結果に対する責任は実行者にあります。AIの提案を鵜呑みにせず、必ずテスト環境で検証してから本番環境に適用してください。とくに以下の点に注意が必要です。

  • SSH設定の変更(ロックアウトのリスク)
  • firewalldの設定(通信遮断のリスク)
  • ユーザー権限の変更(セキュリティ上のリスク)

まとめ

この記事で扱った3つのステップを整理します。

ステップ内容入力AI活用のポイント
ステップ1シェルスクリプトの生成要件(実施内容・制約)エラーハンドリング・セキュリティ設定を含むたたき台の生成
ステップ2Ansible Playbookの生成手順書(記事②で作成したもの等)手順書 → Playbook変換、適切なモジュール選択
ステップ3AIによるコードレビュー既存のスクリプト / Playbookセキュリティ・可読性・冪等性の問題点の指摘と修正案

IaC作成にAIを組み込む際の原則は以下の2点です。

  1. AIは「たたき台の生成」と「レビュー」が得意で、「環境固有の判断」は人間が担います。 要件定義・テスト環境での検証・本番適用の判断は人間の責任です。
  2. 要件定義を丁寧に行うほど、AIの出力品質が上がります。 プロンプトに具体的な要件(対象OS、制約、出力形式)を記述することで、修正の手戻りが減ります。

シリーズ総括

このシリーズ「インフラ運用 × 生成AI 実践レシピ集」では、4つの記事でインフラ運用の主要タスクにAIを組み込む方法を扱いました。

4つの記事を通じて共通するパターンは以下の通りです。

  • プロンプトの4要素(役割・状況/要件・入力データ・出力形式)で構造化する
  • XMLタグでプロンプトを区切り、AIが入力を正確に解釈できるようにする
  • 「推測しない」「不明は不明と回答」 の制約を含め、AIの誤った推測を防ぐ
  • Few-shotで過去のパターンを蓄積し、提案の精度を継続的に上げる

次にやること

  1. シェルスクリプト生成用のプロンプトテンプレートを使い、自チームのサーバー初期設定スクリプトのたたき台を生成する。 環境固有の値を変数に置き換え、チームのルールに合わせて修正する
  2. 既存の手順書を1つ選び、Playbook変換用のプロンプトテンプレートでAnsible Playbookに変換する。 ansible-lint--check --diff で検証し、チーム内でレビューする
  3. 自分が過去に書いたスクリプトを1つ選び、コードレビュー用のプロンプトテンプレートでAIにレビューさせる。 AIの指摘と自分の判断を照合し、コーディング規約に反映する
  4. 生成に使ったプロンプトテンプレートをチームの共有場所(Wiki・リポジトリ等)に保管する。 テンプレートを共有し、チーム全体でAI活用のナレッジを蓄積する

前の記事: ③ 監視アラートをAIでトリアージする
前シリーズ: 生成AIを武器にするインフラエンジニアへの道(全3回)