📊

Microsoft Entra ID アプリケーションのシークレットや証明書の有効期限チェック

2024/03/29に公開

はじめに

Microsoft Entra ID に登録したアプリケーションや SAML の証明書・シークレットは有効期限が設定されており、期限切れとなった場合に必要なアプリにアクセスできなくなるリスクがあります。SAML 証明書は以下のように通知する仕組みになっているのですが、アプリケーションのほうは自身でチェックする必要がありますので、方法をまとめていきます。
https://learn.microsoft.com/ja-jp/entra/identity/enterprise-apps/application-management-certs-faq#how-can-i-automate-the-certificates-expiration-notifications

推奨事項を使う

Microsoft Entra ワークロード ID Premium ライセンスを持っている場合、以下の推奨事項でチェックが可能です。(ライセンスがなくても現時点では見えますが)
https://learn.microsoft.com/ja-jp/entra/identity/monitoring-health/recommendation-renew-expiring-application-credential
https://learn.microsoft.com/ja-jp/entra/identity/monitoring-health/recommendation-renew-expiring-service-principal-credential

Beta ですが、Microsoft Graph PowerShell からも取得できるので、自動化も可能かと思います。
https://learn.microsoft.com/en-us/powershell/module/microsoft.graph.beta.identity.directorymanagement/get-mgbetadirectoryrecommendation?view=graph-powershell-beta
https://learn.microsoft.com/en-us/powershell/module/microsoft.graph.beta.identity.directorymanagement/get-mgbetadirectoryrecommendationimpactedresource?view=graph-powershell-beta

ライセンスを持っていない場合

Microsoft Entra ワークロード ID Premium ライセンスを持ってない場合、自身でチェックする仕組みを作る必要があります。アプリのシークレット/証明書と SAML 証明書ともに Microsoft Graph PowerShell で詳細情報を取得可能なので、そこから 30 日以内に有効期限が切れる項目を CSV で一覧化します。Get-ExpiringApplication.ps1 がアプリ登録のシークレットと証明書、Get-ExpiringServicePrincipal.ps1 がエンタープライズ アプリの SAML 証明書になります。

Get-ExpiringApplication.ps1
# テナント指定
$TenantID="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"

# CSV ファイルのヘッダーを作成
$header = "Type,ApplicationDisplayName,CredentialType,CredentialKeyId,CredentialEndDate,DaysToExpire"

# CSV ファイルにヘッダーを書き込み
$header | Out-File -FilePath "ApplicationExpireDate.csv"

# Graph PowerShell 接続
Connect-MgGraph -Scopes 'Application.Read.All' -TenantId $TenantID

# Get-MgApplication でアプリ登録の一覧を取得
$Applications = Get-MgApplication -All

# 30 日以内に期限が切れる証明書やシークレットを持つアプリ登録をリストアップ
$Applications | ForEach-Object {
    $Application = $_
    $ApplicationDisplayName = $Application.DisplayName
    $ApplicationKeyCredential = $Application.KeyCredentials
    $ApplicationPasswordCredential = $Application.PasswordCredentials

    $ApplicationKeyCredential | ForEach-Object {
        $KeyCredential = $_
        $KeyCredentialEndDate = $KeyCredential.EndDateTime
        $KeyCredentialKeyId = $KeyCredential.KeyId
        if ($KeyCredentialEndDate -ne $null) {
            $KeyCredentialEndDate = [DateTime]::Parse($KeyCredentialEndDate)
            $DaysToExpire = ($KeyCredentialEndDate - (Get-Date)).Days
            if ($DaysToExpire -lt 30) {
                # CSV ファイルにカンマ区切りで書き込み
                $tmp = "Application,$ApplicationDisplayName,Key,$KeyCredentialKeyId,$KeyCredentialEndDate,$DaysToExpire"
                $tmp | Out-File -FilePath "ApplicationExpireDate.csv" -Append
            }
        }
    }
    $ApplicationPasswordCredential | ForEach-Object {
        $PasswordCredential = $_
        $PasswordCredentialEndDate = $PasswordCredential.EndDateTime
        $PasswordCredentialKeyId = $PasswordCredential.KeyId
        if ($PasswordCredentialEndDate -ne $null) {
            $PasswordCredentialEndDate = [DateTime]::Parse($PasswordCredentialEndDate)
            $DaysToExpire = ($PasswordCredentialEndDate - (Get-Date)).Days
            if ($DaysToExpire -lt 30) {
                # CSV ファイルにカンマ区切りで書き込み
                $tmp = "Application,$ApplicationDisplayName,Password,$PasswordCredentialKeyId,$PasswordCredentialEndDate,$DaysToExpire"
                $tmp | Out-File -FilePath "ApplicationExpireDate.csv" -Append
            }
        }
    }
}
Get-ExpiringServicePrincipal.ps1
# テナント指定
$TenantID="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"

# CSV ファイルのヘッダーを作成
$header = "Type,ServicePrincipalDisplayName,CredentialType,CredentialKeyId,CredentialEndDate,DaysToExpire"

# CSV ファイルにヘッダーを書き込み
$header | Out-File -FilePath "ServicePrincipalExpireDate.csv"

# Graph PowerShell 接続
Connect-MgGraph -Scopes 'Application.Read.All' -TenantId $TenantID

# Get-MgServicePrincipal でサービス プリンシパルの一覧を取得
$ServicePrincipals = Get-MgServicePrincipal -All

# 30 日以内に期限が切れる証明書やシークレットを持つ Service Principal をリストアップ
$ServicePrincipals | ForEach-Object {
    $ServicePrincipal = $_
    $ServicePrincipalDisplayName = $ServicePrincipal.DisplayName
    $ServicePrincilalType = $ServicePrincipal.ServicePrincipalType
    $ServicePrincipalKeyCredential = $ServicePrincipal.KeyCredentials
    $ServicePrincipalPasswordCredential = $ServicePrincipal.PasswordCredentials

    # マネージド ID 以外を対象
    if ($ServicePrincilalType -ne "ManagedIdentity") {
        $ServicePrincipalKeyCredential | ForEach-Object {
            $KeyCredential = $_
            $KeyCredentialEndDate = $KeyCredential.EndDateTime
            $KeyCredentialKeyId = $KeyCredential.KeyId
            if ($KeyCredentialEndDate -ne $null) {
                $KeyCredentialEndDate = [DateTime]::Parse($KeyCredentialEndDate)
                $DaysToExpire = ($KeyCredentialEndDate - (Get-Date)).Days
                if ($DaysToExpire -lt 30) {
                    # CSV ファイルにカンマ区切りで書き込み
                    $tmp = "Service Principal,$ServicePrincipalDisplayName,Key,$KeyCredentialKeyId,$KeyCredentialEndDate,$DaysToExpire"
                    $tmp | Out-File -FilePath "ServicePrincipalExpireDate.csv" -Append
                }
            }
        }
        $ServicePrincipalPasswordCredential | ForEach-Object {
            $PasswordCredential = $_
            $PasswordCredentialEndDate = $PasswordCredential.EndDateTime
            $PasswordCredentialKeyId = $PasswordCredential.KeyId
            if ($PasswordCredentialEndDate -ne $null) {
                $PasswordCredentialEndDate = [DateTime]::Parse($PasswordCredentialEndDate)
                $DaysToExpire = ($PasswordCredentialEndDate - (Get-Date)).Days
                if ($DaysToExpire -lt 30) {
                    # CSV ファイルにカンマ区切りで書き込み
                    $tmp = "Service Principal,$ServicePrincipalDisplayName,Password,$PasswordCredentialKeyId,$PasswordCredentialEndDate,$DaysToExpire"
                    $tmp | Out-File -FilePath "ServicePrincipalExpireDate.csv" -Append
                }
            }
        }
    }
}

結果はこのように出力されます。

ちなみに

スクリプト書いた後 (GitHub Copilot にほぼ書いてもらいましたが)に分かったのですが、公式ドキュメントでスクリプトが提供されていました。ので、こちらを使っていただいたほうがよさそうです。
https://learn.microsoft.com/ja-jp/entra/identity/enterprise-apps/scripts/powershell-export-apps-with-expiring-secrets
https://learn.microsoft.com/ja-jp/entra/identity/enterprise-apps/scripts/powershell-export-apps-with-expiring-secrets

次のステップ

次はこれを Azure Functions で実行できるようにして、Logic Apps と組み合わせて定期的なチェックとメール通知を実装します。

Microsoft (有志)

Discussion