Azure AD アプリ専用を使用してアクセスを許可する

SharePoint Online を使用する場合、Azure AD でアプリケーションを定義することができ、これらのアプリケーションには SharePoint へのアクセス許可だけでなく、Office 365 の他のすべてのサービスへのアクセス許可が付与されます。 このモデルは、SharePoint Online を使用している場合の推奨モデルです。SharePoint オンプレミスを使用している場合は、ここに記載されている Azure ACS に基づいた、SharePoint 専用のモデルを使用する必要があります。

重要

Azure Active Directory (Azure AD) のサービスである Azure Access Control (ACS) は、2018 年 11 月 7 日に廃止されます。 SharePoint アドイン モデルでは、(この廃止の影響を受けない) https://accounts.accesscontrol.windows.net ホスト名を使用しているため、この廃止による影響はありません。 詳細については、「SharePoint アドインに対する Azure アクセス制御の終了の影響」を参照してください。

アプリ専用のアクセス向けに Azure AD アプリを設定する

通常、Azure AD をアプリ専用として実行している場合は、証明書を使用してアクセスを要求します。証明書とその秘密キーを持つ人は、アプリケーションと、アプリケーションに付与されたアクセス許可を使用できます。 以下の手順は、このモデルの設定についての説明です。

アプリ専用アクセス トークンを使用して SharePoint Online を起動するための Azure AD アプリケーションを設定する準備が整いました。 これを行うには、自己署名された X.509 の証明書を作成して設定する必要があります。この証明書は、アプリ専用アクセス トークンを要求しながら Azure AD に対してアプリケーションを認証するために使用されます。 最初に、Windows SDK で使用可能な makecert.exe ツールを使用して、または makecert に依存しない PowerShell スクリプトを使用して、自己署名された X.509 の証明書を作成する必要があります。 PowerShell スクリプトの使用が推奨され、この章では、その使用方法について説明します。

重要

管理者特権で以下のスクリプトを実行することが重要です。

自己署名証明書を作成するには、このスクリプトを使用します。

.\Create-SelfSignedCertificate.ps1 -CommonName "MyCompanyName" -StartDate 2017-10-01 -EndDate 2019-10-01

注意

日付は、ISO の日付形式 (YYYY-MM-dd) で用意されています。

ここから、実際のスクリプトをコピーできます。

#Requires -RunAsAdministrator
<#
.SYNOPSIS
Creates a Self Signed Certificate for use in server to server authentication
.DESCRIPTION
.EXAMPLE
PS C:\> .\Create-SelfSignedCertificate.ps1 -CommonName "MyCert" -StartDate 2015-11-21 -EndDate 2017-11-21
This will create a new self signed certificate with the common name "CN=MyCert". During creation you will be asked to provide a password to protect the private key.
.EXAMPLE
PS C:\> .\Create-SelfSignedCertificate.ps1 -CommonName "MyCert" -StartDate 2015-11-21 -EndDate 2017-11-21 -Password (ConvertTo-SecureString -String "MyPassword" -AsPlainText -Force)
This will create a new self signed certificate with the common name "CN=MyCert". The password as specified in the Password parameter will be used to protect the private key
.EXAMPLE
PS C:\> .\Create-SelfSignedCertificate.ps1 -CommonName "MyCert" -StartDate 2015-11-21 -EndDate 2017-11-21 -Force
This will create a new self signed certificate with the common name "CN=MyCert". During creation you will be asked to provide a password to protect the private key. If there is already a certificate with the common name you specified, it will be removed first.
#>
Param(

   [Parameter(Mandatory=$true)]
   [string]$CommonName,

   [Parameter(Mandatory=$true)]
   [DateTime]$StartDate,

   [Parameter(Mandatory=$true)]
   [DateTime]$EndDate,

   [Parameter(Mandatory=$false, HelpMessage="Will overwrite existing certificates")]
   [Switch]$Force,

   [Parameter(Mandatory=$false)]
   [SecureString]$Password
)

# DO NOT MODIFY BELOW

function CreateSelfSignedCertificate(){

    #Remove and existing certificates with the same common name from personal and root stores
    #Need to be very wary of this as could break something
    if($CommonName.ToLower().StartsWith("cn="))
    {
        # Remove CN from common name
        $CommonName = $CommonName.Substring(3)
    }
    $certs = Get-ChildItem -Path Cert:\LocalMachine\my | Where-Object{$_.Subject -eq "CN=$CommonName"}
    if($certs -ne $null -and $certs.Length -gt 0)
    {
        if($Force)
        {

            foreach($c in $certs)
            {
                remove-item $c.PSPath
            }
        } else {
            Write-Host -ForegroundColor Red "One or more certificates with the same common name (CN=$CommonName) are already located in the local certificate store. Use -Force to remove them";
            return $false
        }
    }

    $name = new-object -com "X509Enrollment.CX500DistinguishedName.1"
    $name.Encode("CN=$CommonName", 0)

    $key = new-object -com "X509Enrollment.CX509PrivateKey.1"
    $key.ProviderName = "Microsoft RSA SChannel Cryptographic Provider"
    $key.KeySpec = 1
    $key.Length = 2048
    $key.SecurityDescriptor = "D:PAI(A;;0xd01f01ff;;;SY)(A;;0xd01f01ff;;;BA)(A;;0x80120089;;;NS)"
    $key.MachineContext = 1
    $key.ExportPolicy = 1 # This is required to allow the private key to be exported
    $key.Create()

    $serverauthoid = new-object -com "X509Enrollment.CObjectId.1"
    $serverauthoid.InitializeFromValue("1.3.6.1.5.5.7.3.1") # Server Authentication
    $ekuoids = new-object -com "X509Enrollment.CObjectIds.1"
    $ekuoids.add($serverauthoid)
    $ekuext = new-object -com "X509Enrollment.CX509ExtensionEnhancedKeyUsage.1"
    $ekuext.InitializeEncode($ekuoids)

    $cert = new-object -com "X509Enrollment.CX509CertificateRequestCertificate.1"
    $cert.InitializeFromPrivateKey(2, $key, "")
    $cert.Subject = $name
    $cert.Issuer = $cert.Subject
    $cert.NotBefore = $StartDate
    $cert.NotAfter = $EndDate
    $cert.X509Extensions.Add($ekuext)
    $cert.Encode()

    $enrollment = new-object -com "X509Enrollment.CX509Enrollment.1"
    $enrollment.InitializeFromRequest($cert)
    $certdata = $enrollment.CreateRequest(0)
    $enrollment.InstallResponse(2, $certdata, 0, "")
    return $true
}

function ExportPFXFile()
{
    if($CommonName.ToLower().StartsWith("cn="))
    {
        # Remove CN from common name
        $CommonName = $CommonName.Substring(3)
    }
    if($Password -eq $null)
    {
        $Password = Read-Host -Prompt "Enter Password to protect private key" -AsSecureString
    }
    $cert = Get-ChildItem -Path Cert:\LocalMachine\my | where-object{$_.Subject -eq "CN=$CommonName"}

    Export-PfxCertificate -Cert $cert -Password $Password -FilePath "$($CommonName).pfx"
    Export-Certificate -Cert $cert -Type CERT -FilePath "$CommonName.cer"
}

function RemoveCertsFromStore()
{
    # Once the certificates have been been exported we can safely remove them from the store
    if($CommonName.ToLower().StartsWith("cn="))
    {
        # Remove CN from common name
        $CommonName = $CommonName.Substring(3)
    }
    $certs = Get-ChildItem -Path Cert:\LocalMachine\my | Where-Object{$_.Subject -eq "CN=$CommonName"}
    foreach($c in $certs)
    {
        remove-item $c.PSPath
    }
}

if(CreateSelfSignedCertificate)
{
    ExportPFXFile
    RemoveCertsFromStore
}

秘密キーを暗号化するためのパスワードを入力するように求められ、.PFX ファイルと .CER ファイルの両方が現在のフォルダーにエクスポートされます。

次の手順では、Office 365 テナントにリンクされている Azure Active Directory テナントに Azure AD アプリケーションを登録します。 これを行うには、テナントのグローバル管理者グループのユーザー メンバーのアカウントを使用して、Office 365 管理センター (https://admin.microsoft.com)) を開きます。 Office 365 管理センターの左側のツリー ビューにある "管理センター" グループの下にある "Azure Active Directory" リンクをクリックします。 開かれる新しいブラウザーのタブに、Microsoft Azure portal が表示されます。 アカウントで初めて Azure portal にアクセスする場合は、新しい Azure サブスクリプションを登録する必要があります。また、発生する支払いのために、いくつかの情報の提供とクレジットカードが必要となります。 ただし、Azure AD を試用し、Office 365 アプリケーションを登録する場合は、支払いは発生しませんのでご安心ください。 実際、これらの機能は無料で使用することができます。 Azure ポータル にアクセスしたら、[Azure Active Directory] セクションを選択し、[アプリの登録] オプションを選択します。 詳細については、次の図を参照してください。

Azure AD ポータルを表示する

[アプリの登録] タブには、テナントに登録されている Azure AD アプリケーションのリストがあります。 ブレードの左上部にある [新規登録] ボタンをクリックします。 次に、アプリケーションの名前を指定し、ブレードの下部にある [登録] をクリックします。

新しい Azure AD アプリケーションを作成する

重要

アプリケーションを作成したら、"アプリケーション (クライアント) ID" をコピーします。この ID は後で必要になります。

今度は左側のメニュー バーで [API のアクセス許可] をクリックし、[アクセス許可の追加] ボタンをクリックします。 新しいブレードが表示されます。 ここで、このアプリケーションに付与するアクセス許可を選択します。 すなわち、以下を選択します:

  • SharePoint
    • アプリケーションのアクセス許可
      • サイト
        • Sites.FullControl.All

下部にある青い [アクセス許可の追加] ボタンをクリックして、アプリケーションにアクセス許可を追加します。 "アプリケーションのアクセス許可" は、アプリ専用として実行している際にアプリケーションに付与されるものです。

Azure AD アプリケーションへのアクセス許可の付与

最後の手順で、前に作成した証明書をアプリケーションに “接続” します。 左側のメニュー バーで、[証明書と機密情報] をクリックします。 [証明書のアップロード] ボタンをクリックし、先ほど生成した .CER ファイルを選択し、[追加] をクリックしてこのファイルをアップロードします。

証明書が正常に登録されていることを確認するには、左側のメニュー バーで [マニフェスト] をクリックします。 keyCredentials プロパティを見つけます。 次のようになっているはずです。

  "keyCredentials": [
    {
      "customKeyIdentifier": "<$base64CertHash>",
      "endDate": "2021-05-01T00:00:00Z",
      "keyId": "<$guid>",
      "startDate": "2019-05-01T00:00:00Z",
      "type": "AsymmetricX509Cert",
      "usage": "Verify",
      "value": "<$base64Cert>",
      "displayName": "CN=<$name of your cert>"
     }
  ],

セクションがだいたいこのように表示される場合、証明書が正常に追加されたことになります。

このサンプルでは、Sites.FullControl.All のアプリケーションのアクセス許可は、使用する前に、テナントの管理者の許諾を必要とします。 これを行うには、左側のメニューで [API アクセス許可] をもう一度クリックします。 下部に、[同意の付与] というセクションが表示されます。 [{{組織名}に対する管理者の同意を付与する}] ボタンをクリックし、上部に表示される [はい] ボタンをクリックしてアクションを確認します。

Azure ad アプリケーションへの API アクセス許可の付与

PnP PowerShell でこのプリンシパルを使用する

Azure AD アプリ専用プリンシパルを PnP PowerShell で使用する場合は、PnP PowerShell モジュールのインストール後に以下を使用して SharePoint Online 環境に接続できます。

Connect-PnPOnline -ClientId <$application client id as copied over from the AAD app registration above> -CertificatePath '<$path to the PFX file generated by the PowerShell script above>' -CertificatePassword (ConvertTo-SecureString -AsPlainText "<$password assigned to the generated certificate pair above>" -Force) -Url https://<$yourtenant>.sharepoint.com -Tenant "<$tenantname>.onmicrosoft.com"

これにより、このアプリ専用証明信頼を使用して、SharePoint Online 環境に対して PnP PowerShell を通して操作を実行できるようになります。

注意

PnP PowerShell はオープン ソース ソリューションであり、アクティブなコミュニティでサポートが提供されています。 Microsoft からのオープン ソース ツールのサポート SLA はありません。

SharePoint の PnP サイト コア ライブラリを使用して、アプリケーションでこのプリンシパルを活用する

最初の手順では、PnP Framework ライブラリ NuGet パッケージを追加します https://www.nuget.org/packages/PnP.Framework。

完了したら、以下のコード コンストラクターを使用できます。

using PnP.Framework;
using System;

namespace AzureADCertAuth
{
    class Program
    {
        static void Main(string[] args)
        {
            var authManager = new AuthenticationManager("<application id>", "c:\\temp\\mycert.pfx", "<password>", "contoso.onmicrosoft.com");
            using (var cc = authManager.GetAzureADAppOnlyAuthenticatedContext("https://contoso.sharepoint.com/sites/demo"))
            {
                cc.Load(cc.Web, p => p.Title);
                cc.ExecuteQuery();
                Console.WriteLine(cc.Web.Title);
            };
        }
    }
}

注意

PnP コア コンポーネント(別名: PnP Sites Core) は、アクティブ なコミュニティがサポートを提供するオープンソース ソリューションです。 Microsoft からのオープン ソース ツールのサポート SLA はありません。

PnP サイト コア ライブラリを使用して、PowerShell スクリプトでこのプリンシパルを活用する

Azure Automation Runbook を使用するには、まず共有リソースの下にある証明書オプションで、証明書 (.pfx) を追加し、次に Get-AutomationCertificate コマンドレットを使ってスクリプトで使用する証明書を取得します。

注意

まず、Automation アカウントに SharePointPnPPowerShellOnline モジュールを追加する必要があります。 このモジュールには、認証用電話に必要な OfficeDevPnP.Core.dll アセンブリが含まれます。

# path to installed modules
$path = "C:\Modules\User\SharePointPnPPowerShellOnline"

# reference to needed assemblies
Add-Type -Path "$path\Microsoft.SharePoint.Client.dll"
Add-Type -Path "$path\Microsoft.SharePoint.Client.Runtime.dll"
Add-Type -Path "$path\OfficeDevPnP.Core.dll"

# reference to the certificate
$cert = Get-AutomationCertificate -Name 'NameOfCertificate'

# set the variables
$siteUrl = "https://<tenant>.sharepoint.com"
$appId = "<guid of the App>"
$domain = "<tenant>.onmicrosoft.com"
$azureEnv = [OfficeDevPnP.Core.AzureEnvironment]::Production

# instantiate the objects
$clientContext = new-object Microsoft.SharePoint.Client.ClientContext($siteUrl)
$authManager = new-object OfficeDevPnP.Core.AuthenticationManager

# configure the object
$clientContext = $authManager.GetAzureADAppOnlyAuthenticatedContext($siteUrl, $appId, $domain, $cert, $azureEnv)

# do some stuff
$clientContext.Load($clientContext.Web)
$clientContext.ExecuteQuery()
$clientContext.Web.Title

アプリケーションでこのプリンシパルを使用し、Azure KeyVault を使用して証明書を保存し、 Azure 関数を使用して取得する

マネージド ID を Azure 関数に追加し、この ID アクセス (シークレットに対してアクセス許可を取得する) を KeyVault に許可します。

以下に、同じ GetAzureADAppOnlyAuthenticatedContext メソッドへのわずかに異なる呼び出しがあり、証明書へのパスの代わりに実際の証明書を渡します。 Azure 関数の ID を使用して KeyVault から証明書を取得するための追加機能が追加されます。AzureServiceTokenProvider で「魔法」が発生するため、この取得はシームレスで透過的です。

static void Main(string[] args)
{
    using (var cc = new AuthenticationManager().GetAzureADAppOnlyAuthenticatedContext(
        siteUrl,
        ApplicationId,
        tenant + ".onmicrosoft.com",
        GetKeyVaultCertificate("kv-spo", "AzureAutomationSPOAccess")))
        {
        cc.Load(cc.Web, p => p.Title);
        cc.ExecuteQuery();
        log.Info("Via PnP, we have site: " + cc.Web.Title);
        };
}


internal static X509Certificate2 GetKeyVaultCertificate(string keyvaultName, string name)
{
    // Some steps need to be taken to make this work
    // 1. Create a KeyVault and upload the certificate
    // 2. Give the Function App the permission to GET certificates via Access Policies in the KeyVault
    // 3. Call an explicit access token request to the management resource to https://vault.azure.net and use the URL of our Keyvault in the GetSecretMethod
    if (keyVaultClient == null)
    {
        // this token provider gets the appid/secret from the azure function identity
        // and thus makes the call on behalf of that appid/secret
        var serviceTokenProvider = new AzureServiceTokenProvider();
        keyVaultClient = new KeyVaultClient(new KeyVaultClient.AuthenticationCallback(serviceTokenProvider.KeyVaultTokenCallback));
    }

    // Getting the certificate
    var secret = keyVaultClient.GetSecretAsync("https://" + keyvaultName + ".vault.azure.net/", name);

    // Returning the certificate
    return new X509Certificate2(Convert.FromBase64String(secret.Result.Value));

    // If you receive the following error when running the Function;
    // Microsoft.Azure.WebJobs.Host.FunctionInvocationException:
    // Exception while executing function: NotificationFunctions.QueueOperation--->
    // System.Security.Cryptography.CryptographicException:
    // The system cannot find the file specified.at System.Security.Cryptography.NCryptNative.ImportKey(SafeNCryptProviderHandle provider, Byte[] keyBlob, String format) at System.Security.Cryptography.CngKey.Import(Byte[] keyBlob, CngKeyBlobFormat format, CngProvider provider)
    //
    // Please see https://stackoverflow.com/questions/31685278/create-a-self-signed-certificate-in-net-using-an-azure-web-application-asp-ne
    // Add the following Application setting to the AF "WEBSITE_LOAD_USER_PROFILE = 1"
}


Pnp モダン化スキャナーでこのプリンシパルを使用する

Azure Active Directory アプリケーションの登録の作成は完了しているので、このプリンシパルをこのツールで使用するにはこちらの手順に従ってください

FAQ

Azure AD アプリのアプリ専用アクセスを実現するために、証明書以外の方法を使用できますか?

いいえ、他のすべてのオプションは SharePoint Online によってブロックされ、アクセス拒否メッセージが表示されます。