はじめに
Ansible Automation Platform (AAP) のコンテナ版インストール環境で、プロジェクトのソースコントロールタイプを Manual にして playbook を手動配置したところ、プロジェクト・フォルダにファイルは存在しているのに、ジョブテンプレート作成時の Playbook 選択肢に一部のファイルが表示されないという事象に遭遇しました。
原因を調べたところ、「playbook として認識される条件」と「SELinux のファイルコンテキスト」という 2 つの要素が関係していることが分かったので、確認結果とあわせてまとめます。
コンテナ版 AAP は各コンポーネントが Podman コンテナとして動作するため、従来の RPM 版とは異なり SELinux のコンテナ関連コンテキスト(container_file_t)がファイルアクセスの可否を左右する点がポイントです。
動画
当記事を60秒弱で解説した動画です。
環境
- Red Hat Enterprise Linux 10
- Ansible Automation Platform 2.6(コンテナ版インストール)
- インストールユーザー:
ansible - SELinux: Enforcing モード
Ansible Automation Platform のプロジェクト
Ansible Playbook などの設定ファイル群を管理・連携するためのリポジトリ(保管場所)です。
プロジェクトのフォルダ
プロジェクトのフォルダは
/<AAP インストールフォルダ>/aap/controller/data/projects で定義されます。
下記は test プロジェクトの作成画面です。
ソースコントロールのタイプで Manual を選択することで、playbooks 手動配置の設定となります。
上記の環境では /home/ansible 下でインストールを実行しています。Project base path は /home/ansible/aap/controller/data/projects が設定されており、変更することができません。
(プロジェクトは Git リポジトリーを保持している環境であれば、ソースコントロールのタイプに Git を選択することが多いと思います。検証環境や閉域環境で playbook を試したい場合に Manual が便利ですが、今回のような SELinux 起因の引っ掛かる箇所あります。)
SELinux
SELinux(Security-Enhanced Linux)は、Linux に追加されたセキュリティ強化機能です。
通常のファイルパーミッション(DAC: 任意アクセス制御)による判定を通過した後に、SELinux ポリシー(MAC: 強制アクセス制御)による判定が行われます。
ユーザー
↓
ファイル権限 (rwx / 所有者) ← ここで拒否されれば Permission denied
↓
SELinux ポリシー ← ここで拒否されても Permission denied
↓
アクセス許可
ls -l で見えるパーミッションが正しくても、SELinux で拒否されればアクセスできません。今回のように「所有者もパーミッションも同じなのに挙動が違う」場合は SELinux を疑うのが定石です。
コンテキスト
SELinux の重要な概念です。すべてのファイル・プロセスにはラベル(コンテキスト)が付いており、ls -Z で確認できます。
unconfined_u:object_r:container_file_t:s0
(ユーザー : ロール : タイプ : レベル)
このうちアクセス制御の中心となるのが 3 番目のタイプです。今回登場するタイプは次の 2 つです。
| タイプ | 意味 |
|---|---|
container_file_t |
コンテナプロセスからの読み書きが許可されるファイル |
user_home_t |
ユーザーのホームディレクトリ配下の一般ファイル。コンテナプロセスからはアクセス不可 |
コンテナ版 AAP では、Controller のタスク処理(プロジェクトの同期や playbook 一覧の取得)が Podman コンテナ内のプロセスとして実行されます。コンテナプロセスは SELinux 的に container_t ドメインで動作するため、読めるのは原則 container_file_t が付いたファイルだけです。user_home_t のファイルは、パーミッション上は読めるはずでも SELinux に拒否されます。
コンテキストの継承
SELinux では、ファイルを新規作成すると通常は親ディレクトリのコンテキストを継承します。
ディレクトリ自体が container_file_t なら、その中で作成したファイルにも container_file_t が付与されます。
実験
プロジェクト・フォルダに playbook を配置
$ pwd
/home/ansible/aap/controller/data/projects/test
$
$ ls -lZ
total 8
-rw-r--r--. 1 ansible ansible unconfined_u:object_r:container_file_t:s0 0 Jul 18 02:06 test.yml
-rw-r--r--. 1 ansible ansible unconfined_u:object_r:container_file_t:s0 359 Jul 18 02:08 test1.yml
-rw-r--r--. 1 ansible ansible unconfined_u:object_r:user_home_t:s0 359 Jul 18 02:08 test2.yml
3 つのファイルの状態を整理すると次の通りです。
-
①
test.yml— 中身が空のファイル
SELinux のコンテキストはcontainer_file_t -
②
test1.yml— ping モジュールを実行する playbook
- name: 接続確認(詳細表示)
hosts: localhost
gather_facts: false
become: false
tasks:
- name: 接続先情報表示
debug:
msg:
- "inventory_hostname = {{ inventory_hostname }}"
- "ansible_host = {{ ansible_host | default('not set') }}"
- name: SSH 到達確認
ansible.builtin.ping:
SELinux のコンテキストは container_file_t
- ③
test2.yml—test1.ymlと中身は同一。ただしホームディレクトリで作成後mvで配置
SELinux のコンテキストはuser_home_t
この場合、Ansible Automation Platform では ①〜③ で認識差異が発生します。
ジョブテンプレートの作成で確認
test プロジェクトのジョブテンプレートの作成画面です。
プロジェクト・フォルダには 3 つの playbook(test.yml, test1.yml, test2.yml)が存在していますが、テンプレートでは test1.yml のみしか選択肢に上がってきていません。
表示されない理由は、ファイルごとに異なります。
| ファイル | 表示 | 理由 |
|---|---|---|
| test.yml | ✕ | 中身が空で、playbook として妥当な YAML ではないため |
| test1.yml | ○ | コンテキスト・内容ともに問題なし |
| test2.yml | ✕ |
user_home_t のため、コンテナプロセスがファイルを読めない(内容の妥当性以前の問題) |
AAP は playbook 一覧を生成する際、プロジェクト配下の YAML ファイルを走査し「playbook として解釈できるもの」だけを候補に載せます。空ファイルや構文的に playbook でないファイルは除外されます(①)。user_home_t のファイルは、ディレクトリ一覧の取得(readdir)自体は成功するものの、ファイルの読み取りが SELinux に拒否されるため候補から除外されます(③)。
対処1: 空ファイルに内容を入れる(① への対処)
test.yml に test1.yml の内容をコピーします。
$ cp test1.yml test.yml
$ ls -lZ
total 12
-rw-r--r--. 1 ansible ansible unconfined_u:object_r:container_file_t:s0 359 Jul 18 02:08 test.yml
-rw-r--r--. 1 ansible ansible unconfined_u:object_r:container_file_t:s0 359 Jul 18 02:08 test1.yml
-rw-r--r--. 1 ansible ansible unconfined_u:object_r:user_home_t:s0 359 Jul 18 02:08 test2.yml
対処2: SELinux コンテキストを付与する(③ への対処)
test2.yml に container_file_t コンテキストを付与します。
$ chcon -t container_file_t test2.yml
$ ls -lZ
total 12
-rw-r--r--. 1 ansible ansible unconfined_u:object_r:container_file_t:s0 359 Jul 18 02:08 test.yml
-rw-r--r--. 1 ansible ansible unconfined_u:object_r:container_file_t:s0 359 Jul 18 02:08 test1.yml
-rw-r--r--. 1 ansible ansible unconfined_u:object_r:container_file_t:s0 359 Jul 18 02:08 test2.yml
3 つの playbook すべてがジョブテンプレートの選択肢に表示されるようになりました。
補足: chcon は一時的な変更
chcon によるコンテキスト変更は、ファイルシステムの再ラベル付け(restorecon の実行や touch /.autorelabel 後の再起動など)で元に戻ってしまいます。恒久的に運用するのであれば、semanage fcontext でポリシー側にルールを登録しておくのが安全です。
# ルールの登録(projects 配下を container_file_t にする)
$ sudo semanage fcontext -a -t container_file_t "/home/ansible/aap/controller/data/projects(/.*)?"
# 登録したルールに従ってラベルを適用
$ sudo restorecon -Rv /home/ansible/aap/controller/data/projects
これで、以降 restorecon が実行されても container_file_t が維持されます。
まとめ
- コンテナ版 AAP の Manual プロジェクトで playbook がジョブテンプレートに表示されない場合、原因は大きく 2 つ
- playbook として妥当でない(空ファイル、構文エラーなど)
-
SELinux コンテキストが
container_file_tでないため、コンテナプロセスがファイルを読めない
- パーミッションが正しいのに挙動がおかしいときは
ls -Zでコンテキストを確認する - 同一ファイルシステム内の移動の場合
mvはコンテキストを持ち込むので注意。プロジェクト・フォルダ内で新規作成するか、cpを使う - 応急処置は
chcon -t container_file_t、恒久対応はsemanage fcontext+restorecon
コンテナ版 AAP では「SELinux × コンテナ」起因の挙動差に遭遇しがちです。
同じ事象に遭遇された方の参考になれば幸いです。


