Cortex Data Lake の Log Foward（Syslog転送）機能を利用してS3にログを外部保管する

# ご留意事項
本記事は私の実装事例（検証事例）を共有し、同様の構築を実施される方の効率化を目的としております。私の所属組織ならびにCortex Data Lakeを提供するPalo Alto Networks社が推奨する構成や手順ではありません。
本情報は2021年12月時点のサービス仕様を元にしております。
手順や情報に不備等あれば是非コメントください。

# 本記事でご紹介するもの
Cortex Data LakeのSyslog転送機能を利用し、ログをS3へ保管するための構成例を示します。

# 基盤構成
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/174361/82965730-9dab-188d-9e67-37d1801bfd9e.png)

* TrafficログとThreatログで別ファイルとしてS3に保存する
* Cortex Data LakeのSyslog転送を設定し、EC2のrsyslogでログを受信・ファイルへ出力する
* ログファイルをtd-agent(fluentd）で読み込み、S3 Plugin経由でS3へ保管する
* S3に保管したログファイルの分析を行いたい場合はAthena等を利用する（本手順の範囲外）

# 作業手順

## 1. サーバ証明書取得
* Cortex Data LakeのSyslog転送機能はTSLの暗号化が必要なため、syslogサーバで利用するサーバ証明書を取得します。
* 今回は手軽に実装することを目的とし、[Let's Encrypt](https://letsencrypt.org/ja/)で発行された証明書を使います。
* 利用できるサーバ証明書には以下の制約があります。
    * 暗号化で利用するSyslogサーバのサーバ証明書はOCSPの証明書の有効チェックができる証明書である必要があります。（オレオレ証明書ではダメ）
    * Cortex Data Lake側で[信頼する証明書のリスト](https://docs.paloaltonetworks.com/cortex/cortex-data-lake/cortex-data-lake-getting-started/get-started-with-log-forwarding-app/trusted-root-ca-log-forwarding-app.html#id943bec2e-b271-4999-af50-634bf8b503f2)は公開されています。ただ、証明書チェーンをインポートすることは可能であり、上記の信頼する認証局の証明書である必要はありません。

## 2. 独自ドメイン取得とRoute53への登録
[こちらの記事](https://qiita.com/ymzkjpx/items/ae115ed6d0fd2d383cec)などを参考に、独自ドメインの取得とRoute53の登録を行います。

::: note
今回はAレコードに登録するIPアドレスを固定化したいため、Elastic IPを利用します。
:::
## 3. EC2インスタンスとS3バケットの作成

ログを保管するための[S3バケットを作成します](https://docs.aws.amazon.com/ja_jp/AmazonS3/latest/userguide/create-bucket-overview.html)

パブリックサブネットにEC2を構築します。

* VPC/サブネット/ルートテーブル等の構成要件
     * 一般的なパブリックサブネット構築手順にない独自の構成要件は以下です。
         * インターネットからの80, 443ポートの許可 （サーバ証明書取得のため）
     * インターネットからの6514ポートの許可 （Syslog転送のため）

:::note
Syslog転送のポートは任意のportに設定可能です。
rsyslog.confの設定とCortex Data Lake側のLog Forwarding設定のポート設定を変更してください。
:::

* EC2インスタンス
     * AMI: Amazon Linux 2
     * インスタンスタイプ: t4g.large
     * セキュリティグループ: 80, 443, 6514を許可 （用途等はVPCの設定を参照）、ssh等も必要に応じて許可
     * ロール： ログを保管する[S3バケットへの書き込み権限を設定](https://aws.amazon.com/jp/premiumsupport/knowledge-center/ec2-instance-access-s3-bucket/)

::: note
インスタンスタイプはt2, t3でも問題ありません。x86_64を利用したい場合はt4g以外を利用してください。
また、サイジングもsmall、mediumでも問題無いと思われますが、ログローテーション時など負荷がかかった状態でもログ受信処理が遅れることを避けるためlargeとしています。
:::

構築したEC2に1-2の手順でAレコードに登録したElastic IPをアタッチします。




## 4. 証明書の取得
1. [こちらの手順](https://docs.aws.amazon.com/ja_jp/AWSEC2/latest/UserGuide/SSL-on-amazon-linux-2.html#letsencrypt)を参照し、「Certbot をインストールして実行する」までの作業を実施します。完了すると以下のファイルが作成されます。

```
[root@ip-172-31-47-127 ~]# ll /etc/letsencrypt/live/xxx.com/
total 4
lrwxrwxrwx 1 root root  43 Nov 30 06:39 cert.pem -> ../../archive/xxx.com/cert1.pem
lrwxrwxrwx 1 root root  44 Nov 30 06:39 chain.pem -> ../../archive/xxx.com/chain1.pem
lrwxrwxrwx 1 root root  48 Nov 30 06:39 fullchain.pem -> ../../archive/xxx.com/fullchain1.pem
lrwxrwxrwx 1 root root  46 Nov 30 06:39 privkey.pem -> ../../archive/xxx.com/privkey1.pem
-rw-r--r-- 1 root root 692 Nov 30 06:39 README

```
:::note warn
証明書の有効期限は90日のため、期限切れまでに自動更新するように構成することをお勧めします。
:::

## 5. rsyslogの設定
rsyslogの設定は[rsyslogでのTLS(SSL)によるセキュアな送受信（暗号化のみ）](https://qiita.com/saeki4n/items/198407c8710d769dfa55)を参照しました。
（rsyslogのTLS実装が分かりやすく解説されていて、記事で非常に参考になりました）

rsyslog用のkeyファイルフォルダを作成し、cert.pem chain.pem privekey.pemをコピーします。

```
$ sudo mkdir /etc/rsyslog.d/tls/
$ sudo cp /etc/letsencrypt/live/xxx.com/cert.pem /etc/rsyslog.d/tls/
$ sudo cp /etc/letsencrypt/live/xxx.com/chain.pem /etc/rsyslog.d/tls/
$ sudo cp /etc/letsencrypt/live/xxx.com/privkey.pem /etc/rsyslog.d/tls/
```
:::note
フォルダを新規に作成せず直接参照した方が証明書更新等を考慮すると合理的ですが、pemファイルもrsyslogの設定ファイルの一部として管理することを目的としています。
:::

/etc/letsencrypt/live/xxx.com/chain.pemがCortex Data Lake設定時に必要になるため、手元のPC等にDLします。

rsyslog.confを編集し、MODULEの項目に以下のエントリを追加します。

```
module(
 load="imtcp"
 StreamDriver.Name="gtls"
 StreamDriver.Mode="1"
 StreamDriver.Authmode="anon"
)

input(type="imtcp" port="6514")

global(
 DefaultNetstreamDriver="gtls"
 DefaultNetstreamDriverCAFile="/etc/rsyslog.d/tls/chain.pem"
 DefaultNetstreamDriverCertFile="/etc/rsyslog.d/tls/cert.pem"
 DefaultNetstreamDriverKeyFile="/etc/rsyslog.d/tls/privkey.pem"
)
```
同じrsyslog.confを編集し、Cortex Data Lakeから受信するログを記録するログファイルを指定します。（デフォルト設定だと`/var/log/messages`に出力されます）
RULESの項目を以下のように修正します。

1. `/var/log/messages`のロギング対象からlocal0, local2を除外する（`;local0.none;local1.none`を追加）
1. local0のファシリティを全て任意のログファイル（今回の例は`/var/log/traffic.log`と`/var/log/threat.log`）に記録する設定を追加

```
#### RULES ####

（略）

# Log anything (except mail) of level info or higher.
# Don't log private authentication messages!
*.info;mail.none;authpriv.none;cron.none;local0.none;local1.none    /var/log/messages

（略）

# Cortex Data Lake Log Fowarding
local0.*                                                /var/log/traffic.log
local1.*                                                /var/log/threat.log
```
::: note info
ログのファシリティにはデフォルト（log_user)以外に「local0~local7」を設定可能です。
Cortex Data Lakeの転送設定ごとにファシリティを設定できます。
:::

rsyslogを再起動し、エラーメッセージが出力されていないことを確認します。

```
$ sudo systemctl restart rsyslog
$ sudo systemctl status rsyslog
```

## 6. Cortex Data LakeのLog Forwarding転送設定

Cortex Data Lakeにログインし、左側ペインからLog Forwadingをクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/174361/bac2a2cc-e909-41d2-6ad9-74e08ebd5469.png)
「Syslog」の項目の右側の + ボタン（Display 20 Profilesの右）をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/174361/c766a30c-bb8b-97ed-b754-99da5d8c1413.png)

設定に以下を入力します。

* Name: 任意 （Traffic-logなど）
* SYSLOG SERVER: サーバ証明書を取得したFQDN名
* PORT: 任意（今回はデフォルト6514を利用）
* FACILITY: **LOG_LOCAL0** 　　　注）デフォルトから変更します

Let's Encryptを利用している場合は中間証明書をアップロードする必要があるため、手元PC等にDLした`/etc/letsencrypt/live/xxx.com/chain.pem`ファイルを「+ UPload」ボタンから追加します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/174361/4a0b5bb2-4154-0958-998a-de5001aba8b2.png)

Test Connectionのボタンが有効化します。クリックしてSuccessが出力されることを確認します。（うまくいかない場合はSyslogサーバ側の設定やVPCのルートテーブル等を見直してください）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/174361/8eef2343-5088-67c5-d500-0aaf46d54212.png)

Nextをクリックするとログ形式や取得対象ログを設定する画面が開きます。
FILTERSの項目の + Add をクリックして任意のログタイプを選択します。今回はTrafficログを取得対象として設定しました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/174361/1da748c7-8e6b-4be4-bacf-30a6750c9c79.png)

SAVEボタンが有効化するので、クリックします。
これでログ転送設定のエントリが設定されますが、画面上のステータスはしばらくPROVISONINGと表示され、Syslogサーバへの転送もすぐには始まりません。設定してから5分前後でログが転送されるので、しばらく待ちます。

:::note warn
設定直後（おそらくPROVISIONING中）にログエントリの追加・変更・削除などを追加で実施するとCortex Data Lake側の状態が異常となる場合があります。ステータスが正常になったのを確認してから作業を行なうことお勧めします。
:::
:::note warn
設定後、過去72時間分のログがまとめて転送されます。
初期設定時も含め、Cortex Data Lakeからはログを一行一行転送するわけではなく、まとめてblukで転送する仕様と推測されます。大量のログが出力される場合でも、Syslogサーバ側に大きな処理能力は不要です。（vCPUが2コア程度でも問題ありませんでした）
:::
:::note
FILTERSの項目には複数のログタイプの設定や、クエリによって絞り込んだログの転送を行うなどの設定が可能です。
ログの転送要件に合わせて定義ください。
:::

今回はThreatログを別のログファイルで保管したいので、再度　+ ボタンをクリックしてエントリを追加します。
最初の画面の設定は先ほどと同じですが、FACILITYだけ変更します。

* FACILITY: **LOG_LOCAL1** 　　　注）Trafficログとログファイルを分けたいのでLOCAL **1**とします

次の画面のFILTERSの + Add ボタンからThreatログを選択します。
ログ転送が開始されるまでしばらく待ちます。

## 7. td-agent(fluentd）設定
td-agentを利用し、rsyslogで任意のログファイルに出力されたログを読み込み、S3バケットに保管します。
以下のコマンドでtd-agentをインストールします。

```
$ curl -L https://toolbelt.treasuredata.com/sh/install-amazon2-td-agent4.sh | sh
```

td-agentの起動ユーザをroot変更します。
`/usr/lib/systemd/system/td-agent.service`のUser, Groupをtd-agentからrootへ変更します。

```/usr/lib/systemd/system/td-agent.service
（略）
[Service]
User=root
Group=root
....
```
:::note
rsyslogで出力されるログがデフォルト設定の場合rootユーザにしか読み取り権限がないため、td-agentの起動ユーザをrootに変更しています。
rsyslogの設定でログファイルの権限を変更した方が正しいアプローチかもしれません。
:::


デフォルトのtd-agent設定ファイルをリネームします。

```
$ sudo mv /etc/td-agent/td-agent.conf
```

`/etc/td-agent/td-agent.conf`を以下の内容に変更します。
<バケット名> <リージョン名> は作成したS3バケットの情報を設定してください。

```/etc/td-agent/td-agent.conf
<source>
  @type tail
  format none
  path /var/log/traffic.log
  pos_file /var/log/traffic.log.pos
  tag traffic.log
</source>

<match traffic.log>
  @type s3
  format single_value
  s3_bucket <バケット名>
  region <リージョン名>
  path traffic-log/%Y/%m/%d/
  <buffer>
    @type file
    path /var/log/td-agent/traffic-buffer
    timekey 3600
    chunk_limit_size 10g
  </buffer>
</match>

<source>
  @type tail
  format none
  path /var/log/threat.log
  pos_file /var/log/threat.log.pos
  tag threat.log
</source>

<match threat.log>
  @type s3
  format single_value
  s3_bucket <バケット名>
  region <リージョン名>
  path threat-log/%Y/%m/%d/
  <buffer>
    @type file
    path /var/log/td-agent/threat-buffer
    timekey 3600
    chunk_limit_size 10g
  </buffer>
</match>
```
::: note
rsyslog.confの設定で指定したログファイルを読み込み、元のcsvファイル形式のままgzip圧縮してS3バケットへ保存します。ログはS3バケットに/ログ種別/年/月/日のパスで分類されます。ログファイルは1時間1ファイルとするためtimekeyを3600とし、chunk_limit_sizeを十分に大きい値（今回は10g）としています。バッファ容量を大きく設定するため、バッファタイプにファイルを設定しています。
:::

td-agentの起動ユーザ変更の読み込みとtd-agentの再起動を行います。
ステータスとログファイルを参照してエラーがないことを確認します。

```
$ sudo systemctl daemon-reload
$ sudo systemctl restart td-agent
$ sudo systemctl status td-agent
$ sudo less /var/log/td-agent/td-agent.log
```
::: note
ログファイル読み込みの権限エラーが出力されている場合、/usr/lib/systemd/system/td-agent.serviceの設定を確認してください。
:::

1時間ほど待つとS3バケットにログが保存されるはずです。
すぐに確認したい場合は`td-agent.conf`の`timekey`の値を小さくすることで確認できます。


# 参考情報

https://docs.paloaltonetworks.com/cortex/cortex-data-lake/cortex-data-lake-getting-started/get-started-with-log-forwarding-app/forward-logs-from-logging-service-to-syslog-server.html

https://qiita.com/ymzkjpx/items/ae115ed6d0fd2d383cec

https://docs.aws.amazon.com/ja_jp/AWSEC2/latest/UserGuide/SSL-on-amazon-linux-2.html#letsencrypt

https://qiita.com/saeki4n/items/198407c8710d769dfa55

https://security-log-analysis-platform.workshop.aws/ja/05-ingest-and-process-application-logs/05-3-install-and-configure-fluentd.html