# ログ管理

### Azure Monitor へのログ記録を有効にする

バージョン 3.0 以降、SCEPman および Certificate Master は、Microsoft の Log Ingestion API を利用して Azure Monitor にログを書き込みます。これはデータを保持して解析を可能にする Log Analytics Workspace の概念と、App Service とログ保存間のインターフェースとなる Data Collection Rule を使用します。これにより、SCEPman が LAW にアクセスするための RBAC ベースの権限を含む、よりモダンなアプローチが可能になります。

Log Analytics Workspace の作成および Data Collection Rule の構成は、次のコマンドを実行することで自動的に行われます `Complete-SCEPmanInstallation` （SCEPman PowerShell モジュール）の。

{% hint style="info" %}
既定の **保持期間** Log Analytics Table に保存されるデータの保持期間は **30 日間**です。異なる保持期間が必要な場合は、テーブル "SCEPman\_CL" の構成をそれに応じて調整してください。
{% endhint %}

#### Data Collector API を再有効化する

何らかの理由で以前の API を再導入したい場合は、Log Ingestion に関連するアプリサービス変数を削除し、Data Collector API が使用する変数を再度追加することで可能です。

削除する **変数**:

* [AppConfig:LoggingConfig:DataCollectionEndpointUri](https://app.gitbook.com/o/-LhPlvZ6dc8XcqY7tdZw/s/-LoGejQeUQcw7lqnQ3WX/~/edit/~/changes/787/scepman-configuration/application-settings/dependencies-azure-services/logging#appconfig-loggingconfig-datacollectionendpointuri)
* [AppConfig:LoggingConfig:RuleId](https://app.gitbook.com/o/-LhPlvZ6dc8XcqY7tdZw/s/-LoGejQeUQcw7lqnQ3WX/~/edit/~/changes/787/scepman-configuration/application-settings/dependencies-azure-services/logging#appconfig-loggingconfig-ruleid)

追加する変数：

* [AppConfig:LoggingConfig:WorkspaceId](https://app.gitbook.com/o/-LhPlvZ6dc8XcqY7tdZw/s/-LoGejQeUQcw7lqnQ3WX/~/edit/~/changes/787/scepman-configuration/application-settings/dependencies-azure-services/logging#appconfig-loggingconfig-workspaceid)
* [AppConfig:LoggingConfig:SharedKey](https://app.gitbook.com/o/-LhPlvZ6dc8XcqY7tdZw/s/-LoGejQeUQcw7lqnQ3WX/~/edit/~/changes/787/scepman-configuration/application-settings/dependencies-azure-services/logging#appconfig-loggingconfig-sharedkey)

SCEPman は再起動後に自動的に設定を読み取り、再び Data Collector API を利用します。

## KQL クエリ例

### SCEPman インスタンスの問題を確認する

```kusto
SCEPman_CL
| where Level == "Warn" or Level == "Error" or Level == "Fatal"
```

### 選択した期間内にエンドポイントごとに発行された証明書の数

{% hint style="success" %}
このクエリは、ログに Log Ingestion API を使用している SCEPman 3.0 以降で動作することが保証されています。このクエリを使用できなくする SCEPman への変更は、Breaking Changes と見なされます。
{% endhint %}

{% tabs %}
{% tab title="Log Ingestion API（既定）" %}

```kql
SCEPman_CL
| where Level == "Info" and Message startswith_cs "Issued a certificate with serial number"
| project Message, RequestBase = trim_end('/', replace_string(replace_string(replace_regex(RequestUrl, "(/pkiclient\\.exe)?(\\?operation=PKIOperation(&message=.+)?)?", ""),"certsrv/mscep/mscep.dll","intune"),"step/enrollment","activedirectory"))
| summarize IssuanceCount = count() by Endpoint = extract("/([a-zA-Z]+)$", 1, RequestBase)
```

{% endtab %}

{% tab title="Data Collector API（旧）" %}

```kusto
SCEPman_CL
| where Level == "Info" and Message startswith_cs "Issued a certificate with serial number"
| project Message, RequestBase = trim_end('/', replace_string(replace_string(replace_regex(RequestUrl_s, "(/pkiclient\\.exe)?(\\?operation=PKIOperation(&message=.+)?)?", ""),"certsrv/mscep/mscep.dll","intune"),"step/enrollment","activedirectory"))
| summarize IssuanceCount = count() by Endpoint = extract("/([a-zA-Z]+)$", 1, RequestBase)
```

{% endtab %}
{% endtabs %}

SCEPman 2.8 以降、発行された各証明書ごとに、ログメッセージが "Issued a certificate with serial number " で始まる Info レベルのログエントリが常に正確に 1 件存在し、その後にシリアル番号が続きます。しかし、解決不可能な [二つの軍隊の問題](https://en.wikipedia.org/wiki/Two_Generals'_Problem)のため、作成された証明書が申請者に届かない、あるいは他の種類のエラーにより実際の登録が妨げられることがあります。同様に、重大なエラーの場合、対応するデータベースエントリがないログエントリが存在する、またはその逆が発生することがあります。

### OCSP チェックを伴う重複しない証明書

{% tabs %}
{% tab title="Log Ingestion API（既定）" %}

```kusto
let map_certtype = datatable(serial_start:string, readable:string)
[
  "40", "Intune Device",
  "41", "Intune Device",
  "42", "Intune Incompliant Device",
  "50", "Static",
  "51", "Static",
  "60", "Intune User",
  "61", "Intune User",
  "64", "Jamf User",
  "65", "Jamf User",
  "6C", "Jamf User on Device",
  "6D", "Jamf User on Device",
  "70", "Domain Controller",
  "7C", "Jamf User on Computer",
  "7D", "Jamf User on Computer",
  "54", "Jamf Computer",
  "55", "Jamf Computer",
  "44", "Jamf Device",
  "45", "Jamf Device"
];
SCEPman_CL
| where LogCategory == "Scepman.Server.Controllers.OcspController" and Level == "Info"
| where Message startswith_cs "OCSP Response"
| project serial = extract("Serial Number ([A-F0-9]+)", 1, Message)
| distinct serial
| extend serial_start = substring(serial,0,2)
| join kind=leftouter map_certtype on serial_start
| summarize count() by (readable)
```

{% endtab %}

{% tab title="Data Collector API（旧）" %}

```kql
let map_certtype = datatable(serial_start:string, readable:string)
[
  "40", "Intune Device",
  "41", "Intune Device",
  "42", "Intune Incompliant Device",
  "50", "Static",
  "51", "Static",
  "60", "Intune User",
  "61", "Intune User",
  "64", "Jamf User",
  "65", "Jamf User",
  "6C", "Jamf User on Device",
  "6D", "Jamf User on Device",
  "70", "Domain Controller",
  "7C", "Jamf User on Computer",
  "7D", "Jamf User on Computer",
  "54", "Jamf Computer",
  "55", "Jamf Computer",
  "44", "Jamf Device",
  "45", "Jamf Device"
];
SCEPman_CL
| where LogCategory_s == "Scepman.Server.Controllers.OcspController" and Level == "Info"
| where Message startswith_cs "OCSP Response"
| project serial = extract("Serial Number ([A-F0-9]+)", 1, Message)
| distinct serial
| extend serial_start = substring(serial,0,2)
| join kind=leftouter map_certtype on serial_start
| summarize count() by (readable)
```

{% endtab %}
{% endtabs %}
