IBM Cloud Internet Services (CIS) で logpush されるごとに IBM Log Analysis with LogDNA にログを取り入れる


# 概要
CIS のログは、定期的に IBM Cloud Object Storage (ICOS) バケットに出力することができます。
それだけでは、ログ監視や閲覧性に難があるため、以下のような連携を実装し、ログ分析がおこなえる仕組みを整備します。
LogDNA についての概要は「[LogDNA で IBM Cloud のログ監視をしてみた](https://qiita.com/asasaki/items/c8aee30ee7151740d624)」の記事が参考になります。

![Kobito.wXUwzU.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/101361/9ceecfa1-6ceb-8148-3b68-5ea39d3174f9.png "Kobito.wXUwzU.png")


# 前提条件

- IBM Cloud Object Storage (ICOS) リージョナルバケット
	- Functions と連携するためには Functions が機能するリージョンかつリージョナルバケットである必要があります。
- IBM Cloud Internet Services (CIS) Enterprise plan
	- [Logpush](https://cloud.ibm.com/docs/cis?topic=cis-logpush) ジョブを作成するためには Enterprise 以上の Plan が必須です
- IBM Log Analysis with LogDNA
	- どのリージョンでも問題ありませんが、今回は同一リージョンに揃えた構成にします。
- IBM Cloud Functions Namespace
	- ICOS リージョナルバケットと同一リージョンである必要があります。

# ICOS リージョナルバケット準備
CLI を使って構成準備を進めます。

## `ibmcloud` ログイン

```shell:

export REGION="jp-tok"
export RESOURCE_GROUP="khayama-rg"
ibmcloud login -a cloud.ibm.com -r $REGION -g $RESOURCE_GROUP
```

## ICOS サービスインスタンス作成

```shell:

export COS_NAME=khayama-cis-cos
export COS_PLAN=standard

ibmcloud resource service-instance-create $COS_NAME \
cloud-object-storage $COS_PLAN global
```

## CLI プラグインインストール

```shell:

ibmcloud plugin install cloud-object-storage
ibmcloud plugin show cloud-object-storage
```

## ICOS リージョナルバケットの作成
`jp-tok` に [Smart Tier](https://qiita.com/khayama/items/3ccfefa0dd979805ba9d#smart-tier-%E3%81%A8%E3%81%AF) のバケットを作成します。

```shell:

COS_ID=$(ibmcloud resource service-instance --output JSON $COS_NAME | jq -r '.[].id')
echo $COS_ID

export BUCKET_NAME=khayama-cis-log

ibmcloud cos create-bucket \
--bucket $BUCKET_NAME --class smart\
--ibm-service-instance-id $COS_ID \
--region $REGION
```

## ICOS サービス認証情報の作成
Functions からアクセスするための認証情報を作成します。

```shell:

ibmcloud resource service-key-create "$COS_NAME"-service-key  --instance-id $COS_ID
ibmcloud resource service-keys  
```

# CIS Logpush 設定
CIS はオーダー済み、ドメイン登録済みの前提で進めます。

## CLI プラグインインストール

```shell:

ibmcloud plugin install cloud-internet-services
ibmcloud plugin show cloud-internet-services
```

## CLI コンテキスト設定
サービスインスタンス名の指定と、そこに登録されたドメインの ID を取得します。

```shell:

CIS_NAME="CIS-Enterprise"
ibmcloud cis instance-set $CIS_NAME

DOMAIN="khayama.cloudnativejapan.com"
DOMAIN_ID=$(ibmcloud cis domains --output JSON | jq -r '.[] | select (.name=="'$DOMAIN'") | .id')
echo $DOMAIN_ID 
``` 

## CIS Logpush Job 作成
[Logpush](https://cloud.ibm.com/docs/cis?topic=cis-logpush) ジョブを作成します。
正確な時系列表示のためにタイムスタンプ形式は `unixnano` を指定してください。

```shell:

JOB_NAME=khayama-cis-log
BUCKET_PATH="cos://$BUCKET_NAME/cislog?region=$REGION&instance-id=$(echo $COS_ID | cut -d: -f 8)"
echo $BUCKET_PATH

ibmcloud cis logpush-job-create $DOMAIN_ID --destination $BUCKET_PATH --name $JOB_NAME --fields all --enable true --timestamps unixnano
```

以下のように途中でチャレンジトークンの入力を求められます。
バケットからファイルをダウンロードし、内容をペーストしましょう。

```shell:result

ドメイン 'd0d205d4658ea04af1f33axxxxxxxxxx' 内のログプッシュ・ジョブを確認中...
OK
所有権チャレンジの発行 ...
OK
チャレンジ・トークンが IBM Cloud Object Storage バケット内のファイル 'cislog/ownership-challenge-7072f20d.txt' に書き込まれました。これをコピー・アンド・ペーストしてください。
チャレンジ・トークン > 
所有権の検証 ...
OK
ドメイン 'd0d205d4658ea04af1f33axxxxxxxxxx' 内にログプッシュ・ジョブを作成中... 
OK
                          
データ・セット         http_requests   
有効                   true   
名前                   khayama-cis-log   
フィールド             FirewallMatchesSources,OriginResponseTime,CacheTieredFill,ClientMTLSAuthStatus,FirewallMatchesActions,OriginResponseBytes,WAFProfile,WorkerSubrequestCount,ClientMTLSAuthCertFingerprint,EdgeResponseBytes,ClientRequestProtocol,ClientSrcPort,EdgeEndTimestamp,EdgePathingOp,EdgeResponseCompressionRatio,EdgeServerIP,WorkerStatus,ClientRequestReferer,ClientRequestUserAgent,WorkerSubrequest,EdgeRateLimitAction,WAFAction,ClientDeviceType,ClientRequestBytes,WAFRuleID,CacheCacheStatus,OriginIP,ParentRayID,WorkerCPUTime,EdgeResponseContentType,OriginResponseHTTPExpires,RayID,WAFFlags,EdgeColoID,OriginSSLProtocol,EdgeRateLimitID,ClientRequestMethod,ClientRequestPath,ClientRequestURI,OriginResponseStatus,WAFRuleMessage,ClientIPClass,FirewallMatchesRuleIDs,ClientXRequestedWith,EdgePathingSrc,EdgePathingStatus,EdgeRequestHost,WAFMatchedVar,ZoneID,ClientASN,ClientRequestHost,EdgeStartTimestamp,OriginResponseHTTPLastModified,CacheResponseBytes,EdgeColoCode,ClientIP,ClientSSLProtocol,EdgeResponseStatus,SecurityLevel,CacheResponseStatus,ClientCountry,ClientSSLCipher   
タイム・スタンプ形式   rfc3339   
宛先                   cos://khayama-cis-log/cislog?region=jp-tok&instance-id=baaxxxxx-fxxx-4xxx-8xxx-7a764eaxxxxx   
前回の完了                
前回のエラー              
エラー・メッセージ        
```
# Log Analysis with LogDNA インタンス準備
ログ保管先となる LogDNA を準備します。
https://cloud.ibm.com/catalog/services/ibm-log-analysis-with-logdna

## LogDNA サービスインスタンス作成
東京リージョンに7日間保管プランで作成します。

- [Provisioning an instance](https://cloud.ibm.com/docs/Log-Analysis-with-LogDNA?topic=Log-Analysis-with-LogDNA-provision)

```shell:

export LOG_NAME=khayama-cis-logdna
export LOG_PLAN=7-day

ibmcloud resource service-instance-create $LOG_NAME \
logdna $LOG_PLAN $REGION
```

## LogDNA サービス認証情報の作成
Functions からアクセスするための認証情報を作成します。

```shell:

LOG_ID=$(ibmcloud resource service-instance --output JSON $LOG_NAME | jq -r '.[].id')
echo $LOG_ID

ibmcloud resource service-key-create "$LOG_NAME"-service-key  --instance-id $LOG_ID
ibmcloud resource service-keys  
```

# Functions 設定

## Namespace 設定
`namespace` を作成して CLI にコンテキストをセットします。

```shell:

export NAMESPACE="khayama-fn"
ibmcloud fn namespace create $NAMESPACE
ibmcloud fn namespace target $NAMESPACE
```

## Functions から ICOS へのアクセスを許可

COS の変更通知を受信してトリガーできるように以下の許可設定をおこないます。

- [Using authorizations to grant access between services](https://cloud.ibm.com/docs/account?topic=account-serviceauth#auth-cli)

```shell:

ibmcloud iam authorization-policy-create \
functions \
--source-service-instance-name $NAMESPACE \
cloud-object-storage \
--target-service-instance-name $COS_NAME \
"Notifications Manager" 
```

## アクション作成
GitHub からスクリプトをダウンロードし、`zip` 化したものでアクションを作成します。
OpenWhisk Native Docker コンテナ（[openwhisk/dockerskeleton](https://hub.docker.com/r/openwhisk/dockerskeleton/)）内でシェルスクリプトを実行するアクションの形式をとります。
また、スクリプト内では、 LogDNA のエンドポイントに `jp-tok` とハードコーディングされた部分がありますので、 LogDNA インスタンスがあるリージョンに応じて適宜変更してください。

- [khayama/cis-logpush-to-logdna](https://github.com/khayama/cis-logpush-to-logdna)

```shell:

git clone https://github.com/khayama/cis-logpush-to-logdna.git
cd cis-logpush-to-logdna

ACTION_NAME=cis-logpush-to-logdna
zip -9 -j "$ACTION_NAME".zip *

ibmcloud fn action update $ACTION_NAME --native "$ACTION_NAME".zip
```

## サービス認証情報のバインド
作成しておいたサービス認証情報を Functions アクションにパラメータとしてバインドします。
アクションに変更があって update した場合は、再度、サービス認証情報のバインドが必要な仕様のため、ご注意ください。

- [Binding IBM Cloud services to Cloud Functions entities](https://cloud.ibm.com/docs/openwhisk?topic=openwhisk-services)

```shell:

ibmcloud fn service bind logdna $ACTION_NAME --instance $LOG_NAME
ibmcloud fn service bind cloud-object-storage $ACTION_NAME --instance $COS_NAME
ibmcloud fn action get $ACTION_NAME parameters
```

## トリガー作成
CIS Logpush のターゲットに指定したバケットに `write` トリガーを設定します。

```shell:

TRIGGER_NAME=cis-logpush-trigger
ibmcloud fn trigger create $TRIGGER_NAME --feed /whisk.system/cos/changes -p bucket $BUCKET_NAME -p event_types write -p prefix cislog/
ibmcloud fn trigger get $TRIGGER_NAME
```

## ルール作成

トリガーが起動したとき、特定のアクションが実施されるようにルールを作成して紐付けします。

```shell:

ibmcloud fn rule create "$TRIGGER_NAME"-"$ACTION_NAME" $TRIGGER_NAME $ACTION_NAME
```

# 稼働確認

例えば、5秒おきに `curl` で http リクエストを行うコマンドを実施して、対象ドメイン内の Web サイトにアクセスし続けます。

```
while true; do sleep 5 && curl -s https://xxxxx.khayama.cloudnativejapan.com/ ; done
```

CIS の Log が定期的に ICOS にアップロードされることが確認できます。

>https://cloud.ibm.com/docs/cis?topic=cis-logpush 
>A Logpush job is created successfully after CIS validates the ownership challenge. The Logpush job pushes request logs to your Object Storage bucket every 30 seconds or every 100,000 records, whichever comes first. More than one file might be pushed per 30-second period or per 100,000 records.

![Kobito.x0qLBQ.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/101361/430b6b3e-f5c9-7295-5da9-6f662563113a.png "Kobito.x0qLBQ.png")


その後、トリガーが起動し、アクションが実施されることが確認できます。

![Kobito.sjXmK0.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/101361/b97f73a7-41eb-c361-b4af-d2cfa4fb7f3c.png "Kobito.sjXmK0.png")

それぞれのアクションログはこのように確認ができます。

![Kobito.WrerXy.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/101361/991277ce-e63e-127a-c994-b8e8c37bca75.png "Kobito.WrerXy.png")


LogDNA でも 5 秒おきの Web アクセスログが随時取り込まれることが確認できます。

![貼り付けた画像_2020_09_18_2_08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/101361/9760b26b-17a7-8d52-0b94-2bc05e7edc37.png "貼り付けた画像_2020_09_18_2_08.png")

それぞれのアクセスログ詳細も以下のように確認できます。

![貼り付けた画像_2020_09_18_2_02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/101361/ad8bd4f0-6468-d3f4-b2fd-240959c7e475.png "貼り付けた画像_2020_09_18_2_02.png")

# さいごに
無事、CIS のログを LogDNA に取り入れられることがわかりました。
さらに、ログ項目をフィルタリングしたり、 LogDNA で特定ログの有無によってアラートを設定することもできます。
具体的には WAF イベントログなどの監視に活用できるかと思います。

# 参考
JavaScript 版はこちらに公開されているので、よかったら試してみてください。

- [IBM/logdna-cos: A Node.js function to send all log files from Cloud Object Storage to LogDNA](https://github.com/IBM/logdna-cos)

その他

- [CIS(Cloud Internet Service)アクセスログをICOSへ定期的にLogpush - Qiita](https://qiita.com/testnin2/items/175d8cfa991218f21e86)
- [IBM-Cloud/serverless-image-processor: Use Cloud Functions to automatically analyze images in Cloud Object Storage](https://github.com/IBM-Cloud/serverless-image-processor)