【実践シェルスクリプト講座 第3回】面倒な「ユーザー作成」を全自動化!CSV読み込みとSSH鍵配布の極意

【実践シェルスクリプト講座 第3回】「えっ、手動で50人分登録するの!?」面倒なユーザー作成を全自動化しよう

こんにちは!「リナックス先生」です。
前回は、サーバーを守るための「バックアップ」と「通知」の仕組みを構築しました。
これで守りは完璧…と言いたいところですが、コウ君、なんだかお疲れ気味じゃない?

コウ君

先生…実は、来週から新しいプロジェクトが始まるらしくて、開発メンバー20人分のユーザーアカウントを作成することになったんです。
しかも、「セキュリティのため全員SSH鍵認証にして、秘密鍵を個別に配布してくれ」って言われて…。
ユーザー作って、パスワード設定して、鍵を作って、権限変えて…これを20回繰り返すなんて、指が取れちゃいますよ!(泣)

リナックス先生

それは大変ね。でも、エンジニアにとって「単純な繰り返し作業」は最大の敵であり、同時に自動化のチャンスでもあるの。
エクセル(CSV)で作った名簿さえあれば、その作業、スクリプト一つで1秒で終わらせられるわよ。
今回は、シェルスクリプトの真骨頂である「ループ処理」「テキスト読み込み」をマスターしましょう!

「実践シェルスクリプト講座」第3回のテーマは、インフラエンジニアの業務効率を劇的に改善する「ユーザー管理の自動化」です。
while ループを使ってCSVファイルを一行ずつ読み込み、ユーザー作成からSSH鍵の生成・配置までを一気に処理するプロ仕様のスクリプトを作成します。

本講座のカリキュラム(全4回)

本シリーズでは、現場で即使えるレベルの実践的なスクリプトを作成します。

  1. サーバーの異変を未然に防ぐ!「ディスク容量監視」と「ログローテーション」【完了】
  2. データ消失の悲劇を防ぐ!「自動バックアップ」と「エラー通知」【完了】
  3. 【今回】ユーザー管理の効率化:CSVファイルから大量のユーザーとSSH鍵を一括生成する
  4. セキュリティ監視:不正アクセス(SSH総当たり攻撃)を検知してIPを自動ブロックする

1. 手作業の恐怖と自動化の設計図

まず、コウ君がやろうとしている手作業の手順を書き出してみましょう。
ユーザー1人あたり、これだけのコマンドが必要です。

# 1. ユーザー作成
useradd -m -s /bin/bash tanaka

# 2. パスワード設定(対話式で入力が必要)
passwd tanaka

# 3. .sshディレクトリ作成
mkdir /home/tanaka/.ssh
chmod 700 /home/tanaka/.ssh

# 4. SSH鍵ペアの生成
ssh-keygen -t rsa -f /home/tanaka/.ssh/id_rsa -N ""

# 5. 公開鍵をauthorized_keysに登録
cat /home/tanaka/.ssh/id_rsa.pub > /home/tanaka/.ssh/authorized_keys
chmod 600 /home/tanaka/.ssh/authorized_keys

# 6. 所有者の変更
chown -R tanaka:tanaka /home/tanaka/.ssh

これを20人分、一度もタイプミスせずに打つ自信はありますか?
途中で誰かの権限設定を間違えてログインできなくなったり、SSH鍵を他人のものと取り違えたりするリスクが非常に高いです。

今回は、「ユーザー名と初期パスワードを書いたCSVファイル」を用意し、それをスクリプトに読み込ませることで、これら全てを自動実行させます。

2. ループ処理の主役「while read」構文

シェルスクリプトでファイルを一行ずつ読み込むには、while read という構文を使います。
これはLinuxの定型文として覚えてしまいましょう。

基本構文

while IFS=, read -r 変数1 変数2 ...; do
    # ここに処理を書く
    echo "読み込んだ値: $変数1, $変数2"
done < 読み込むファイル名

💡 呪文の解説

  • IFS=, (Internal Field Separator):
    「区切り文字はカンマ(,)ですよ」という宣言です。CSVを読む時は必須です。
  • read -r:
    ファイルから一行読み込みます。-r はバックスラッシュを文字として扱うオプションで、安全のために付けます。
  • < ファイル名:
    ループの最後に書くことで、指定したファイルの中身をループに流し込みます。

3. 準備:CSVファイルの作成

まずは、ユーザーリストとなる user_list.csv を作成します。
フォーマットは「ユーザー名,初期パスワード」としましょう。

[root@localhost ~]# vi user_list.csv

user_list.csv の中身

tanaka,Pass1234
suzuki,P@ssword5678
sato,Linux2024!

※実務では、パスワードを平文(そのままの文字)でファイルに保存するのはリスクがあります。
作業が終わったらこのCSVファイルは即座に削除するか、後述するパスワード自動生成テクニックを使うのが一般的ですが、今回はわかりやすく「指定したパスワードを設定する」方式で進めます。

4. 実装:一括ユーザー作成スクリプト

それでは、スクリプト create_users.sh を作成していきましょう。
段階を追って機能を積み上げていきます。

Step 1: CSVを読んで表示するだけ(テスト)

まずは正しく読み込めるか確認します。

#!/bin/bash

CSV_FILE="user_list.csv"

# ファイルの存在確認
if [ ! -f "$CSV_FILE" ]; then
    echo "エラー: $CSV_FILE が見つかりません。"
    exit 1
fi

echo "--- 読み込み開始 ---"

# ループ処理
while IFS=, read -r USERNAME PASSWORD; do
    # 空行や、#で始まるコメント行はスキップする
    [[ -z "$USERNAME" || "$USERNAME" =~ ^# ]] && continue

    echo "ユーザー: $USERNAME / パス: $PASSWORD を処理予定"
done < "$CSV_FILE"

echo "--- 読み込み終了 ---"

実行して、CSVの中身が表示されればOKです。

Step 2: ユーザー作成とパスワード設定の実装

実際に useradd コマンドを組み込みます。
パスワード設定には、対話入力が不要な chpasswd コマンドを使います。

💡 chpasswdコマンドとは?

通常 passwd ユーザー名 だと人間が手入力する必要がありますが、
echo "ユーザー名:パスワード" | chpasswd
とすることで、スクリプトから一発でパスワードを設定できます。大量登録の必須コマンドです。

# (ループの中身に追加)
    
    # ユーザーが既に存在しないかチェック
    if id "$USERNAME" &>/dev/null; then
        echo "[SKIP] $USERNAME は既に存在します。"
    else
        # ユーザー作成 (-m:ホームディレクトリ作成, -s:シェル指定)
        useradd -m -s /bin/bash "$USERNAME"
        
        # パスワード設定
        echo "${USERNAME}:${PASSWORD}" | chpasswd
        
        if [ $? -eq 0 ]; then
            echo "[OK] $USERNAME を作成しました。"
        else
            echo "[ERROR] $USERNAME の作成に失敗しました!"
        fi
    fi

Step 3: SSH鍵の生成と配置(プロ級テクニック)

ここが今回のハイライトです。
ユーザーを作成した直後に、そのユーザー専用のSSH鍵ペア(秘密鍵と公開鍵)をサーバー上で生成し、ログインできるように設定してあげます。

完成したスクリプト create_users_full.sh は以下のようになります。

#!/bin/bash

# ==========================================
# 設定エリア
# ==========================================
CSV_FILE="user_list.csv"
KEY_DIR="generated_keys" # 生成した秘密鍵を集める場所

# root権限チェック
if [[ $EUID -ne 0 ]]; then
   echo "エラー: このスクリプトはrootユーザーで実行してください。"
   exit 1
fi

# ==========================================
# メイン処理
# ==========================================

# 配布用鍵ディレクトリの作成
mkdir -p "$KEY_DIR"
chmod 700 "$KEY_DIR"

echo "=== ユーザー一括作成処理を開始します ==="

while IFS=, read -r USERNAME PASSWORD; do
    # 1. データチェック(空行・コメント行スキップ)
    [[ -z "$USERNAME" || "$USERNAME" =~ ^# ]] && continue

    # 2. ユーザー存在チェック
    if id "$USERNAME" &>/dev/null; then
        echo "[SKIP] ユーザー $USERNAME は既に存在します。"
        continue
    fi

    # 3. ユーザー作成
    useradd -m -s /bin/bash "$USERNAME"
    if [ $? -ne 0 ]; then
        echo "[ERROR] $USERNAME の作成に失敗しました。"
        continue
    fi

    # 4. パスワード設定
    echo "${USERNAME}:${PASSWORD}" | chpasswd

    # 5. SSHディレクトリの準備
    USER_HOME="/home/$USERNAME"
    SSH_DIR="$USER_HOME/.ssh"
    
    mkdir -p "$SSH_DIR"
    chmod 700 "$SSH_DIR"

    # 6. SSH鍵ペアの生成
    # -t rsa: 暗号化方式
    # -b 2048: 鍵の長さ
    # -N "": パスフレーズなし(自動化のため)
    # -f: 出力先ファイル名
    # -C: コメント(誰の鍵かわかるように)
    ssh-keygen -t rsa -b 2048 -N "" -f "$SSH_DIR/id_rsa" -C "Key for $USERNAME" > /dev/null 2>&1

    # 7. 公開鍵をauthorized_keysに登録
    cat "$SSH_DIR/id_rsa.pub" >> "$SSH_DIR/authorized_keys"
    chmod 600 "$SSH_DIR/authorized_keys"

    # 8. 権限修正(重要!)
    # rootで作ってしまったファイルを、ユーザーの所有に変更する
    chown -R "$USERNAME:$USERNAME" "$SSH_DIR"

    # 9. 秘密鍵を管理者が回収(配布用)
    # ユーザー本人に渡すために、手元のディレクトリにコピーしておく
    cp "$SSH_DIR/id_rsa" "$KEY_DIR/${USERNAME}_id_rsa"
    
    echo "[OK] $USERNAME を作成し、SSH鍵(${USERNAME}_id_rsa)を生成しました。"

done < "$CSV_FILE"

echo "=== 全処理完了 ==="
echo "生成された秘密鍵は $KEY_DIR に保存されています。"
echo "各ユーザーに安全な方法で配布してください。"
コウ君

おおお!
実行したら一瞬で画面が流れて、generated_keys フォルダの中に全員分の秘密鍵ができあがってます!
これなら、あとはこの鍵ファイルを本人にメールかチャットで送るだけで済みますね!

リナックス先生

その通り!
ただし、秘密鍵は「家の鍵」と同じくらい重要なものだから、メールで送るときはZipでパスワードをかけたり、社内の安全なファイルサーバー経由で渡したりと、取り扱いには十分注意してね。
そして、使い終わったこのスクリプトとCSVファイルは、必ず削除しておくこと。パスワードが残ったまま放置するのは厳禁よ。

5. パーミッション(権限)の落とし穴

このスクリプトで一番ハマりやすいポイントは、ステップ8の chown(所有者の変更) です。
これを忘れるとどうなると思いますか?

スクリプトは root 権限で実行しているため、作られた .ssh ディレクトリや authorized_keys ファイルの所有者は、デフォルトで root になってしまいます。
すると、ユーザー(例:tanakaさん)がログインしようとした時、「自分の家(ホームディレクトリ)にある鍵ファイルなのに、root様の持ち物だから読み取れない!」という状態になり、SSHログインが拒否されてしまうのです。

SSHのトラブル原因のNo.1は、この「パーミッションと所有権の間違い」です。
自動化スクリプトを書くときは、「誰の権限でファイルが作られるか」を常に意識しましょう。

6. 応用:パスワードを自動生成する場合

「初期パスワードを考えるのも面倒くさい」という場合は、openssl コマンドを使ってランダムな文字列を生成することができます。
CSVファイルのパスワード欄を空にして、スクリプト側で以下のように生成すれば、さらに自動化が進みます。

# ランダムな12文字のパスワードを生成
PASSWORD=$(openssl rand -base64 12)

echo "ユーザー: $USERNAME / 自動生成パスワード: $PASSWORD"
# 生成したパスワードを別途ファイルに保存して、後で管理者が確認できるようにする
echo "$USERNAME,$PASSWORD" >> created_passwords.csv

まとめ:ループ処理を制する者はサーバーを制す

今回は、シェルスクリプトによる「繰り返し処理(ループ)」の実践編として、ユーザー一括作成ツールを作りました。

技術要素 解説
while read ファイルを行単位で読み込む基本構文
IFS=, CSV(カンマ区切り)を正しく分割するための設定
chpasswd スクリプトから非対話でパスワードを設定するコマンド
ssh-keygen -N "" パスフレーズなしのSSH鍵を自動生成するオプション

20人のユーザー作成も、1000人のユーザー作成も、このスクリプトがあれば労力は変わりません。
これが「自動化(Automation)」の威力です。

コウ君、これで浮いた時間を使って、もっとクリエイティブな仕事(あるいは休憩)ができそうね!

次回予告:見えない攻撃者との戦い

さて、ユーザーを作成してSSHを開放したということは、外部からのアクセスの入り口が増えたことも意味します。
あなたのサーバーは今この瞬間も、世界中から「総当たり攻撃(ブルートフォースアタック)」を受けているかもしれません。

次回は最終回。
ログをリアルタイムで監視し、何度もログインに失敗してくる怪しいIPアドレスを自動的に検知して、ファイアウォールでブロックする「自動防衛システム」を作成します。
まさに「サーバーの守護神」となるスクリプトを作りましょう!

リナックス先生

今回のスクリプト、試すときは間違って自分(今ログインしているユーザー)を上書きしたりしないように、テスト環境で慎重にやってね。
VPSなら、OS再インストール機能を使って、まっさらな状態から試すのが一番の練習になるわよ!

▼スクリプトの実験場に最適!推奨VPS

【2026年最新】Linuxサーバー構築におすすめのVPS比較3選!現役エンジニアが速度とコスパで厳選
Linuxの勉強、まだ「自分のPC」でやって消耗していませんか?「Linuxを覚えたいけど、環境構築でエラーが出て先に進めない…」「VirtualBoxを入れたらパソコンが重くなった…」これは、Linux学習を始める9割の人がぶつかる壁です...

コメント