個人開発者が受託Laravelシステムのエスクロー情報を整えた記録
このメモ書きは、個人で受託開発・保守をしている開発者が、顧客から「開発者に万一のことがあった場合に備え、パスワード・仕様・引き継ぎ情報を預けてほしい」と求められ、その準備を進めた記録である。手順だけでなく、つまずき、寄り道、余談もそのまま残している。
前提と要件
対象はLaravel製の業務システムで、1台のVPS上に本番の複数店舗サイトとステージングが同居している。コードは全店舗共通で、店舗ごとの違いは各サイトの .env で吸収している。開発環境はWSLである。
顧客側の要望を整理すると、要件は次の5つになる。
| 要件 | 内容 |
|---|---|
| 迷わない | 開発者に何かあっても、引き継ぎ者が迷わない |
| 更新できる | 預けた内容を、開発者がいつでも更新できる |
| 安全に渡せる | パスワードや鍵を安全に渡せる |
| 気づける | 予期せぬアクセスがあれば、開発者が気づける |
| 止まらない | 支払いの停止やサービス停止でシステムが止まらない |
エスクローとは、第三者が預かり物を保管し、決められた条件がそろったときだけ相手に渡す仕組みである。今回は「開発者と2週間連絡が取れない場合」などを開示条件とし、預け先は顧客自身か、顧客が契約するエスクロー業者になる。性質としては貸金庫に近い。
全体の進め方
最初に全項目を洗い出したロードマップを作ったところ、項目が多すぎて手が止まりそうになった。そこで最低限の項目に★を付け、★だけで引き継ぎが成立する形に絞っている。
顧客の返事待ちが発生する作業(見積、契約書、ホスティング会社への問い合わせ)を先に投げ、待っている間に自分だけでできる作業を片付ける順番にしている。★の作業量は合計20〜30時間程度の見積もりだが、実際のボトルネックは作業時間ではなく待ち時間になる。
名義と支払いの棚卸し
アカウント・契約名義・支払い者を一覧にしたところ、ほぼすべてが開発者個人のGmailにぶら下がっていた。この状態では、開発者に何かあった時点でパスワード再設定もできなくなる。
サービスは、複数人で使えるかどうかで扱いが分かれる。
| 種類 | 例 | 対応 |
|---|---|---|
| 複数人で使える | GitHub、Google Cloud | 引き継ぎ者を追加すれば済む |
| 1アカウントのみ | ドメインレジストラ、ホスティングの会員ID | ログイン用メールを顧客側が受け取れるものにするしかない |
1アカウントしか使えないサービスはメールで認証コードが届くため、顧客側が受け取れるメールアドレスがすべての土台になる。
開発者は当初、顧客専用のつもりで作ったホスティング会社のメールボックスのアドレスを使う予定だった。ところが、そのメールボックス契約は開発者個人の名義・支払いで、個人のアドレスとも同居していた。契約が止まればアドレスごと消えるため、根本的な解決にはなっていなかった。
ドメインの登録者情報(WHOIS)のメールアドレスを変更すると、ICANNのルールにより確認メールが届く。期限内にリンクを押さないと、ドメインが一時停止される場合がある。ログイン用のメールアドレスと登録者情報のメールアドレスは別物で、確認メールが関係するのは後者である。Whois代理公開を使っている場合は、登録者のメールが代理業者のものになっていることもある。
郵便番号から住所への変換にGoogle CloudのGeocoding APIを使っていたが、プロジェクトは開発者個人のアカウントのまま引き継がない方針にしている。支払いは顧客の請求アカウントなので、開発者に何かあってもAPIはしばらく動き続ける。作り直しの手順だけを残す。郵便番号変換は日本郵便が配布しているデータで置き換えられるため、将来的にはGCPへの依存自体をなくす選択肢もある。
ソースコードをPCの外へ出す
最初の緊急対応は、ソースコードをGitHubへ退避することだった。Gitの履歴が開発者のWSLにしか存在せず、PCが壊れれば履歴ごと消える状態だったためである。
GitHubアカウントは顧客用のものを新規に作り、リポジトリは非公開で作成している。作成時の選択肢は次のように扱った。
| 選択肢 | 選択 | 理由 |
|---|---|---|
| 公開範囲 | Private | 非公開システムのため |
| README追加 | なし | 手元に既存のものがあり、履歴が衝突する |
| .gitignore追加 | なし | Laravelに最初から含まれている |
| ライセンス | None | OSSライセンスを付けると利用許諾を出すことになる |
リポジトリ名に STAGING を付けるか迷ったが、リポジトリはコードの置き場であって環境の置き場ではないため付けていない。本番とステージングの区別はブランチとREADMEの冒頭で示している。
## ブランチと反映先
| ブランチ | 反映先 |
|---|---|
| main | 本番(全店舗) |
| staging | ステージング |
SSH鍵でつまずいた点
pushまでに何度も Permission denied (publickey) が出ている。原因は単純で、公開鍵をGitHubに登録していなかった。
SSH鍵は物理の鍵と錠前にたとえると理解しやすい。秘密鍵がギザギザの付いた鍵、公開鍵が錠前である。ssh-keygen は鍵と錠前を1セット作る。錠前(.pub)をドア(GitHubやサーバー)に取り付けて、初めて鍵が回る。秘密鍵は動かさず、錠前のほうを運ぶ。錠前から鍵は作れないが、鍵から錠前は作り直せる。
ssh-keygen -t ed25519 -C "github-customer" -f ~/.ssh/github_customer
cat ~/.ssh/github_customer.pub
表示された1行を、GitHubの「Settings」→「SSH and GPG keys」→「New SSH key」に貼る。Key typeは Authentication Key を選ぶ。Signing Key はコミットの署名用で、ドアは開けられない。
登録済みの公開鍵は、次のURLで誰でも確認できる。登録漏れの確認に使える。
https://github.com/ユーザー名.keys
接続に使う鍵は、-v で確認できる。
ssh -vT git@github.com 2>&1 | grep -E "identity file|Offering|Authenticated|denied"
Offering public key に目的の鍵が出ていて、なお拒否される場合は、GitHub側に錠前が付いていない。
秘密鍵と公開鍵の見分け方は次のとおりである。ファイル名に .pub が付いているのが公開鍵で、1行だけの ssh-ed25519 AAAA... という形式になる。秘密鍵は拡張子なしで、1行目が -----BEGIN OPENSSH PRIVATE KEY----- になっている。PRIVATE KEY と書かれたものは、どこにも貼らない。
鍵が複数ある場合の扱い
開発者は個人のGitHubアカウントも持っているため、鍵の使い分けが必要になった。SSHは id_ed25519 などの決まった名前の鍵しか自動で使わない。また、GitHubへの接続ユーザーは全員 git で共通で、どの鍵を差し込んだかでアカウントが判別される。
| 状況 | ~/.ssh/config |
|---|---|
鍵が id_ed25519 の1本だけ |
不要 |
| 鍵に独自の名前を付けた | 必要 |
| 同じホストに複数アカウントで入る | 必要 |
Host github-customer
HostName github.com
User git
IdentityFile ~/.ssh/github_customer
IdentitiesOnly yes
git remote set-url origin git@github-customer:アカウント名/リポジトリ名.git
github-customer は開発者のWSL内だけで通じる別名である。引き継ぎ者は自分の環境で通常どおり git@github.com:... を使う。
ssh コマンドは -i で鍵を指定できるが、git は -i を受け付けない。別名を使わない場合は、リポジトリ単位で鍵を指定する方法もある。
git config core.sshCommand "ssh -i ~/.ssh/github_customer -o IdentitiesOnly=yes"
config の中身は、コマンドの -i、-p、-l などを事前に書いておくものにすぎない。
Could not resolve hostname github-customer が出た場合は、~/.ssh/config が存在しないか、別名の綴りが違っている。SSHが別名を知らないため、実在のホスト名として探しに行って失敗している。
GitHubは2021年に、gitの操作でのパスワード認証を廃止している。現在はSSH鍵かトークンを使う。gh auth login でブラウザから承認する方式は、パスワードを毎回送るのではなく、取り消し可能な通行証(トークン)を端末ごとに発行する仕組みになる。トークンは使い捨てではなく、取り消すか期限が切れるまで使える。不要になった端末のトークンは削除しておく。
git push は受け皿を自動では作らない。GitHub CLIを使うと、作成とpushを一度に実行できる。公開範囲を指定しないと対話で聞かれるか、エラーで止まる。
gh repo create リポジトリ名 --private --source=. --push
push後は、ブラウザのシークレットウィンドウでリポジトリのURLを開き、404になることを確認している。
サーバー側の確認
バックアップ
バックアップスクリプトのログを確認したところ、店舗ごとのDBはすべてダンプされていた。外部サーバーへの転送はコメントアウトで停止されており、ドキュメント側の記述だけが古いまま残っていた。
sudo tail -n 50 /var/log/backup.log
sudo grep -n "rsync" /usr/local/bin/backup.sh
コメントアウトした箇所には、停止した理由を1行残している。理由がないと、引き継ぎ者が戻すべきか判断できない。
同じVPS内にしかないバックアップは、VPSごと失われた場合には意味をなさない。外部保存は別料金とし、要否を顧客に文書で判断してもらう方針にしている。
廃止したサイトの公開停止
/etc/apache2/sites-enabled/ に、廃止済みのプロジェクトが2つ残っていた。Apacheは起動時に sites-enabled だけを読み込むため、ここにある設定はすべて配信対象になる。メンテナンスされないコードは攻撃の入り口になりやすいため、公開を停止している。
sudo a2dissite 廃止サイト 廃止サイト-le-ssl
sudo apache2ctl configtest
sudo systemctl reload apache2
停止前に、そのサイトの ServerName が他のサイトと共有されていないことを確認している。
sudo grep -n "ServerName\|ServerAlias\|DocumentRoot" /etc/apache2/sites-available/廃止サイト*.conf
sudo apache2ctl -S
確認用のコマンド例をまとめて貼り付けて実行した結果、最後の「元に戻すコマンド」まで実行してしまい、停止したサイトが再び有効になっていた。プレースホルダ(ドメイン1 など)もそのまま実行され、curlが 000 を返していた。手順をまとめて渡されたときは、1行ずつ意味を確認して実行する必要がある。
phpMyAdmin
phpMyAdminはBasic認証付きで公開されていたが、ユーザー名がDB名から推測できるものだった。また、Aliasがグローバル設定のため、全ドメインから同じURLで開ける状態になっていた。
理想はSSHトンネル経由でしか開けない構成である。ただ、手順が増えるため今回は見送り、Basic認証の強化にとどめている。
sudo htpasswd -c /etc/apache2/.htpasswd_pma 推測されにくい名前
openssl rand -base64 24
.htpasswd はviでも開けるが、コロンの右側はハッシュ化されたパスワードである。平文で書き換えるとログインできなくなる。ユーザー名だけを変えるならviで左側を書き換えれば動くが、パスワードを変えるなら htpasswd コマンドを使う。
IP制限は、開発者が外出先から作業できなくなるうえ、引き継ぎ者のIPも分からないため採用していない。SSHトンネル方式であれば、IPではなくSSH鍵で入口を絞れるため、引き継ぎ用の鍵ともつながる。後日の課題として残している。
SSHログイン通知の設計
「予期せぬアクセスに気づける」を満たすため、許可したIP以外からSSHログインがあった場合に通知する仕組みを設計している。PAMの pam_exec を使うと、SFTPも含めてログイン時にスクリプトを実行できる。
#!/bin/bash
[ "$PAM_TYPE" = "open_session" ] || exit 0
ALLOW_IPS="xxx.xxx.xxx.xxx"
for ip in $ALLOW_IPS; do
[ "$PAM_RHOST" = "$ip" ] && exit 0
done
MSG="WARNING! SSH login: user=${PAM_USER} from=${PAM_RHOST} host=$(hostname) at $(date '+%F %T')"
printf "Subject: [WARNING] SSH login from %s\n\n%s\n" "$PAM_RHOST" "$MSG" | msmtp 通知先 &
exit 0
session optional pam_exec.so /usr/local/bin/ssh-login-alert.sh
required にすると、通知の失敗でログイン自体ができなくなるため optional にする。通知手段は当初Discordを検討したが、何年も放置される前提では仕様変更が怖いため、最も長く変わらないメールを選んでいる。どの手段でも、通知が止まると届かないことが「平和」に見えるため、定期的にわざと通知を飛ばして確認する。
エスクロー情報の置き場所
預けるのは「金庫の鍵」だけ
パスワードや手順書そのものを封筒で預けると、変更のたびに預け直しになり、「いつでも更新できる」が成立しない。そこで中身はオンラインに置き、封筒にはそこへ入るための情報だけを入れる設計にしている。
Bitwardenとスプレッドシート
当初はパスワードマネージャーのBitwardenを検討した。組織向けの有料プランならアクセスログも残るが、無料プランにはない。最終的に、管理用のGoogleアカウントを新規作成し、その中のスプレッドシートを台帳にする構成を選んでいる。
| 観点 | 判断 |
|---|---|
| 共有範囲 | リンク共有はしない。管理用アカウントのみ |
| 開発者個人のGmailとの共有 | しない。個人アカウントが乗っ取られると全部漏れる |
| 閲覧ログ | 個人のGoogleアカウントでは取れない。ログインの検知で補う |
| アクセスの検知 | 新しい端末からのログイン時に、Googleが再設定用メールへ通知する |
「URLを知らなければ開けない」は守りにならない。共有アイテム、閲覧履歴、共有通知メールなど、アカウントに入られればURLは数秒で見つかる。守りの要はURLではなくアカウントそのものになる。
切り替えが面倒という理由で一度は個人のGmailと共有したが、裏口を作ることになるため外している。代わりに、Chromeのプロフィールを分けて、ワンクリックで切り替えられるようにしている。
Googleは、2年間使われていない個人アカウントを削除する。管理用アカウントの中身を個人アカウントから編集者として更新しても、管理用アカウント自体の利用にはならない。今回は各サービスの通知メールの受け取り先も管理用アカウントに寄せたため、定期的にログインすることになり、この問題は起きにくい。
アカウント作成時の生年月日について、封筒を開けた人に開発者の生年月日が渡ることを懸念した。ただ、SNSで公開済みであれば隠す意味は薄い。管理用アカウントらしさを優先するなら、開発者個人と関係のない日付にする選択肢もある。後から変更でき、18歳未満になる日付は避ける。
パスワードの作り方
封筒のパスワードは、紙から手で打ち込まれる。0 と O、1 と l と I などの紛らわしい文字を除いて生成している。
tr -dc 'A-HJ-NP-Za-km-z2-9' < /dev/urandom | head -c 24; echo
紙には4文字ずつ区切って書き、区切りのスペースは入力しないと添える。
2段階認証とシークレットキー
認証アプリ方式の2段階認証はTOTP(Time-based One-Time Password)と呼ばれる。シークレットキーと現在時刻から6桁を計算するため、シークレットキーさえ控えておけば、別のスマホでも同じ6桁を出せる。引き継ぎ者は、自分の認証アプリにキーを手入力すればよい。
| 方式 | 引き継ぎ |
|---|---|
| 認証アプリ(TOTP) | シークレットキーを控えれば可能 |
| SMS | 開発者の電話番号に縛られるため不可 |
| メール | 受信先を顧客側が見られれば可能 |
| パスキー | 開発者の端末に縛られるため不可 |
台帳にパスワードもシークレットキーも書くため、TOTPとメール認証で安全性はほぼ変わらない。メール認証を選べるサービスはメール、選べないサービス(GitHubなど)はTOTPという使い分けにしている。
QRコードからシークレットキーを取り出す
GitHubはQRコードの下の「setup key」でキーを文字表示できる。ホスティング会社の画面はQRコードしか表示されなかったため、スクリーンショットを撮ってWSLで読み取っている。
sudo apt install zbar-tools
zbarimg /mnt/c/Users/PC/Downloads/QR.jpg
QR-Code:otpauth://totp/アカウント名?secret=XXXXXXXX&issuer=...
secret= から & の手前までがシークレットキーである。控えたらスクリーンショットは削除する。
Windowsのパス C:\Users\PC\Downloads\QR.jpg をそのままWSLで指定すると、\ が消えて UsersPCDownloadsQR.jpg として扱われ、must specify image size というエラーになる。WSLでは /mnt/c/Users/PC/Downloads/QR.jpg と書く。
相談の途中、QRコードの画像を赤い枠線で囲んで「塗りつぶした」つもりで共有している。QRコードは一部が欠けても読み取れるように作られているため、枠線程度では隠れない。漏れたものとして2段階認証を設定し直している。
リカバリーコードは、6桁の代わりに1回ずつ使える予備の鍵である。シークレットキーがあれば理屈の上では不要だが、キーを写し間違えていた場合の最後の命綱になるため保存している。2段階認証を設定し直すと古いキーは無効になり、リカバリーコードを再発行すると古いコードはすべて無効になる。封筒の中身と食い違わないよう、作り直した場合は封筒も更新する。
Googleの7日制限でつまずいた件
今回最大のつまずきである。管理用のGoogleアカウントを作成した翌日、2段階認証を有効化しようとしたところ「本人確認を行えませんでした」と表示され、何をしても先へ進めなくなった。
Googleのヘルプによると、2段階認証の有効化は「機密情報に関する操作」に分類される。本人確認には7日以上前から登録されている端末か電話番号が必要で、作成直後のアカウントにはそれが存在しない。本人確認に失敗すると7日間は機密の操作がブロックされ、7日経過後は本人確認なしで操作できるようになる。
同じ回線、同じOS、同じブラウザでも通らなかった理由は、GoogleがIPやユーザーエージェントではなく、ブラウザに保存されたCookieや端末の識別情報で「前に見た端末か」を判断しているためである。シークレットウィンドウは閉じるたびにそれを消すため、毎回初めての端末として扱われる。IPやユーザーエージェントは偽装できるため、判断材料としては弱い。
さらに、作ったばかりのアカウントで、ブラウザを次々に変え、電話番号を追加しては消し、セキュリティ設定を連発する動きは、乗っ取りやアカウントの量産と区別がつかない。乗っ取り犯は最初に2段階認証を自分のスマホで設定し、持ち主を締め出すためである。
最終的にアカウントを作り直し、作成直後のセッションのうちに2段階認証を有効化して通過している。このとき、QRコードによる認証アプリと電話番号の両方が求められた。電話番号は開発者のものなので、引き継ぎ者には「確認がスマホに送られた場合は『別の方法を試す』から認証アプリのコードを使う」と説明書に書く。
新しいGoogleアカウントは、作成したその場で2段階認証とバックアップコードまで済ませる。これが今回の最大の教訓である。
2段階認証をオフのままにしておけば手間は減るように見えるが、オフでもGoogleは知らない端末からのログインに確認を求めることがある。そのとき確認コードが届くのは再設定用のメールや電話番号で、開発者のものであれば引き継ぎ者は受け取れない。バックアップコードは2段階認証をオンにしないと発行できないため、オンにしたほうが引き継ぎは確実になる。
顧客には封筒の発送を延期する連絡を入れている。遅れの理由をGoogleのセキュリティ仕様として事実だけ書き、あわせて「2段階認証を設定したうえで送ったほうが安全に預けられる」と添えると、言い訳ではなく顧客のための判断として伝わる。延期の連絡でも、それまでに完了した作業を列挙しておくと、何もしていなかったようには見えない。
エスクロー用のSSH鍵
開発者が普段使っている鍵は預けず、エスクロー専用の鍵を別に作っている。普段の鍵を使い回すと、漏れたときに自分の鍵まで作り直しになり、ログを見てもどちらの鍵で入られたか区別できない。
ssh-keygen -t ed25519 -C "escrow-customer" -f ~/escrow_customer
cat ~/escrow_customer.pub
公開鍵の1行をサーバーの ~/.ssh/authorized_keys に追記し、その鍵でログインできることを確認する。確認中は、普段の鍵で入っているセッションを切らない。
ssh -i ~/escrow_customer ubuntu@サーバー
ssh-keygen -lf ~/escrow_customer.pub
指紋(SHA256:...)は台帳に控える。秘密鍵は管理用アカウントのドキュメントに貼り、パスフレーズは台帳に書き、手元の鍵は削除している。
鍵をサーバー側で作らない理由は、秘密鍵が一度でもサーバー内に存在すると、サーバーが乗っ取られたときに持ち去られる可能性があるためである。鍵は使う側の手元で作り、錠前だけをドアに付ける。サーバーにまだ錠前がない最初の1本は、ssh-copy-id でパスワードを使って登録するか、コントロールパネルのコンソールから書き込む。
新しいサーバーを立て直すなら、エスクロー用の鍵は不要に思える。ただ、バックアップは同じVPS内にしかないため、古いサーバーからDBやアップロードファイルを取り出すために必要になる。エスクロー用の鍵は、新しいサーバーに入るためではなく、古いサーバーから荷物を運び出すための鍵である。
GitHub用のSSH鍵は台帳に載せていない。引き継ぎ者は管理用アカウントのGitHubにログインし、自分の鍵を登録するか、自分のアカウントをCollaboratorとして招待すればよい。秘密鍵を台帳に載せても使い道がなく、漏れる場所が増えるだけになる。
封筒の設計
| 項目 | 内容 |
|---|---|
| 中身 | 管理用Googleアカウントのログイン情報、シークレットキー、バックアップコード、説明書(A4 1枚) |
| 封 | 内側の封筒の継ぎ目に日付と署名をまたいで書き、透明テープを貼る |
| 外側 | 二重封筒にし、外には「書類在中」とだけ書く |
| 版管理 | 表に「第1版 日付」と書き、更新時は丸ごと差し替えて旧版を未開封で返送してもらう |
| 送付 | 手渡しが最善。郵送なら一般書留、簡易書留、レターパックプラス |
説明書には、開封してよい条件、届いたときにやること(封の確認と施錠保管)、開封するときに日時と氏名を書くことを記載する。
顧客とのやりとり(余談)
エスクローの準備と並行して、顧客から「AIを使った自動攻撃への対策は大丈夫か」という問い合わせがあった。
返信の方針は、「問題ありません」とは書かず、やっていることと穴を正直に書いて、穴は改善提案に変えることである。顧客のシステムでは、ログインパスワードに電話番号が使われ、さらに全員が同じパスワードを共有していた。退職者のアカウントを無効にしても、他人のアカウントで入れてしまう。
ITに不慣れな相手への説明は、以下でたとえた。
| 説明したいこと | たとえ |
|---|---|
| 共有パスワードの危険 | 郵便受けの暗証番号を、辞めた社員が今も知っている状態 |
| 192.168で始まるIPアドレス | 社内だけで使う内線電話の番号 |
IPアドレス制限を提案したところ、各拠点から届いたのは 192.168.x.x のプライベートIPばかりだった。確認サイトを案内し直した結果、正しいグローバルIPが届いている。続いて「パスワードを変更しました」という連絡とともに、新しいパスワードがメールで送られてきた。その文字列は、IPを調べたときにパソコンの画面に表示されていたIPv6のリンクローカルアドレスの後半と一致していた。パスワードはメールで送らないこと、送ったものは変更することを伝えている。
メールの文面では、句読点を入れすぎると機械的な文章に見えるという意見があった。改行で区切っているなら、読点は減らしてもよい。ただし「その為」などの漢字表記は硬く見えるため、ひらがなにしている。また、同じ名字の人が2人いる相手に名字だけで書いたところ、別の人が自分のことだと思って返信してきた。「先ほどの件」のような指示語も、行き違いの直後には避けている。
余談
情報セキュリティの基本は、機密性(見ていい人しか見られない)、完全性(勝手に書き換えられない)、可用性(使いたいときに使える)の3要素である。国家銀行の金庫から自転車の鍵まで、規模が違うだけで考え方は同じになる。今回のエスクローは、開発者がいなくなってもシステムを使い続けられるようにする、可用性の対策にあたる。全員同じパスワードの件は、機密性と責任追跡性が同時に崩れている状態である。
鍵と暗号の歴史は古い。紀元前2000年頃のエジプトにはピン式の木製錠があり、スパルタのスキュタレー、ローマのシーザー暗号、9世紀の頻度分析、第二次大戦のエニグマ解読、1970年代の公開鍵暗号へと続く。4000年間、本人そのものを確かめる方法は存在せず、確かめているのは「知っているもの」「持っているもの」「本人の体」という証拠だけである。どれも盗まれるか、渡されるか、真似される。体にIDチップを埋めても「持っているもの」の一種で、作り直せない分だけ扱いは難しくなる。最後は「誰を信用するか」という人間の判断に行き着く。
GitHubも過去にSSH鍵まわりで事件を経験している。2012年には脆弱性を突いて他人のリポジトリに公開鍵が登録される実演があり、2023年にはGitHub自身のSSH用の秘密鍵が一時的に公開リポジトリに載る事故が起きている。専門家の集まる会社でも秘密鍵はうっかり漏れる。push前の .env の確認は手を抜かない。
まとめ
| 論点 | 結論 |
|---|---|
| 何を預けるか | 中身ではなく、中身に入るための鍵だけを預ける |
| どこに置くか | 管理用の専用アカウントに集約し、個人アカウントとは共有しない |
| 名義と支払い | 1アカウントしか使えないサービスは、顧客が受け取れるメールが土台になる |
| ソースコード | 最優先でPCの外へ出す。リポジトリ名は環境ではなくシステムを表す |
| SSH鍵 | 鍵は手元で作り、錠前だけを運ぶ。エスクロー用は普段の鍵と分ける |
| 2段階認証 | TOTPのシークレットキーを控えれば引き継げる。SMSとパスキーは引き継げない |
| 新規Googleアカウント | 作成したその場で2段階認証とバックアップコードまで済ませる |
| アクセスの検知 | 見られたかより、使われたかを検知する |
| 不要な公開 | 廃止したサイトは sites-enabled から外す |
| 顧客への説明 | 問題なしと書かず、穴は改善提案に変える。たとえ話は1行で |
あとがきとして、今回の作業は技術的には基本的な内容が多かった。それでも、SSH鍵の仕組みやGitのリモートの意味を「なぜそうなるのか」から確かめ直したことで、引き継ぎ書に書くべき内容がはっきりしている。自分が理解していないことは、人に説明できないためである。Googleの7日制限には半日以上振り回されたが、結果として「新規アカウントは作った瞬間に固める」という教訓が残っている。エスクローの封筒は、開けられないまま返ってくるのが一番よい結末である。