Crontab を別のユーザのもので上書きしてしまった話

このやらかしは、私の人生観を変えるきっかけとなった出来事でもあります。最後までお読みいただけたら幸いです。

## 環境

CentOS

## やらかしたこと

root ユーザの Crontab を他の一般ユーザのもので上書きしました。

## 背景

某平日の夜 9 時半ごろ、（当時）新卒 2 年目で開発チームの私と新卒 4 年目でインフラチームの先輩は障害対応にあたっており、 **Crontab の一部をコメントアウトする操作** を行おうとしていました。

> 私「もう眠いですよ～先輩、早くクーロン見ましょ :blush:」
>
> 先輩「うん、見よ見よ :yellow_heart: これをこうして... :computer::hammer:」
>
> 私「Crontab の確認って、 Crontab を確認したいユーザにログインして `crontab -l` じゃないんですか？ :thinking:」
>
> 先輩「ああ、それもあるけどわたしはいつも **root で `/var/spool/cron/${ユーザ名}` 見てる** よー :mag:」
>
> 私「へぇ～、初めて知りました。そういう方法もあるんですね :bulb:」

そして、いざ作業へ。

> 私「じゃあさっそく作業に入りますか :muscle:」
>
> 先輩「いいよー :+1:」
>
> 私「**Crontab の修正はこちらでやりますね** :sparkles:」
>
> 先輩「オッケー :ok_woman:」

私は慣れた手つきで Crontab の修正を行います。

まずサーバでの操作です。
目的のユーザにログインして Crontab をファイルにリダイレクトしておきます。

```html:私のターミナル
$ ssh target_user@centos
[target_user@centos ~]$ crontab -l > /tmp/file.txt
[target_user@centos ~]$ exit
```

次にローカルでの操作です。
次にローカルにファイルをダウンロードして、編集してからアップロードします。堅実ですね。

```html:私のターミナル
$ scp target_user@centos:/tmp/file.txt .
$ いろいろ編集する
$ scp ./file.txt target_user@centos:/tmp
```

そして、 Crontab を反映させるときが来ました。

**作業は先輩の PC で** 、画面を 2 人で見ながらやります。

```html:先輩のターミナル
[root@centos ~]$
```

> 私「では反映いっちゃいますか :pray:」
>
> 先輩「いいよー、 **`crontab /tmp/file.txt`** っと...」

```html:先輩のターミナル
[root@centos ~]$ crontab /tmp/file.txt
```

> 先輩「いくよー？ :wink:」
>
> 私「いいですよー！ :smiley:」
>
> 先輩「じゃあいきまーす、ちゅどーん :bomb:（Enter キーを叩きながら :boom:）」

Crontab の反映が完了しました。

```html:先輩のターミナル
[root@centos ~]$ crontab /tmp/file.txt
[root@centos ~]$
```

> 私「...ん？ちょっと待ってください？」
>
> 先輩「ん、どした？」

ターミナルをもう一度見直すと、

```html:先輩のターミナル
[root@centos ~]$ crontab /tmp/file.txt
[root@centos ~]$
```

root ユーザで作業していました。

何度見ても root ユーザなのには変わりありませんでした。

私は root ユーザの Crontab を他のユーザのもので上書きしたのです。

こうして root ユーザの Crontab は失われました。

## どうやって復旧したか

私はふと **Crontab の中身が Git 管理されている** ことを思い出し、すぐさまそこから Crontab の復元を行いました。

幸い、事なきを得ています。

## 惨劇はなぜおこってしまったのか

細かく見ると私の知識不足とか root で作業する必要性とかあると思うのですが、今回のオペミスの直接原因としては大きく 2 つあります。

#### 実行ユーザの確認を怠った

コマンドの確認はしっかり行っていましたが、普段から「root ユーザで作業するときはどうせ sudo だし」とか「自分は root に入ることはまずないし」とかで、ユーザの確認をすることが少なかったように思います。

#### その場でコマンドを打って作業していた

もともと障害対応のため、早く対応しなければという焦りから、ターミナルで直接コマンドを打って作業していました。

## 二度と惨劇を起こさないためにどうしたのか

本番サーバでは、少しの作業でも

- ターミナル上でコマンドを直接打たない
- ユーザの確認を含めた手順書を作成する、もしくは急ぎであってもローカル PC のエディタにコマンドを下書きして、チェックしてからコピペ→実行する

ようにしました。

手順書作成中にファイルの場所を確認したりコマンドの存在を確認したりするなど、やむを得ない場合もありますが、ターミナルウィンドウがアクティブの時には、できるだけ「Ctrl + V」「Enter」「マウス操作」だけで操作を完結できるように気を付けました。

それからコマンドのミスをすることは大幅に減りました。

#### 作業をより安全に行うために

コピペミス防止のための対策もあるといいと思います。
テキストを選択した状態でエディタでコピーした後、その場で 1 度貼り付け、テキストの中身が変化しなければちゃんとコピーできています。

また、 `rm` や `chmod` など、みなさんがよく使用するコマンドには `-v (--verbose)` オプションがついているものも多く、「ファイル削除しましたよー」とか「権限変更しましたよー」のメッセージをターミナル上に表示することが可能です。
ぜひ使ってみてください。

#### 2020/12/17 追記: @NACK さまコメントより

> `crontab -l > ${ファイル名}` を実行するターミナルと `crontab ${ファイル名}` を実行するターミナルは同じものを使用する

リダイレクトした後にターミナルをキープしておき、編集後にまたそのターミナルで作業を再開するようにすると、 `su` などしない限りはユーザの間違いは起こらなくなります。

#### 2020/12/17 追記: @nii_yan さまコメントより

Crontab を反映させる前に、変更した部分が正しいかどうかを diff コマンドで確認すると、修正間違いも防ぐことができます。

```sh
diff <(crontab -l) /tmp/file.txt
```

コメントくださった方、ありがとうございます。

## 調子に乗っていた説

私は以前に `crontab -e` のタイポで `crontab -r` を打ってしまった方の記事を読んだことがありました。

@NACK さまの記事: https://qiita.com/NACK/items/c0c0feda4e7a8030346f

この記事をまだ見ていないよという方は一度開いてみてください。

---

開きましたか？

そうです。 [本番環境でやらかしちゃった人 Advent Calendar 2019](https://qiita.com/advent-calendar/2019/yarakashi-production) の記事なんです。

その記事を読んで以来、私は Crontab の変更にあたって Crontab を直接編集することはせず、 `crontab -l > ${ファイル名}` でファイルにリダイレクトし、ファイルを編集してから `crontab ${ファイル名}` で反映させる方法を採用しています。

> 「私ちゃんとローカルで編集してる、えらい！」
>
> 「Crontab のコマンドもばっちり、えらい！」
>
> 「やらかしちゃった人の経験を活かして自分はやらかさないように気を付けるぞ！」

こんなことを思いながら **調子に乗って作業していた** んです。

その結果、今年のカレンダーにデビューすることになってしまいました。

調子に乗るのはよくありません。

## さいごに

今回のオペミスを受けて以来、私自身、物事に謙虚になることを心がけています。
本番サーバでの作業にかかわらず、プロダクトのリリースに向けたテストが順調に進んでいるとき、いつもやっている定常作業をするときなど。
「これはスケジュール余裕ですね！」とか言った 30 分後にバグが見つかってリリースが延期されるようなことも経験してきました。

これから仕事をしていくにあたり、常に想定外の事態に備えて、ゴールが見えても、ゴールできることが読めても、ゴールするまでは謙虚な姿勢を持つようにしていきたいと思います。

---

明日は [@hoshi_kouki](https://qiita.com/hoshi_kouki) 様による、「テストしたつもりになってバグらせたことに関して」の記事です。
お楽しみにお待ちくださいませ。

最後までお読みいただきありがとうございました :wink: