概要
GCP 上の Ubuntu Server において、ssh.service に systemd の hardening 設定を追加したところ、
- 一般ユーザーでの ssh ログインは可能
- しかし `sudo` / `su` が一切使えなくなる
という 管理不能に近い状態 に陥った。
本記事では、
- 何が原因だったのか
- なぜ sudo が使えなくなったのか
- 想定される復旧ルート(シリアル接続 / ディスク救出)
- 最終的に **GCP メタデータの起動スクリプトで復旧した手順**
を、備忘録として体系的にまとめる。
環境
- GCP Compute Engine
- Ubuntu Server
- ssh 経由で管理
- Docker + AppArmor を利用
発生した事象
- ssh ログインは可能
- 通常コマンドは実行可能
- docker / サイトは通常稼働
- sudo / su のみ完全に不可
原因
ssh.service に以下の hardening 設定を入れていた。
NoNewPrivileges の影響
- `NoNewPrivileges=yes` は **SUID / sudo / capability を完全に無効化**
- sshd はログインシェルの親プロセス
- ssh 経由で起動した全プロセスがこの制約を **解除不能で継承**
結果:
ssh から入った瞬間に sudo が永遠に使えなくなる
これは systemd の仕様通りの挙動。
想定される復旧ルート
1. シリアルコンソール接続
- VM を停止
- 「シリアルポートへの接続」を有効化
- VM を起動
- シリアルコンソールに接続
ただし GCP 公式イメージでは:
- ローカルパスワード未設定
- root ログイン不可
→ Login incorrect で入れないケースが多い
2. 起動ディスク救出(確実だが重い)
- VM 停止
- ブートディスクをデタッチ
- 別 VM にアタッチ
- `override.conf` を修正
- 元の VM に戻す
成功率 100% だが、作業コストが高い。
今回成立した前提条件
今回のケースでは以下が成立していた:
- 一般ユーザーで ssh ログイン可能
- OS / systemd は正常起動
- metadata server へ到達可能
→ GCP 起動スクリプト(startup-script)が使える
最終的に採用した復旧方法(起動スクリプト)
方針
- ssh を経由せず
- sudo も使わず
- root 権限で
- `override.conf` を直接修正
起動スクリプト内容
GCP コンソール → インスタンス編集 → メタデータ → 起動スクリプト
実行手順
- 起動スクリプトを保存
- VM を再起動
- ssh ログイン
注意点(重要)
ssh セッションの再接続が必須
既存の ssh セッションは:
- **古い NoNewPrivileges 制約を保持したまま**
そのため:
→ ssh を切断して再接続 が必須。
確認
→ sudo 復活
起動スクリプトは必ず削除
復旧後は:
- 起動スクリプトを **必ず削除**
- 毎回 ssh restart が走るのを防ぐ
教訓
❌ やってはいけない
- `ssh.service` に `NoNewPrivileges=yes`
✅ 正しい hardening
- ssh(管理入口)は **昇格可能に保つ**
- hardening は以下に限定 * nginx * django * mariadb * worker / batch
まとめ
- sudo が使えなくなった原因は `NoNewPrivileges`
- systemd の仕様通りの挙動
- 復旧手段は複数あるが * **軽度ロックアウト:起動スクリプト** * 完全ロックアウト:ディスク救出
- ssh は「最優先で管理可能性を確保する」
同様の事故を防ぐためにも、
**入口(ssh)と実行体(サービス)を分けて hardening する**
ことが重要。




