Linuxセキュリティ　capabilityについて理解する

# はじめに
本記事はLinuxのcapabilityについて記載しています。

capabilityを翻訳すると、能力や、機能を意味します。

ビジネスの世界でも[ケイパビリティ](https://ja.wikipedia.org/wiki/%E3%82%B1%E3%82%A4%E3%83%91%E3%83%93%E3%83%AA%E3%83%86%E3%82%A3)という言葉は使用されていますが、Linuxの世界でもcapabilityという言葉が存在します。

## Linuxのcapability
前提としてLinux上のファイルなどオブジェクトに対するアクセス制御は、一般的には以下の2種類があります。

- 任意アクセス制御（DAC：Discretionary Access Control）
    - [ファイルパーミッション](https://ja.wikipedia.org/wiki/%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%83%91%E3%83%BC%E3%83%9F%E3%83%83%E3%82%B7%E3%83%A7%E3%83%B3)を基本とし、オブジェクトのアクセス権を所有者、グループ、その他に分類してアクセス可能なユーザーを制限
    - アクセス制御リスト（ACL：Access Control List）を用いて、特定のユーザーやグループなどに対するACLを設定
- 強制アクセス制御（MAC：Mandatory Access Control）
    - 任意アクセス制御より細かなアクセス制御設定が可能
    - SELinux/AppArmor/SmackなどセキュアOSで実現

Linuxの[**capability**](https://man7.org/linux/man-pages/man7/capabilities.7.html)は、ファイルやプロセスなどのリソースに対して付与される権限の組み合わせを指します。

従来のUNIX実装では、パーミッションチェックを実行するために、特権プロセス（実効ユーザーIDが0）と、非特権プロセス（実効UIDが0以外）に大別できます。特権プロセスはすべてのカーネル許可チェックをバイパスしますが、非特権プロセスはプロセスの資格情報に基づいて認可を受けます。

Linux2.2以降、Linuxは従来スーパーユーザーに関連付けられていた特権を、機能と呼ばれる個別の単位に分割し、個別に有効化および無効化できます。機能はスレッドごとの属性です。

ファイル機能により、ユーザーはより高い権限でプログラムを実行できます。これは、ビットの動作に似ています。スレッド機能は、実行中のプログラム機能の現在の状態を追跡します。

従ってcapabilityを使用することで、rootユーザーを使用することなく、RAWソケットを使用するなどの特権操作が実行できます。

:::note
強制アクセス制御を実現するSELinuxは、米国国家安全保障局 (National Security Agency)によって開発されています。
:::

### getcap
[**getcap**](https://man7.org/linux/man-pages/man8/getcap.8.html)コマンドは、指定された各ファイルの名前とcapabilityを表示します。
`-r`オプションを付与することで、再起的な検索もできます。

`getcap`コマンドの使用例について以下に記載します。

- ファイルのcapabilityを表示
`$ getcap /usr/bin/ping`

```console
/usr/bin/ping cap_net_raw=ep
```

- システム全体のcapabilityを表示
`$ getcap -r / 2> /dev/null`

```console
/usr/lib/x86_64-linux-gnu/gstreamer1.0/gstreamer-1.0/gst-ptp-helper cap_net_bind_service,cap_net_admin=ep
/usr/bin/dumpcap cap_net_admin,cap_net_raw=eip
/usr/bin/fping cap_net_raw=ep
/usr/bin/ping cap_net_raw=ep
```

:::note
上記出力結果を踏まえて、/usr/bin/pingファイルにcap_net_rawというcapabilityが設定されているのが分かります。pingコマンドはRAWソケットとPACKETソケットを使用しています。capabilityという仕組みを用いて、必要な権限だけを与えています。
:::

### capsh
[**capsh**](https://man7.org/linux/man-pages/man1/capsh.1.html)コマンドは、Linuxのcapability管理ができるコマンドです。
オプションの注意点としては、指定された順序で作用します。

- 現在のcapabilityの状態を表示
`$ capsh --print`

:::note
capshコマンドを使用して、スーパーユーザーなどrootユーザーに対する制限も可能です。
:::

## コンテナのcapability
コンテナでもcapabilityを設定することができます。

Kubernetesの公式ドキュメント[^1]より、[Set capabilities for a Container](https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#set-capabilities-for-a-container)を参考にしながら試してみましょう。

以下２つのPodをデプロイします。

- pods/security/security-context-3.yaml

```yaml
apiVersion: v1
kind: Pod
metadata:
  name: security-context-demo-3
spec:
  containers:
  - name: sec-ctx-3
    image: gcr.io/google-samples/node-hello:1.0
```

- pods/security/security-context-4.yaml

```yaml
apiVersion: v1
kind: Pod
metadata:
  name: security-context-demo-4
spec:
  containers:
  - name: sec-ctx-4
    image: gcr.io/google-samples/node-hello:1.0
    securityContext:
      capabilities:
        add: ["NET_ADMIN", "SYS_TIME"]
```

デプロイしたPodのコンテナにログインを行い、`capsh --print`コマンドを実行します。

- security-context-demo-3

```console
Current: = cap_chown,cap_dac_override,cap_fowner,cap_fsetid,cap_kill,cap_setgid,cap_setuid,cap_setpcap,cap_net_bind_service,cap_net_raw,cap_sys_chroot,cap_mknod,cap_audit_write,cap_setfcap+eip
Bounding set =cap_chown,cap_dac_override,cap_fowner,cap_fsetid,cap_kill,cap_setgid,cap_setuid,cap_setpcap,cap_net_bind_service,cap_net_raw,cap_sys_chroot,cap_mknod,cap_audit_write,cap_setfcap
Securebits: 00/0x0/1'b0
 secure-noroot: no (unlocked)
 secure-no-suid-fixup: no (unlocked)
 secure-keep-caps: no (unlocked)
uid=0(root)
gid=0(root)
groups=
```

- security-context-demo-4

```console
Current: = cap_chown,cap_dac_override,cap_fowner,cap_fsetid,cap_kill,cap_setgid,cap_setuid,cap_setpcap,cap_net_bind_service,cap_net_admin,cap_net_raw,cap_sys_chroot,cap_sys_time,cap_mknod,cap_audit_write,cap_setfcap+eip
Bounding set =cap_chown,cap_dac_override,cap_fowner,cap_fsetid,cap_kill,cap_setgid,cap_setuid,cap_setpcap,cap_net_bind_service,cap_net_admin,cap_net_raw,cap_sys_chroot,cap_sys_time,cap_mknod,cap_audit_write,cap_setfcap
Securebits: 00/0x0/1'b0
 secure-noroot: no (unlocked)
 secure-no-suid-fixup: no (unlocked)
 secure-keep-caps: no (unlocked)
uid=0(root)
gid=0(root)
groups=
```

上記出力結果の通りに、security-context-demo-4のコンテナに対して、`CAP_NET_ADMIN`と、`CAP_SYS_TIME`が設定されているのが分かります。

:::note
付与されるcapabilityの範囲が異なるため、capabilityによって細分化されたプロセスの特権（root権限）が付与されたことが分かります。
また、Dockerでも`docker run`コマンドを用いてcapabilityを設定することができます。
:::

[^1]:Kubernetes Documentation. [Configure a Security Context for a Pod or Container](https://kubernetes.io/docs/tasks/configure-pod-container/security-context/)

# おわりに
Linuxのセキュリティに興味がある場合は、LPIC303の受験がお奨めです。

LPIC303では、強制アクセス制御などの仕組みについて学ぶことができます。
また、LPIC3については[重要なお知らせ](https://www.lpi.org/ja/lpic-3-version-30-update)の通りに、2022年でVersion2.0が廃止され、現在はVersion3.0に更新されているため、受験する際はご注意ください。

## 参考
- [ capabilities - Linux のケーパビリティ (capability) の概要](https://manpages.ubuntu.com/manpages/bionic/ja/man7/capabilities.7.html)
- [ケイパビリティ](https://wiki.archlinux.jp/index.php/%E3%82%B1%E3%82%A4%E3%83%91%E3%83%93%E3%83%AA%E3%83%86%E3%82%A3)
- [LPIC-3 Exam 303: Security](https://www.lpi.org/ja/our-certifications/exam-303-objectives)