2026年8月18日

2026年8月18日

AppArmorのプロファイル作成と管理方法|WordPressサーバーで使う確認・作成・調整の手順

AppArmorのプロファイルは、ゼロから手書きするより、aa-genprof で実際の動作を記録しながら作り、complain(記録のみ)モードで様子を見てからenforce(強制)モードに切り替えるのが安全な進め方です。既存のプロファイルを直したいときは、本体ではなく /etc/apparmor.d/local/ の追加用ファイルに書きます。この記事では、Ubuntu/DebianのWordPressサーバーを例に、状態の確認、拒否ログの読み方、MySQLのデータ置き場を変えたときの調整、バックアップ用スクリプトのプロファイル作成までを解説します。

AppArmorの仕組みと状態の確認

AppArmorは、プログラムごとに「読み書きしてよいファイル」「実行してよいプログラム」「使ってよいネットワーク」などを定めたプロファイルで動作を制限する仕組みです。RHEL系のSELinuxがファイルに付けたラベルで判断するのに対し、AppArmorはファイルのパスで判断するため、プロファイルを読めば何が許可されているかが分かりやすいのが特徴です。UbuntuやDebianでは標準で有効になっています。

# 読み込まれているプロファイルと、制限されているプロセスの一覧
sudo aa-status

# プロファイルの本体が置かれている場所
ls /etc/apparmor.d/

aa-status の出力では、各プロファイルが enforce(違反を拒否して記録)か complain(拒否せず記録だけ)かが分かります。プロファイルの作成や切り替えに使う aa-genprof、aa-logprof、aa-complain、aa-enforce などは apparmor-utils パッケージに含まれるので、入っていなければ sudo apt install apparmor-utils で導入します。

注意したいのは、NginxやApache、PHP-FPMといったWordPressの中心的なプログラムに、標準ではプロファイルが用意されていない場合が多いことです。プロファイルが無いプログラムはAppArmorの制限を受けません。どのプログラムに何が適用されているかは、ディストリビューションやパッケージのバージョンによって異なるため、aa-status で実際に確認してください(2026年10月現在)。

ネットワークで待ち受けているのに制限されていないプロセスは、次のコマンドで一覧できます。

sudo aa-unconfined

AppArmorが原因かを見分ける

パーミッションは正しいのに「Permission denied」で失敗する場合、AppArmorによる拒否の可能性があります。拒否はカーネルのログに記録されます。

# カーネルログから拒否を探す
sudo journalctl -k | grep 'apparmor="DENIED"'

# auditd を入れている環境ではこちらにも記録される
sudo grep 'apparmor="DENIED"' /var/log/audit/audit.log

記録は次のような形です。

apparmor="DENIED" operation="open" profile="/usr/sbin/mysqld" name="/data/mysql/ibdata1" requested_mask="r" denied_mask="r"

profile がどのプロファイルで止められたか、name が対象のファイル、requested_mask が求めた操作(r は読み取り、w は書き込み)を表します。この例なら「mysqldのプロファイルが /data/mysql/ 配下の読み取りを許していない」と読めます。ログに何も出ていなければ、原因はAppArmor以外にあると考えて、通常のパーミッションやサービスの設定を確認します。

既存のプロファイルを調整する: MySQLのデータ置き場を変えた場合

WordPressのサーバーで実際に起きやすいのが、ディスク容量の都合でMySQLのデータディレクトリを別のディスクに移したら、MySQLが起動しなくなるケースです。Ubuntuの mysql-server パッケージには mysqld 用のプロファイルが同梱されていることが多く、許可されているのは標準の /var/lib/mysql/ などに限られるためです(MariaDBのパッケージでは扱いが異なることがあります)。

このとき、/etc/apparmor.d/usr.sbin.mysqld 本体を書き換えるのは避けます。パッケージの更新で上書きされたり、更新時に差分の確認を求められたりするためです。多くの同梱プロファイルは、/etc/apparmor.d/local/ 配下の同名ファイルを読み込むように作られているので、追加の許可はそちらに書きます。

# /etc/apparmor.d/local/usr.sbin.mysqld に追記
/data/mysql/ r,
/data/mysql/** rwk,
# プロファイルを再読み込み
sudo apparmor_parser -r /etc/apparmor.d/usr.sbin.mysqld
sudo systemctl restart mysql

** はサブディレクトリを含むすべてのファイル、* は1階層のみを表します。k はファイルのロックの許可で、データベースのように排他制御を行うプログラムでは必要になります。本体の末尾に local/ を読み込む行(include if exists <local/usr.sbin.mysqld> など)があるかを事前に確認しておきます。この行が無いプロファイルでは、local/ に書いても読み込まれません。データディレクトリの移動そのものは、事前にバックアップを取り、検証用サーバーで手順を確かめてから行ってください。

新しいプロファイルを作る: バックアップスクリプトの例

ここでは、WordPressのファイルを固めて保存する自作スクリプト /usr/local/bin/wp-backup.sh を、必要なファイルにしか触れられないように制限してみます。外部から渡されたデータを扱うスクリプトや、root権限で定期実行するスクリプトほど、制限する意味が大きくなります。

1. aa-genprof で記録しながら作る

sudo aa-genprof /usr/local/bin/wp-backup.sh

aa-genprof を起動したら、別のターミナルでスクリプトを普段通りに実行します。終わったら元の画面に戻ってスキャンを指示すると、記録された操作ごとに「許可する」「拒否する」「パスを一般化する(* や ** に置き換える)」などを選ぶ画面になります。選択肢の表記はバージョンによって異なりますが、内容を読んで、業務上必要なものだけを許可します。終了すると、/etc/apparmor.d/usr.local.bin.wp-backup.sh のように、パスの / を . に置き換えた名前でプロファイルが保存されます。

2. 生成されたプロファイルを読む

生成結果はおおむね次のような形になります。環境によって含まれる行は変わるので、これは読み方の例として見てください。

abi <abi/3.0>,
include <tunables/global>

profile wp-backup /usr/local/bin/wp-backup.sh {
  include <abstractions/base>
  include <abstractions/bash>

  /usr/local/bin/wp-backup.sh r,
  /usr/bin/bash ix,
  /usr/bin/date ix,
  /usr/bin/tar ix,
  /usr/bin/gzip ix,

  /var/www/html/ r,
  /var/www/html/** r,
  /var/backups/wp/ rw,
  /var/backups/wp/** rw,
}

include <abstractions/...> は、多くのプログラムが共通して必要とする許可(共有ライブラリの読み込みなど)をまとめたものです。ix は、そのプログラムを同じプロファイルの制限下で実行するという意味です。WordPressのファイルは読み取り(r)だけ、保存先だけに書き込み(w)を許しているので、スクリプトに不具合や乗っ取りがあっても、WordPressのファイルを書き換えたり、別の場所へ書き出したりはできません。

ux(制限なしで実行)が含まれていたら、そこから先は一切制限されないことを意味するので、本当に必要かを見直します。

3. complainモードで様子を見てからenforceにする

# 記録だけのモードにする
sudo aa-complain /etc/apparmor.d/usr.local.bin.wp-backup.sh

# 数日から1週間ほど通常運用し、記録された操作をプロファイルに反映
sudo aa-logprof

# 問題がなければ強制モードへ
sudo aa-enforce /etc/apparmor.d/usr.local.bin.wp-backup.sh

月に1度だけ動く処理や、エラー時にだけ通る分岐は、最初の記録で漏れがちです。complainモードの期間を設けて aa-logprof で取り込むと、enforceにした後の「たまにしか起きない失敗」を減らせます。手でプロファイルを編集したときは、sudo apparmor_parser -r <プロファイルのパス> で再読み込みします。構文に誤りがあればここでエラーになります。

なお、データベースのダンプのようにソケットやネットワークを使う処理を加えると、そのための許可も必要になります。処理を追加したら、もう一度complainモードで記録し直すのが近道です。

プロファイルを止める・外す

# 一時的に記録だけのモードへ(切り分け用)
sudo aa-complain /etc/apparmor.d/usr.sbin.mysqld

# プロファイルを無効化(disable/ にリンクを作り、読み込みを外す)
sudo aa-disable /etc/apparmor.d/usr.local.bin.wp-backup.sh

原因の切り分けでは、無効化よりもcomplainモードへの切り替えを勧めます。制限は外れますがログは残るため、何が拒否されていたかを後から確認できます。調査が終わったらenforceに戻すことを忘れないよう、作業記録に残しておきます。AppArmor全体を止める方法もありますが、Snapで入れたアプリケーションやDockerのコンテナなど、AppArmorを前提に動いているものへの影響もあるため、避けたほうが無難です。

まとめ

  • aa-status で何がenforce・complainで制限されているかを確認する。WordPress周りのプログラムは標準で未制限のことも多い
  • 「Permission denied」の原因がAppArmorかは、カーネルログの apparmor="DENIED" で判断する
  • 同梱プロファイルの調整は本体ではなく /etc/apparmor.d/local/ に書き、apparmor_parser -r で反映する
  • 新しいプロファイルは aa-genprof で作り、complainモードで運用してから aa-logprof で整え、enforceにする
  • 切り分けは無効化よりcomplainモードへの切り替えを使い、終わったら戻す

お気軽にご相談ください

お見積りへ お問い合わせへ
▲