Ubuntu日和

【第40回】Linux管理の必須スキル!root権限とCLIのテキストエディタについて知る

 前回は、UbuntuにおけるGUIのテキストエディタについて紹介した。ここで述べたように、Linuxのシステム管理には、GUIではなく、CLIのテキストエディタの使用が推奨されている。そこで予告通り、今回はその理由と、具体的なCLIのテキストエディタの使い方について解説しよう。

なぜCLIを使わなければならないのか

 Linuxはシステム上に複数のユーザーが存在する、マルチユーザーOSだ。そしてユーザーには、大きく分けて2種類が存在する。あらゆる権限を持ったrootユーザーと、権限を制限されたそれ以外のユーザー(一般ユーザー)だ。普段ログインして使っているのは制限された一般ユーザーであるため、たとえば自分のホームディレクトリ以外にはデータを書き込めない。

 このため一般ユーザーでは、アプリのインストールなど、システムを変更するタイプの作業が行なえない。そこでこうした操作を行なう時のみ、sudoコマンドで一時的にrootに昇格するのがUbuntuのお作法だ。前回の繰り返しとなるが、Linuxはさまざまな設定をテキストファイルの形で持っており、設定変更はテキストエディタで書き換えることで行なう。つまりシステムの設定を変更する場合は、sudoを使ってテキストエディタを起動する必要があるわけだ。

「なるほど。sudo geditとかやって、Geditをroot権限で起動すればいいんだな!?」

 そう思った方もいるかもしれない。まあ確かに、ターミナルから「sudo gedit」を実行すると、root権限でGeditが起動する。ただしこれは原則としてやってはいけない。

 一般的にGUIのアプリは、設定ファイルをホームディレクトリ内に自動的に作成する。そのためGUIのアプリをsudoで起動してしまうと、一般ユーザーのホームディレクトリ内のファイルが、rootによって置き換えられてしまうことがあるのだ。もしもこの現象が起きてしまうと、以後の利用に際して、意図しないトラブルが起きる可能性もある。

 オンラインフォーラムなどでは、rootでGUIを使った結果、GUIへのログインそのものができなくなってしまったという話も目にするほどだ。そのためUbuntuの「ドキュメントにも「You should never use normal sudo to start graphical applications as root.」と、はっきり書かれている。

少し古いUbuntu、16.04 LTSでsudo geditを実行してみた。ホームディレクトリ内の.dbusディレクトリと、geditの設定ディレクトリがroot権限で作成されてしまっているのが分かる

「その説明は正しくない。昇格後の環境変数HOMEを置き換える-Hオプションを指定すれば、この問題は回避可能。そして最近のUbuntuのsudoは、デフォルトで-Hオプションを指定した時と同じ挙動をするから、意図的に-Eオプションを指定しない限り、ホームディレクトリの汚染問題は発生しない!」

 こう考えた貴方は、かなりのsudoマニアだ。いきなり前言を翻してしまうが、最近のUbuntuは上記の問題を回避して、sudoでGUIアプリを起動することができる。だがそもそもLinuxのお約束として、root権限でGUIセッションやGUIアプリは起動しないということになっているのだ。その理由は、GUIアプリはCLIアプリと比較して、非常に大きく複雑なためだ。こうした「余計な機能があるもの」を、必要以上に強い権限で起動することは、それだけでセキュリティリスクとなる。

「じゃあなんでGUIでroot権限を使うための、gksuコマンドがあるんだよ」

 こんなツッコミを思いつく人もいるだろう。ネットで検索すると、gksuを使ってアプリを起動する例を紹介している記事もたくさん見つかる。だがgksuが使えたのは昔の話で、18.04 LTS以降のUbuntuでは廃止されている。もはやこのコマンドは、存在そのものを忘れてしまっていいだろう。そうなると、次の貴方のセリフはこうだ。

「何を言ってるんだ、gksuの後継のpkexecコマンドがあるだろう?」

 確かにpkexecを使えば、GUIでもroot権限でアプリを起動できる。だがpkexecはsudoのように、任意のコマンドをroot権限で実行できるわけではなく、事前に「ポリシー」を作成しておく必要がある。

pkexecでGeditを起動しようとした例。パスワードの入力ダイアログこそ表示されるものの、無情にも起動は失敗する

 たとえば「ソフトウェアとアップデート」がUbuntuのリポジトリの設定をGUIから変更できるのは、/usr/share/polkit-1/actions/com.ubuntu.softwareproperties.policyというポリシーが設定されているからだ。

GUIアプリからroot権限を行使する例。これはソフトウェアとアップデートで、使用するリポジトリを変更して適用しようとしたところ

 そしてGeditのポリシーはデフォルトで用意されていないため、pkexecでGeditを起動することはできない。もちろんポリシーを自作すれば可能なのだが、こうしたpkexecの利用は、Ubuntuの開発者的に非推奨とされている。

 少し長くなってしまったのでまとめよう。

  • root権限をGUIで使うこと自体は可能。
  • ただしセキュリティ面やさまざまな事情から推奨されない

 これが、Linuxシステムを管理するためには、CLIが推奨される理由だ。

CLIにおける標準エディタ

 背景の説明が終わったので、いよいよ本題、CLIにおけるテキストエディタの話をしよう。Linuxの標準的なCLIエディタと言えば、なんと言っても「vi」……と思うかもしれない。ところがUbuntuの標準のCLIエディタには「nano」が採用されている。

 前回も少し紹介したが、viは操作方法が独特すぎるのがその理由だ。初心者はうっかりviを起動してしまったが最後「カーソルが動かない」、「文字が入らない」、「終了できない」のハマり状態になり、しめやかにターミナルウィンドウの×ボタンをクリックすることになるのがLinuxの通過儀礼と言っても過言ではない。

 そこで「ユーザーに優しい」を謳うUbuntuとしては、機能的には劣るものの、一般的なテキストエディタと同じような操作感を持つnanoを、デフォルトエディタに採用しているというわけだ。

 nanoは同名の「nano」コマンドで起動する。デフォルトでは新規バッファが開かれるが、引数にファイル名を指定すると、そのファイルを直接開いてくれる。nanoをわざわざ使うシチュエーションというのは、システムの設定を変更する時であろうから、以下のようにsudoと対象のファイルを指定する使い方が多くなるだろう。

/etc/hostsファイルをnanoで編集する例
$ sudo nano /etc/hosts
なんとnanoは、カーソルキーでカーソルが動くし、キーボードを押すと押した文字がそのまま入力される。画期的!! ただnanoもnanoで、保存のショートカットがCtrl+O、ペーストがCtrl+Uなど、「viの操作性がとか、どの口が言うのか?」といろいろ思うところはあるのだが

 ちなみにnanoを採用しているのはUbuntuだけではない。現在ではFedoraも、デフォルトのエディタをviからnanoへ変更している。その理由も同様で、リリースノートから引用すると「having a default editor that doesn't require specialist knowledge to use.」とのことだ。

標準エディタをnanoからviに変更する

 /etc/sudoersというファイルがある。これはsudoコマンドが参照するファイルで、どのユーザーに、どのコマンドの実行を許可するか、パスワード入力を省略できるか、などの設定が記述されている。

 Ubuntuの場合はsudoグループにさえ所属していれば、パスワード入力こそ必須なものの、無制限にsudoの行使が可能なため、このファイルを特に編集する必要はない。

 だが、このファイルに独自のカスタマイズを施したい場合もある。たとえばサーバーのバックアップ用のユーザーには、rsyncコマンドに限って、パスワードなしでsudoを許可したい……といった具合だ[^1]。

 ところがこのファイルを直接書き換えるのは推奨されない。なぜなら万が一ミスタイプなどをしてしまい、書き換えに失敗すると、システムが正しく動作しなくなってしまうからだ。「sudo nano /etc/sudoersでファイルを直接編集する」→「タイプミスに気づかず保存終了」→「エラーで以後sudoできなくなる」→「修正もできひん……詰んだ……」はあるあるだ。

 そこでvisudoというコマンドが用意されている。これは、sudoersを安全にエディタで書き換えるためのフロントエンドだ。visudoはsudoersファイルをロックして編集が衝突しないようにしてから、エディタを起動する。そしてファイルの保存時には構文チェックを行ない、問題がない場合に限って元ファイルと置き換えるという挙動をする。安全のためにも、sudoersを編集する時は直接エディタで開かず、visudoを使うようにしよう。

 さて、visudoという名前からも分かる通り、このコマンドはviでsudoの設定を書き換えることを前提にしている。しているのだが、Ubuntuの場合は容赦なく標準エディタのnanoが起動する。

sudo visudoを実行してみた状態。visudoのviとはいったい……うごごご……

 これが気に入らない人も多いのではないだろうか。そもそもnanoが初心者に優しいとは言え(諸説あります)、Linuxに慣れている人からすれば、むしろviの方が使いやすいだろう(筆者もそうだ)。前フリが長くなったが、デフォルトのエディタをnanoからviに変更する方法を紹介しよう。

 Ubuntuには、「機能」に対する「実装」を自由に切替える仕組みがあり、これをAlternativesと呼ぶ。デフォルトでは「editor」という機能に対して、nanoという実装が設定されているわけだ。なのでここをviに変更すればいい。

 ちなみに先週からvi、viと言っているが、現在オリジナルのviがインストールされてる環境は、おそらく存在しないだろう。多くの環境では、viから派生した「Vim」が、viのかわりに使われているのではないだろうか。Ubuntuではvim-tinyというパッケージが、viのかわりを務めている。

 本来Vimは非常に高機能なエディタなのだが、vim-tinyはviの代替となることを目的として作られた、その名の通りVimのミニマルなビルドだ。vim-tinyはいろいろと機能が足りないので、最初に(本来の)vimパッケージを入れておくことを推奨する。

Vimをインストールする
$ sudo apt install -y vim

 Alternativesは、実際のコマンドに対して、機能名のシンボリックリンクを作成することで、実装を切り替えている。そしてこのシンボリックリンクの生成・削除・管理を行なうコマンドがupdate-alternativesだ。

 既存のシンボリックリンクを変更するには、「--config」オプションと、変更したい機能名を引数に指定する。以下のようにコマンドを実行しよう。

/usr/bin/editorというシンボリックリンクの向き先を切り替える
$ sudo update-alternatives --config editor
alternative editor (/usr/bin/editor を提供) には 4 個の選択肢があります。

  選択肢    パス              優先度  状態
------------------------------------------------------------
* 0            /bin/nano            40        自動モード
  1            /bin/ed             -100       手動モード
  2            /bin/nano            40        手動モード
  3            /usr/bin/vim.basic   30        手動モード
  4            /usr/bin/vim.tiny    15        手動モード

現在の選択 [*] を保持するには <Enter>、さもなければ選択肢の番号のキーを押してください: 3
update-alternatives: /usr/bin/editor (editor) を提供するためにマニュアルモードで /usr/bin/vim.basic を使います

 使える実装として、標準のnano、古典的ラインエディタのed、vi代替であるvim.tiny、そして先ほどインストールしたvim.basic(Vim)がリストアップされる。ここでは「3」を入力して、vim.basicを選択しよう。これ以後、デフォルトのエディタとしてVimが使われるようになる。

 ちなみに「vi」も、実は機能名だ。viコマンドでvim-tinyが起動するのも、Alternativesの設定による。Ubuntuにはvi系エディタの実装として、vim-tiny/vimのほかに、nviやneovimというパッケージも存在する。もしもこれらのエディタをviとして使いたい場合は、パッケージをインストールした後に、以下のコマンドを実行してみよう。

同様に、/usr/bin/viの向き先を切り替える例
$ sudo update-alternatives --config vi

環境変数でエディタを切り替える

 Alternativesを使えば、システム全体でデフォルトのエディタを変更できる。だが複数ユーザーで共有しているサーバーなどでは、システム全体の設定は変更せず、個人的な設定のみに留めたい場合もあるだろう。

 実は多くのCLIコマンドでは、呼び出すエディタを環境変数VISUALとEDITORで指定することができる。たとえば「git commit」コマンドでコミットログを記述する際に起動するエディタなどが、これに該当する。エディタとしてVimを使いたいのであれば、以下のコマンドを実行しよう。

環境変数VISUALとEDITORの両方にvimを設定する例。設定する時は誤動作防止のため、両方に同じ内容を設定すること
$ export VISUAL=/usr/bin/vim
$ export EDITOR=/usr/bin/vim

 なぜ環境変数が2つあるかと言うと、大昔の環境では、全画面を占有して動くタイプのビジュアル(スクリーン)エディタと、その機能がなくても動く古典的なラインエディタを区別する必要があったためだ。現在ではビジュアルエディタが動かない環境はないと思われるため、これらを区別する意味は本来ない。本来ないはずなのだが、コマンドによって内部的に環境変数の優先度が異なったり、どちらか片方しか参照しないということがある。そのためもしも環境変数でエディタを指定するのであれば、両方の環境変数に同じ内容を指定しておくのが安定だろう。

sudoeditのすすめ

 繰り返しになるが、sudoを使うと、対象のプロセスをroot権限で起動できる。そのおかげで設定ファイルの編集が可能になるわけだが、ここで1つ問題が出てくる。それはエディタでテキスト編集以外のことができる場合、root権限でその機能を行使できてしまうという点だ。

 特に外部コマンドを呼び出せるエディタの場合、root権限で任意のコマンドを実行できてしまう。VimやEmacsはファイラーとして使うこともできるため、これをsudoで起動することは、自由にファイルのコピーや削除ができることと同義になる。CLIを使う理由は、機能豊富なGUIアプリをsudoで起動するのはセキュリティリスクだからだと説明した。ならばCLIと言えども、VimやEmacsのような高機能エディタをsudoで起動しては、本末転倒と言えるだろう。

 またroot権限でエディタを起動すると、エディタの設定はrootユーザーのものが読み込まれる。rootユーザーは普段使いしないため、自分の環境とは異なり、エディタの設定がきちんと整備されていない場合が多いだろう。すると必然的に、エディタをデフォルト、ないしそれに近い状態で使うことになる。独自のキーバインドなどを設定して効率化を図っている場合、それが反映されないのは辛い。かといってrootユーザー用に設定を別途メンテナンスするのも面倒だ。

 そこでおすすめしたいのが、sudoeditコマンドだ。sudoeditは簡単に説明すると、一般ユーザーの権限で実行したエディタで、root権限が必要なファイルの書き換えを実現するものだ。

 sudoeditコマンドの引数に、編集したいファイル名を指定して実行しよう。するとまず/var/tmp以下のディレクトリに、そのファイルのコピーが作成される。このテンポラリファイルは、sudoeditを実行したユーザーが所有し、そのパーミッションは600になっている。そのため一般ユーザー権限で起動したエディタで自由に編集できる上に、第三者に盗み見られることもない。そしてエディタを終了した際に、sudoeditは元ファイルとテンポラリファイルを比較し、もしも差分があれば上書きして置き換えるという挙動をする。

sudoeditで/etc/hostsファイルを編集する例
$ sudoedit /etc/hosts
sudoedit起動中に別のターミナルを開き、プロセスツリーを見てみた状態。sudoeditコマンド自体はroot権限で実行されているが、そこからviがmizunoユーザー権限で起動し、/var/tmp/hosts.(ランダムな名前)というファイルを編集中なことが分かる
$ pstree -acu
(...略...)
  └─zsh
      └─sudoedit,root /etc/hosts
          └─sudoedit /etc/hosts
              └─vi,mizuno /var/tmp/hosts.XXGchIQ1

 エディタを一般ユーザー権限で起動できるということは、セキュリティ的に好ましいのはもちろん、自分でカスタマイズした、普段使いの環境をそのまま使えることを意味する。Vimをバリバリにカスタマイズして、ターミナル内で使い倒しているような人には、「sudo vim」より「sudoedit」をオススメしたい。

 さて、勘のいい貴方であれば気づいただろう。

「sudoeditを使えばエディタはユーザー権限で起動するんだから、GUIのエディタを使ってもいいんじゃないの?」

 ここまできて前提を引っくり返すようで恐縮だが、アリかナシかで言えばアリだ。ただしCLIから起動するデフォルトのエディタをGeditに設定することはできないので、環境変数を使って一時的に指定するのがいいだろう。sudoeditで起動するエディタはVISUALとEDITORだけでなく、専用の環境変数SUDO_EDITORでも制御できる。ほかのコマンドへの副作用を抑えるためにも、この環境変数を使うことを推奨する。

Geditを指定してsudoeditを実行する例
$ SUDO_EDITOR=gedit sudoedit /etc/hosts
sudoeditでGeditを起動した状態。一般ユーザー権限のGUIエディタで、システム設定ファイルを書き換えることができる。ただしエディタのプロセス自体はユーザー権限であっても、保存時にはroot権限で上書きが行なわれるため、編集ミスには十分注意すること

 だが環境変数を指定してsudoeditを実行するというとは、CLIを操作しているということにほかならない。サーバーのようにそもそもGUIを持たない環境も多いため、いちいちマウスでウィンドウ切替えるより、腹をくくってCLIのエディタに慣れた方が効率はいいと筆者は思う。


[^1]: ちなみに現在のUbuntuでは、/etc/sudoers.dディレクトリ以下のファイルに設定を分割することができる。事故防止のため/etc/sudoersを書き換えるのではなく、独自設定は別ファイルに分割して設定するのがよいだろう。/etc/sudoers以外のファイルを編集したい場合は、visudoコマンドに-fオプションを指定しよう。