0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

ODB@Aの利用のために、ADユーザでOCIコンソールにSSOする ─ ADFSでSAMLフェデレーション

0
Last updated at Posted at 2026-07-07

はじめに

お疲れ様です。矢儀 @yuki_ink です。

Oracle Database@AWSの利用のために、OCIコンソールへのログイン環境を整えないといけませんでした(VMクラスタの構築まではAWS側からできるが、その上のDBの構築やパッチ適用などはOCIコンソールから!)

ADFS(Active Directory Federation Services)は、Microsoftが提供する認証連携(フェデレーション)サービスです。
ADFSを利用すれば、社内のAD(Active Directory)のIDを使って、社外のクラウドサービスやWebアプリにシングルサインオン(SSO)できます。

ADFSは現在でも多くの企業で利用されていますが、近年は Microsoft Entra ID(旧 Azure AD) やOIDCベースの認証へ移行するケースも増えています。

一方で、オンプレミスADとの密接な連携や、閉域網環境での運用が求められるケース(特に、閉域網の中でも、さらにアクセス元IPアドレスを制御したいようなケース)では、現在でもADFSが有効な選択肢となります。

というわけで、EC2でADFSを起動して、OCIコンソールにSSOします!!!

概要

今回の検証では 「ADユーザ test@yagi.local(※)の認証情報で、OCI IAMユーザ test@yagi.local にフェデレーションすること」 を目指します。
※「yagi.local」ドメインの「test」ユーザ

ユーザのマッピングはこのようになります。

AD の UPN(test@yagi.local)⇒ OCI IAM ユーザ名(test@yagi.local)

AWSのマネジメントコンソールでADFS連携しようとするとIAMユーザではなくIAMロールを利用しますが、OCIのフェデレーションでは、AWS STS AssumeRole のようにロールへスイッチする構成ではなく、OCI IAMユーザへ直接マッピングする構成になります。

サーバとしてはAmazon EC2で「Windows Server 2022」を利用し、その中で以下のサービスを稼働させます。
今回は検証のため、サービスごとにサーバの分離はしません。

サービス 役割 / 概要 今回の検証での目的
Active Directory Domain Services (ADDS) Windowsドメイン環境を提供し、ユーザーや認証情報を管理する。 yagi.local ドメインを構築し、ADFSの認証基盤として利用する。
Active Directory Federation Services (ADFS) 外部サービスとのシングルサインオン(SSO)を実現する認証連携機能。 yagi.local のユーザーでOCIコンソールへログインできるようにする。
Active Directory Certificate Services (ADCS) 証明書の発行・管理を行う認証局(CA)。 ADFS用のSSL証明書を発行し、HTTPS通信を有効にする。
DNS Server 名前解決を行い、ホスト名とIPアドレスを対応付ける。 yagi.localadfs.yagi.local の名前解決を行う。

全体アーキテクチャ

今回の構成では、ADFS (adfs.yagi.local) はVPC内部からのみアクセス可能なプライベート構成としています。
そのため、本記事の構成でOCIコンソールへSSOできるのは、内部NWからADFSへ到達できるユーザに限定されます。

インターネット上の任意端末からOCIへSSOさせる場合は、ADFS Proxy(WAP: Web Application Proxy)やリバースプロキシを利用して、ADFSを安全に外部公開する構成が必要になりますが、本記事の趣旨ではないので詳細は触れません🙇‍♀️

前提条件

  • AWSアカウントおよびOCIアカウントが作成済みであること
  • EC2インスタンス用のVPCおよびサブネットが構成済みであること

STEP 1: EC2 インスタンスの作成

ADFS用と検証用とで、2つインスタンスを起動します。

1-1. ADFS用 EC2 インスタンスの作成

以下の通り、EC2インスタンスを作成します。

項目 推奨値
AMI Windows Server 2022 Base
インスタンスタイプ t3.large
ストレージ 60GB (gp3)
IAMロール 指定なし

ADFS用EC2インスタンスにアタッチするセキュリティグループの設定は以下の通りです。

ポート プロトコル 用途 ソース
3389 TCP RDP(構築・管理用) 操作端末のグローバルIP(インターネット経由)
443 TCP ADFS HTTPS(SAMLエンドポイント) VPC CIDR
53 TCP/UDP DNS VPC CIDR

1-2. 検証用 EC2 インスタンスの作成

以下の通り、EC2インスタンスを作成します(ブラウザが使えればいいので、適当でいいです😇)

項目 推奨値
AMI Windows Server 2022 Base
インスタンスタイプ t3.small
ストレージ 30GB (gp3)
IAMロール 指定なし

検証用EC2インスタンスにアタッチするセキュリティグループの設定は以下の通りです。

ポート プロトコル 用途 ソース
3389 TCP RDP(構築・管理用) 操作端末のグローバルIP(インターネット経由)

STEP 2: Active Directory ドメインサービス (ADDS) の構築

yagi.local ドメインを構築し、フェデレーション検証用のADユーザを作成します。

ここから、ADFS用EC2インスタンスにRDP接続して操作を進めます。

2-1. コンピュータ名の変更

Administrator でログイン後、PowerShellを管理者として実行し、コンピュータ名を変更して再起動します。
今回は YAGI-DC-ADFS01 としました。

Rename-Computer -NewName "YAGI-DC-ADFS01" -Restart

再起動後、再度RDP接続します。

2-2. OSの日本語化

ここで、OSの日本語化をしておきます(ADの構築とは直接関係ないですが😅)
こちらのスクリプトを参考にさせていただきました。

管理者権限で、以下のPowerShellスクリプトを実行します。

日本語化スクリプト
change-ws2022-lang-ja.ps1
function Invoke-LanguagePackCabFileDownload
{
    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true)]
        [ValidateNotNullOrEmpty()]
        [string] $LangPackIsoUri,

        [Parameter(Mandatory = $true)]
        [long] $OffsetToCabFileInIsoFile,

        [Parameter(Mandatory = $true)]
        [long] $CabFileSize,

        [Parameter(Mandatory = $true)]
        [ValidateNotNullOrEmpty()]
        [string] $CabFileHash,

        [Parameter(Mandatory = $true)]
        [ValidateNotNullOrEmpty()]
        [string] $DestinationFilePath
    )

    $request = [System.Net.HttpWebRequest]::Create($LangPackIsoUri)
    $request.Method = 'GET'

    # Set the language pack CAB file data range.
    $request.AddRange('bytes', $OffsetToCabFileInIsoFile, $OffsetToCabFileInIsoFile + $CabFileSize - 1)

    # Donwload the language pack CAB file.
    $response = $request.GetResponse()
    $reader = New-Object -TypeName 'System.IO.BinaryReader' -ArgumentList $response.GetResponseStream()
    $fileStream = [System.IO.File]::Create($DestinationFilePath)
    $contents = $reader.ReadBytes($response.ContentLength)
    $fileStream.Write($contents, 0, $contents.Length)
    $fileStream.Dispose()
    $reader.Dispose()
    $response.Close()
    $response.Dispose()

    # Verify integrity of the downloaded language pack CAB file.
    $fileHash = Get-FileHash -Algorithm SHA1 -LiteralPath $DestinationFilePath
    if ($fileHash.Hash -ne $CabFileHash) {
        throw ('The file hash of the language pack CAB file "{0}" is not match to expected value. The download was may failed.') -f $DestinationFilePath
    }
}

function Set-LanguageOptions
{
    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true)]
        [ValidateNotNullOrEmpty()]
        [string] $UserLocale,

        [Parameter(Mandatory = $true)]
        [ValidateNotNullOrEmpty()]
        [string] $InputLanguageID,

        [Parameter(Mandatory = $true)]
        [int] $LocationGeoId,

        [Parameter(Mandatory = $true)]
        [bool] $CopySettingsToSystemAccount,

        [Parameter(Mandatory = $true)]
        [bool] $CopySettingsToDefaultUserAccount,

        [Parameter(Mandatory = $true)]
        [ValidateNotNullOrEmpty()]
        [string] $SystemLocale
    )

    # Reference:
    # - Guide to Windows Vista Multilingual User Interface
    #   https://docs.microsoft.com/en-us/previous-versions/windows/it-pro/windows-vista/cc721887(v=ws.10)
    $xmlFileContentTemplate = @'
<gs:GlobalizationServices xmlns:gs="urn:longhornGlobalizationUnattend">
    <gs:UserList>
        <gs:User UserID="Current" CopySettingsToSystemAcct="{0}" CopySettingsToDefaultUserAcct="{1}"/>
    </gs:UserList>
    <gs:UserLocale>
        <gs:Locale Name="{2}" SetAsCurrent="true"/>
    </gs:UserLocale>
    <gs:InputPreferences>
        <gs:InputLanguageID Action="add" ID="{3}" Default="true"/>
    </gs:InputPreferences>
    <gs:MUILanguagePreferences>
        <gs:MUILanguage Value="{2}"/>
        <gs:MUIFallback Value="en-US"/>
    </gs:MUILanguagePreferences>
    <gs:LocationPreferences>
        <gs:GeoID Value="{4}"/>
    </gs:LocationPreferences>
    <gs:SystemLocale Name="{5}"/>
</gs:GlobalizationServices>
'@

    # Create the XML file content.
    $fillValues = @(
        $CopySettingsToSystemAccount.ToString().ToLowerInvariant(),
        $CopySettingsToDefaultUserAccount.ToString().ToLowerInvariant(),
        $UserLocale,
        $InputLanguageID,
        $LocationGeoId,
        $SystemLocale
    )
    $xmlFileContent = $xmlFileContentTemplate -f $fillValues

    Write-Verbose -Message ('MUI XML: {0}' -f $xmlFileContent)

    # Create a new XML file and set the content.
    $xmlFileFilePath = Join-Path -Path $env:TEMP -ChildPath ((New-Guid).Guid + '.xml')
    Set-Content -LiteralPath $xmlFileFilePath -Encoding UTF8 -Value $xmlFileContent

    # Copy the current user language settings to the default user account and system user account.
    $procStartInfo = New-Object -TypeName 'System.Diagnostics.ProcessStartInfo' -ArgumentList 'C:\Windows\System32\control.exe', ('intl.cpl,,/f:"{0}"' -f $xmlFileFilePath)
    $procStartInfo.UseShellExecute = $false
    $procStartInfo.WindowStyle = [System.Diagnostics.ProcessWindowStyle]::Minimized
    $proc = [System.Diagnostics.Process]::Start($procStartInfo)
    $proc.WaitForExit()
    $proc.Dispose()

    # Delete the XML file.
    Remove-Item -LiteralPath $xmlFileFilePath -Force
}

# Download the language pack CAB file for Japanese.
#
# Reference:
# - Windows Server 2022 - Evaluation Center
#   https://www.microsoft.com/en-us/evalcenter/evaluate-windows-server-2022
$langPackFilePath = Join-Path -Path $env:TEMP -ChildPath 'Microsoft-Windows-Server-Language-Pack_x64_ja-jp.cab'
$params = @{
    LangPackIsoUri           = 'https://software-static.download.prss.microsoft.com/pr/download/20348.1.210507-1500.fe_release_amd64fre_SERVER_LOF_PACKAGES_OEM.iso'
    OffsetToCabFileInIsoFile = 0x107d35800L
    CabFileSize              = 54130307
    CabFileHash              = '298667B848087EA1377F483DC15597FD5F38A492'
    DestinationFilePath      = $langPackFilePath
}
Invoke-LanguagePackCabFileDownload @params -Verbose

# Install the language pack.
Add-WindowsPackage -Online -NoRestart -PackagePath $langPackFilePath -Verbose

# Delete the language pack CAB file.
Remove-Item -LiteralPath $langPackFilePath -Force -Verbose

# Install the Japanese language related capabilities.
Add-WindowsCapability -Online -Name 'Language.Basic~~~ja-JP~0.0.1.0' -Verbose
Add-WindowsCapability -Online -Name 'Language.Fonts.Jpan~~~und-JPAN~0.0.1.0' -Verbose
Add-WindowsCapability -Online -Name 'Language.OCR~~~ja-JP~0.0.1.0' -Verbose
Add-WindowsCapability -Online -Name 'Language.Handwriting~~~ja-JP~0.0.1.0' -Verbose   # Optional
Add-WindowsCapability -Online -Name 'Language.Speech~~~ja-JP~0.0.1.0' -Verbose        # Optional
Add-WindowsCapability -Online -Name 'Language.TextToSpeech~~~ja-JP~0.0.1.0' -Verbose  # Optional

# Set the time zone for the current computer.
Set-TimeZone -Id 'Tokyo Standard Time' -Verbose

$params = @{
    UserLocale                       = 'ja-JP'
    InputLanguageID                  = '0411:{03B5835F-F03C-411B-9CE2-AA23E1171E36}{A76C93D9-5523-4E90-AAFA-4DB112F9AC76}'
    LocationGeoId                    = 122  # Japan
    CopySettingsToSystemAccount      = $true
    CopySettingsToDefaultUserAccount = $true
    SystemLocale                     = 'ja-JP'
}
Set-LanguageOptions @params -Verbose

# Restart the system to take effect changes.
Restart-Computer

このスクリプトでは、言語パックはインストールされるものの、表示言語の更新がされなかったので、そこだけ手動で設定しました。
image.png

2-3. ADDS ロールのインストール

PowerShellを管理者として起動し、以下のコマンドを実行します。

Install-WindowsFeature AD-Domain-Services -IncludeManagementTools

2-4. ドメインコントローラの構築

PowerShellを管理者として起動し、以下のコマンドを実行します。

Import-Module ADDSDeployment

Install-ADDSForest `
  -DomainName "yagi.local" `
  -DomainNetBiosName "YAGI" `
  -ForestMode "WinThreshold" `
  -DomainMode "WinThreshold" `
  -InstallDns:$true `
  -SafeModeAdministratorPassword (ConvertTo-SecureString "P@ssw0rd!Dsrm" -AsPlainText -Force) `
  -Force:$true

Install-ADDSForest コマンドの実行後、自動で再起動が走ります。

フォレスト・ドメインの機能レベルを指定する WinThreshold は、Windows Server 2016 の機能レベルを指します。

2-5. ADユーザ test の作成

PowerShellを管理者として起動し、以下のコマンドを実行します。

New-ADUser `
  -Name "test" `
  -GivenName "Test" `
  -Surname "User" `
  -SamAccountName "test" `
  -UserPrincipalName "test@yagi.local" `
  -AccountPassword (ConvertTo-SecureString "UserP@ssw0rd!" -AsPlainText -Force) `
  -Enabled $true `
  -PasswordNeverExpires $true

# 確認(ユーザ名・UPN・有効状態を確認)
Get-ADUser -Identity "test" -Properties UserPrincipalName, Enabled, PasswordNeverExpires |
  Select-Object Name, SamAccountName, UserPrincipalName, Enabled, PasswordNeverExpires

STEP 3: Active Directory 証明書サービス (ADCS) の構築と証明書発行

ADFSのHTTPS通信に使用するSSL証明書を発行するため、ドメイン内認証局(ADCS)を構築します。

3-1. ADCS ロールのインストール

PowerShellを管理者として起動し、以下のコマンドを実行します。

Install-WindowsFeature AD-Certificate, ADCS-Cert-Authority, ADCS-Web-Enrollment -IncludeManagementTools

3-2. エンタープライズ ルートCA の構成

PowerShellを管理者として起動し、以下のコマンドを実行します。

Install-AdcsCertificationAuthority `
  -CAType EnterpriseRootCA `
  -CACommonName "Yagi-Local-RootCA" `
  -CADistinguishedNameSuffix "DC=yagi,DC=local" `
  -KeyLength 4096 `
  -HashAlgorithmName SHA256 `
  -ValidityPeriod Years `
  -ValidityPeriodUnits 10 `
  -CryptoProviderName "RSA#Microsoft Software Key Storage Provider" `
  -Force

インストール後、CA サービスが起動していることを確認します。

Get-Service certsvc
# Status が Running であることを確認

3-3. ADFS 用証明書テンプレートの作成

ADCSの既定テンプレート「Web Server」を複製し、ADFS用にカスタマイズします。

  1. スタートメニューから certsrv.msc(証明機関)を起動します。
  2. [証明書テンプレート] を右クリックして [管理] を選択します。
  3. Web Server テンプレートを右クリックして [テンプレートの複製] を選択します。
  4. 複製後、以下のタブを設定します。
タブ 設定内容
全般 テンプレート表示名: ADFS-SSL
要求処理 秘密キーのエクスポートを許可する にチェック
セキュリティ YAGI-DC-ADFS01$(コンピュータアカウント)に 登録 権限を追加

▼コンピュータアカウントは、場所の指定 をドメインとして、オブジェクトの種類の選択 をコンピュータにすると表示されます。
image.png
登録 権限を追加して適用します。
image.png

続いて、テンプレートを CA に追加します。

  1. certsrv.msc[証明書テンプレート] を右クリックします。
  2. [新規作成][発行する証明書テンプレート] を選択します。
  3. ADFS-SSL を選択して OK をクリックします。

[証明書テンプレート]ADFS-SSL が表示されれば完了です。
image.png

3-4. ADFS 用 SSL 証明書の要求と発行

CSR(証明書署名要求)の作成

adfs_cert_request.inf として以下の内容のファイルを作成し、Cドライブ直下に配置します。

adfs_cert_request.inf
[Version]
Signature="$Windows NT$"

[NewRequest]
Subject = "CN=adfs.yagi.local, OU=IT, O=Yagi, L=Tokyo, S=Tokyo, C=JP"
KeySpec = 1
KeyLength = 2048
Exportable = TRUE
MachineKeySet = TRUE
SMIME = FALSE
PrivateKeyArchive = FALSE
UserProtected = FALSE
UseExistingKeySet = FALSE
ProviderName = "Microsoft RSA SChannel Cryptographic Provider"
ProviderType = 12
RequestType = PKCS10
KeyUsage = 0xa0
HashAlgorithm = SHA256

[EnhancedKeyUsageExtension]
OID = 1.3.6.1.5.5.7.3.1 ; サーバー認証

[Extensions]
; Subject Alternative Name (SAN) - VPC内プライベートFQDNのみ
2.5.29.17 = "{text}"
_continue_ = "dns=adfs.yagi.local&"
_continue_ = "dns=YAGI-DC-ADFS01.yagi.local&"

今回はADFSへのプライベート通信のみを想定するため、SANにはプライベートFQDNのみを記載します(パブリックFQDNは不要です)。

証明書ベースの認証を使用しないため、certauth.adfs.yagi.local をSANに含めていません。

certauth.* はADFSの証明書認証エンドポイント用のFQDNです。
SANに含めないと Install-AdfsFarm 実行時に、SANが certauth.* をサポートしていないことを示す警告メッセージが表示されます。

警告メッセージは無視して問題ないですが、気になるようならSANの記述に以下を追加してください。

_continue_ = "dns=certauth.adfs.yagi.local&"

(参考)Windows Server の AD FS での証明書認証のための代替ホスト名バインド

PowerShellを管理者として起動し、以下のコマンドを実行してCSRを生成します。

certreq -new C:\adfs_cert_request.inf C:\adfs_cert_request.csr

certreq -new 実行時に The parameter is incorrect と表示される場合、.inf ファイルの文字コードが原因となっていることがあります。
ファイルをBOM無しUTF-8またはANSIで保存し直して再実行してみてください。

CSR を CA に送信して証明書を発行

PowerShellを管理者として起動し、以下のコマンドを実行します。

certreq -submit -attrib "CertificateTemplate:ADFS-SSL" `
  C:\adfs_cert_request.csr `
  C:\adfs_cert.cer

コマンド実行後、「証明機関の一覧」が表示されるので、OK をクリックします。
image.png

certreq -submit 実行時に The permissions on the certificate template do not allow the current user to enroll for this type of certificate と表示される場合、テンプレートのセキュリティ設定でコンピュータアカウントに 登録 権限が付与されていないことが考えられます。

3-3の証明書テンプレート設定にて、コンピュータアカウント YAGI-DC-ADFS01$登録 権限の追加をしましたが、その設定が反映されているか確認してください。

証明書を個人ストアにインストール

PowerShellを管理者として起動し、以下のコマンドを実行します。

certreq -accept C:\adfs_cert.cer

3-5. ルートCA証明書のエクスポート

後続のSTEP 10で検証用サーバに信頼させるため、ルートCA証明書をエクスポートします。
PowerShellを管理者として起動し、以下のコマンドを実行します。

$caName = (Get-ItemProperty "HKLM:\SYSTEM\CurrentControlSet\Services\CertSvc\Configuration").Active
certutil -store "Root" "$caName" C:\YagiRootCA.cer

エクスポートした YagiRootCA.cer は検証用サーバへの転送が必要なため、保管しておきます。

STEP 4: Active Directory Federation Services (ADFS) の構築

ADFSロールをインストールし、STEP 3で発行したSSL証明書を使ってADFSファームを構成します。

4-1. ADFS ロールのインストール

PowerShellを管理者として起動し、以下のコマンドを実行します。

Install-WindowsFeature ADFS-Federation -IncludeManagementTools

4-2. ADFS の構成

PowerShellを管理者として起動し、以下のコマンドを実行します。

# 証明書取得
$cert = Get-ChildItem Cert:\LocalMachine\My | Where-Object { $_.Subject -like "*adfs.yagi.local*" }
$cert | Format-List Subject, Thumbprint, NotAfter

# ADFS構成
Import-Module ADFS

Install-AdfsFarm `
  -CertificateThumbprint $cert.Thumbprint `
  -FederationServiceName "adfs.yagi.local" `
  -FederationServiceDisplayName "Yagi ADFS" `
  -ServiceAccountCredential (Get-Credential -Message "ADFSサービスアカウントのパスワードを入力" -UserName "YAGI\Administrator")

Install-AdfsFarm コマンド実行後、サービスアカウントのパスワードを入力するポップアップが表示されます。
image.png

今回は検証環境のため Administrator をADFSサービスアカウントとして利用しています。

実運用では、以下のような専用アカウントの利用が推奨されます。

  • gMSA(Group Managed Service Account)
  • ADFS専用のドメインユーザ

特にgMSAを利用すると、サービスアカウントのパスワード管理をActive Directory側で自動化できるため、安全かつ運用負荷を低減できます。

4-3. Install-AdfsFarm 実行後の再起動

ADFSファームの構成が完了すると再起動を促すメッセージが表示されるので、OSを再起動します。
PowerShellを管理者として起動し、以下のコマンドを実行します。

Restart-Computer

再起動後、再度RDP接続します。

4-4. DNS Aレコードの登録

adfs.yagi.local の名前解決ができるよう、DNSにAレコードを登録します。PowerShellを管理者として起動し、以下のコマンドを実行します。

# YAGI-DC-ADFS01自身のプライベートIPを取得
$ip = (Get-NetIPAddress -AddressFamily IPv4 -InterfaceAlias "Ethernet*").IPAddress

# adfs.yagi.local のAレコードを登録
Add-DnsServerResourceRecordA -ZoneName "yagi.local" -Name "adfs" -IPv4Address $ip

# 確認
Get-DnsServerResourceRecord -ZoneName "yagi.local" -Name "adfs"

$ip に複数のIPアドレスが取得される場合(複数NICやループバック等)、Add-DnsServerResourceRecordA が失敗することがあります。
その場合は、 Get-NetIPAddress -AddressFamily IPv4 -InterfaceAlias "Ethernet*" で一覧を確認し、プライベートIPを直接 -IPv4Address "172.31.xx.xx" のように指定してください。

4-5. ADFSサービスの確認

PowerShellを管理者として起動し、以下のコマンドを実行してADFSサービスが起動していることを確認します。

Get-Service adfssrv
# Status が Running であることを確認

4-6. フェデレーションメタデータの取得

PowerShellを管理者として起動し、以下のコマンドを実行してメタデータXMLを取得します。

Invoke-WebRequest -Uri "https://adfs.yagi.local/federationmetadata/2007-06/federationmetadata.xml" `
  -OutFile "C:\ADFS_FederationMetadata.xml" `
  -UseBasicParsing

後続で取得するOCI の SP メタデータファイルと混ざらないように、「ADFS_FederationMetadata.xml」というファイル名でCドライブ直下に出力しています。

STEP 5: OCI側の Identity Federation 設定

OCIコンソールにADFSをIDプロバイダとして登録し、IdPポリシーを設定してOCIコンソールと連携させます。

5-1. フェデレーション画面へのアクセス

  1. OCIコンソールにログインします。
  2. ハンバーガーメニューアイデンティティとセキュリティドメイン を開きます。
  3. ADFS連携するユーザが存在するドメインを選択します(今回は Default ドメイン)。
  4. フェデレーション タブをクリックします。

5-2. OCI の SP メタデータのエクスポート

IDプロバイダを追加する前に、OCI側のSPメタデータをエクスポートします。
このファイルは後続のADFS設定(STEP 6)で使用します。

  1. フェデレーション タブ上部の SAMLメタデータのエクスポート ボタンをクリックします。
    image.png
  2. メタデータ・ファイル が選択されていることを確認します。
  3. 自己署名証明書を含むメタデータ の行の XMLのダウンロード をクリックします。
    image.png
  4. ダウンロードされたXMLファイル(ADFS_Metadata.xml)を保管しておきます。

自己署名証明書を含むメタデータ を使用することで、ADFS側のCRL/OCSPチェックをバイパスできるようです。

5-3. SAML IdP(IDプロバイダ)の追加

IdPの作成

  1. アクション ボタン → SAML IdPの追加 をクリックします。
    image.png
  2. 以下を入力して IdPの作成 をクリックします。
項目 入力値
名前 ADFS-yagi-local
説明 AWS EC2上のADFS (yagi.local)
IdPメタデータのインポート STEP 4-6 で取得した ADFS_FederationMetadata.xml をアップロード
リクエストされた名前IDフォーマット なし(デフォルト)
アイデンティティ・プロバイダ・ユーザー属性 SAMLアサーション名ID(デフォルト)
マップ先(アイデンティティ・ドメイン・ユーザー属性) ユーザー名(デフォルト)

ADFSはSTEP 6-3で設定する emailAddress 形式でNameID(test@yagi.local)を送信します。
OCI側は受け取ったNameIDの値をそのままユーザー名として検索するため、デフォルト設定で正しくマッピングされます。

できました。
IdPの作成直後は、ステータスが 非アクティブ になっているので、次の手順でアクティブ化します。
image.png

IdPのアクティブ化とポリシー設定

  1. IdPのアクティブ化 ボタンをクリックし、確認ダイアログで承認します。
    image.png
  2. ステータスが アクティブ に変わったことを確認します。
  3. IdPポリシーに追加 ボタンをクリックします。

IdPポリシーのルール設定

  1. 遷移先の画面で IdPポリシーの作成 をクリックします。
    image.png
  2. 名前に ADFS Federation Policy を入力します(任意の名前で構いません)。
  3. アイデンティティ・プロバイダ・ポリシーの作成 をクリックします。
    image.png
  4. 遷移先の画面で IdPルールの追加 をクリックします。
    image.png
  5. 以下を入力して IdPルールの追加 をクリックします。
項目 設定値
ルール名 ADFS-yagi-local-rule
アイデンティティ・プロバイダの割当て ADFS-yagi-local
式配置 式で始まる ※デフォルト
ユーザー名式の入力 空欄 ※デフォルト(すべてのユーザーを対象とする)
ユーザーを除外 ADFSを経由させたくないユーザ(特権ユーザー等)を指定する
クライアントIPアドレスでフィルタ 任意の場所

ユーザーを除外 に指定したユーザはこのIdPルールの対象外となり、OCIのローカル認証(パスワードログイン)が使用されます。
ルートユーザーや緊急アクセス用の特権ユーザーはここに登録しておくことを推奨します。

IdPとOCIコンソールの連携

  1. IdPポリシー画面で アプリケーション タブを開きます。
  2. アプリケーションの追加 をクリックします。
    image.png
  3. 一覧から OCI Console を選択します。
    image.png
  4. アプリケーションの追加 をクリックします。

この設定を実施することで、OCIコンソールのサインイン画面にIdP「ADFS-yagi-local」が表示されるようになります。
これをクリックすることでADFSへSAMLリダイレクトされ、ADFS認証によりOCIにログインできます。
image.png

STEP 6: ADFS に OCI の証明書利用者信頼 (Relying Party Trust) を追加

ADFS側にOCIをサービスプロバイダ(SP)として登録し、SAMLアサーションに含めるクレームルールを設定します。

6-1. ADFS 管理コンソールの起動

スタートメニューから AD FSの管理 を起動します。
image.png

6-2. 証明書利用者信頼の追加

PowerShellを管理者として起動し、以下のコマンドを実行します。
事前にSTEP 5-2でエクスポートした ADFS_Metadata.xmlC:\OCI_SP\ 配下に配置してておいてください。

# OCIのSPメタデータXMLを C:\OCI_SP\ 配下に配置済みとして実行
# (STEP 5-2 でエクスポートした ADFS_Metadata.xml を YAGI-DC-ADFS01 に転送し、
#   ADFS側のメタデータ ADFS_FederationMetadata.xml と混同を避けるため、別フォルダに配置)
$metadataPath = "C:\OCI_SP\ADFS_Metadata.xml"

Add-AdfsRelyingPartyTrust `
  -Name "OCI-Console" `
  -MetadataFile $metadataPath `
  -AutoUpdateEnabled $false `
  -MonitoringEnabled $false `
  -Enabled $true

# 確認
Get-AdfsRelyingPartyTrust -Name "OCI-Console"

6-3. 要求発行変換規則 (Claim Issuance Policy) の設定

OCI IAM ユーザ名(test@yagi.local)と AD の UPN(test@yagi.local)を一致させるため、NameID に UPN の値をそのままメールアドレス形式で送信する規則を設定します。
PowerShellを管理者として起動し、以下のコマンドを実行します。

ユーザ名マッピングの方針:

  • AD ユーザ UPN: test@yagi.local
  • SAML NameID として送信する値: test@yagi.local(UPN、emailAddress形式)
  • OCI IAM ユーザ名も test@yagi.local で作成しておくことで、NameID の値と完全一致し自動的にマッピングされる。
項目
AD UPN test@yagi.local
ADFS が NameID として送信する値 test@yagi.local
OCI が検索する IAM ユーザ名 test@yagi.local
# 規則1: AD から UPN と sAMAccountName を取得
$rule1 = @"
@RuleTemplate = "LdapClaims"
@RuleName = "Get AD Attributes"
c:[Type == "http://schemas.microsoft.com/ws/2008/06/identity/claims/windowsaccountname",
   Issuer == "AD AUTHORITY"]
 => issue(store = "Active Directory",
          types = (
            "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/upn",
            "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/samaccountname"
          ),
          query = ";userPrincipalName,sAMAccountName;{0}",
          param = c.Value);
"@

# 規則2: UPN を NameID(emailAddress形式)として送信
#         → "emailAddress" はSAMLのNameIDフォーマットの識別子名であり、
#            実際にメールアドレスとして有効である必要はない。
#            "@" を含む文字列であれば "test@yagi.local" のようなローカルドメインでも問題なく動作する。
#         → OCIはこの値("test@yagi.local")を文字列としてIAMユーザ名と照合する。
$rule2 = @"
@RuleName = "Send UPN as NameID"
c:[Type == "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/upn"]
 => issue(Type = "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier",
          Issuer = c.Issuer,
          OriginalIssuer = c.OriginalIssuer,
          Value = c.Value,
          ValueType = c.ValueType,
          Properties["http://schemas.xmlsoap.org/ws/2005/05/identity/claimproperties/format"] =
            "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress");
"@

Set-AdfsRelyingPartyTrust `
  -TargetName "OCI-Console" `
  -IssuanceTransformRules ($rule1 + $rule2)

# 設定確認
Get-AdfsRelyingPartyTrust -Name "OCI-Console" | Select-Object -ExpandProperty IssuanceTransformRules

6-4. 発行承認規則 (Issuance Authorization Rules) の設定

デフォルトでは全ユーザのトークン発行が拒否されるため、許可する規則を追加します。
PowerShellを管理者として起動し、以下のコマンドを実行します。

# ADFS に正常認証できたユーザーは、OCI-Console へのトークン発行を許可する
$authRule = @"
@RuleTemplate = "AllowAllAuthzRule"
 => issue(Type = "http://schemas.microsoft.com/authorization/claims/permit",
          Value = "true");
"@

Set-AdfsRelyingPartyTrust `
  -TargetName "OCI-Console" `
  -IssuanceAuthorizationRules $authRule

# 設定確認
Get-AdfsRelyingPartyTrust -Name "OCI-Console" | Select-Object -ExpandProperty IssuanceAuthorizationRules

STEP 7: OCI IAM ユーザの設定

ADユーザのUPNと一致するユーザ名でOCI IAMユーザを作成し、フェデレーテッド認証を有効化します。

7-1. IAMユーザの作成

  1. OCIコンソールにログインします。
  2. ハンバーガーメニューアイデンティティとセキュリティドメイン を開きます。
  3. Default ドメインをクリックします。
  4. ユーザー管理 タブをクリックします。
  5. ユーザの 作成 ボタンをクリックします。
  6. 以下を入力して 作成 をクリックします。
項目
TEST(任意)
ADFS(任意)
ユーザー名として電子メール・アドレスを使用 オフ
ユーザー名 test@yagi.local
電子メール 有効なメールアドレス(例: test@example.com

ユーザー名として電子メール・アドレスを使用 をオフにすることで、ユーザー名と電子メールを別々に設定できます。

.local ドメインのメールアドレスは一般的なインターネットメールとしては利用できないため、電子メール欄には実在する有効なアドレスを入力する必要があります。
電子メール として test@yagi.local を指定するとエラーになります。

認証に使用されるのはユーザー名(test@yagi.local)のみであり、電子メールはOCIからの通知用途にすぎません。
なお、OCI IAM のユーザ名には @ を含めることができます。
ここでは、OCI IAM のユーザ名と AD の UPN と完全一致させることが重要です。

ADFSフェデレーションの検証が目的なので、今回はグループの指定はしません。

7-2. IAMユーザのフェデレーテッドの有効化

  1. 作成したユーザー test@yagi.local をクリックします。
  2. ユーザーの編集 ボタンをクリックします。
    image.png
  3. アイデンティティ・プロバイダ情報 セクションの フェデレーテッド をオンにします。
    image.png
  4. 変更の保存 をクリックします。

・・・

この設定を行うことで、当該のIAMユーザではOCIのローカル認証(パスワードログイン)は利用できなくなります。

この状態で、ログイン画面の「Forgot Password?」ボタンをクリックして、当該のIAMユーザのパスワードリセットを行おうとしても、それができないことは確認済みです。

パスワードリセット画面でユーザ名を指定すると
image.png

パスワード・リセット通知送信済 と表示されますが、実際にそのメールは届きません。
image.png

↓のように フェデレーテッド をオフにすると、パスワードリセットのメールが届くようになることを確認済みです。
image.png

STEP 8: フェデレーテッドユーザのMFA無効化設定(任意)

OCI Identity Domains のデフォルト設定では、すべてのIAMユーザにMFAが要求されます。
「AD側でADユーザのMFAが設定されていてOCI側でのMFAは必須ではない」というケースでは、フェデレーテッドユーザのMFA無効化が可能です。

こちらのブログに従って、OCI側のMFAを無効化するサインオンルールを追加します。

8-1. サインオン・ポリシーへのルール追加

  1. OCIコンソールにログインします。
  2. ハンバーガーメニューアイデンティティとセキュリティドメインDefault を開きます。
  3. ドメイン・ポリシーサインオン・ポリシーSecurity Policy for OCI Console を選択します。
  4. サインオン・ルールの追加 をクリックします。
    image.png
  5. 以下を設定します。
項目 設定値
ルール名 Federated-Users-NoMFA
条件(認証アイデンティティ・プロバイダ) ADFS-yagi-local を選択
その他の設定 すべてデフォルトのまま

ここで、追加ファクタの要求 がオフになっていることを確認してください。
「ほんまにMFAオフでええんか?」と同意を求めるチェックボックスが表示されるので、✅を入れて、理由も入れておきます。
image.png

追加 をクリックして、ルールが追加できればOKです。

8-2. ルールの優先度を最高位に設定

優先度ポリシーに基づき、追加したルールを最上位に配置する必要があります。

  1. ルール一覧で Federated-Users-NoMFA を選択します。
  2. 優先度の編集 をクリックします。
    image.png
  3. Federated-Users-NoMFA の優先度を 1 に設定します。
    それに従って、他のルールの優先度も調整します(1個優先度を下げる)
    image.png

STEP 9: DNS 設定の確認

ADDS インストール時にDNSサーバロールも同時にインストールされているため、YAGI-DC-ADFS01 自身がDNSサーバとして機能します。
DNSサーバとして正しく動作していることを確認します。

PowerShellを管理者として起動し、以下のコマンドを実行します。

Get-Service DNS
# Status が Running であることを確認

Get-DnsServerZone | Select-Object ZoneName, ZoneType
# "yagi.local" ゾーンが存在することを確認

STEP 10: 検証用サーバの準備

AD・ADFSサーバ(YAGI-DC-ADFS01)側の設定が完了したら、検証用サーバ(ドメイン非参加)で以下の設定を行います。
動作確認の前提として、内部CAが発行した証明書を信頼させ、adfs.yagi.local の名前解決ができる状態にします。

ここから、検証用EC2インスタンスにRDP接続して操作を進めます。

10-1. ルートCA証明書のコピー

YAGI-DC-ADFS01 でエクスポートした YagiRootCA.cer を検証用サーバのCドライブ直下にコピーします(RDP経由でファイル転送)。

10-2. ルートCA証明書のインポート

検証用サーバ上でPowerShellを管理者として起動し、以下のコマンドを実行します。

certutil -addstore "Root" C:\YagiRootCA.cer

続いて、以下のコマンドでインポートを確認します。

Get-ChildItem Cert:\LocalMachine\Root | Where-Object { $_.Subject -like "*Yagi*" } |
  Select-Object Subject, Thumbprint, NotAfter
# "Yagi-Local-RootCA" が表示されれば信頼済み

10-3. DNSサーバの設定

検証用サーバのネットワークアダプタに、YAGI-DC-ADFS01 のプライベートIPをDNSサーバとして設定します。
PowerShellを管理者として起動し、以下のコマンドを実行します。

# ネットワークインターフェース名(Ethernet)を確認
Get-NetAdapter

# DNSサーバをYAGI-DC-ADFS01のプライベートIPに設定
Set-DnsClientServerAddress -InterfaceAlias "Ethernet" -ServerAddresses "172.31.xx.xx"

# 確認
Get-DnsClientServerAddress -InterfaceAlias "Ethernet"

Set-DnsClientServerAddress 実行時に No MSFT_DNSClientServerAddress objects found と表示される場合、インターフェース名が Ethernet と異なります。

Get-NetAdapter で実際のインターフェース名を確認し、-InterfaceAlias に正しい名前を指定してください。

10-4. 名前解決の確認

PowerShellを管理者として起動し、以下のコマンドを実行して adfs.yagi.local が正しく解決されることを確認します。

Resolve-DnsName adfs.yagi.local
# YAGI-DC-ADFS01のプライベートIPが返ることを確認

10-5. ADFS の動作確認(検証用サーバのブラウザから)

ブラウザから以下のURLにアクセスし、ADFSのログインページが表示されることを確認します。

https://adfs.yagi.local/adfs/ls/idpinitiatedsignon

image.png

An error occurred - The resource you are trying to access is not available. と表示されますが、想定通りです。
これはIdP起点(IdP-initiated)のSSOでADFSに直接アクセスした際、発行承認規則(Issuance Authorization Rules)でユーザーのアクセスが拒否されているために発生します(ADFSサーバ側のイベントビューアーでは「EventID 325」で記録されています)。

SP起点(SP-initiated)のSSO(OCIコンソールのログイン画面からADFSにリダイレクトされるフロー)では発生しないため、SSOの動作確認が正常に完了していれば無視して問題ありません。

が、もしエラーを解消したい場合は、ADFS側でIdP起点のSSOを有効にします。

# IdP起点のSSOの有効化
Set-AdfsProperties -EnableIdPInitiatedSignonPage $true

# 確認
Get-AdfsProperties | Select-Object EnableIdPInitiatedSignonPage

IdP起点のSSOの有効化が完了したら、再度 https://adfs.yagi.local/adfs/ls/idpinitiatedsignon にアクセスしてみてください。
ID・パスワードの入力フォームが出てくるはずです。

STEP 11: 動作確認

検証用サーバからOCIコンソールにアクセスし、ADFS認証でログインできることを確認します。

  1. 検証用サーバのブラウザからOCIコンソールのURLにアクセスします。
    https://www.oracle.com/cloud/sign-in.html
    
  2. テナント名を入力して 次へ をクリックします。
  3. ADFS-yagi-local をクリックします。
    image.png
  4. AD FS のログインページにリダイレクトされることを確認します。
    image.png
  5. ユーザ名 test@yagi.local / パスワード UserP@ssw0rd! を入力します。
  6. OCI マネジメントコンソールに test@yagi.local ユーザとしてログインできることを確認します。
    image.png

OCIコンソールへのSSOが確認できました!

ADFSのログインページで認証後、何らかのエラーが表示される場合は、「YAGI-DC-ADFS01」側のイベントビューアー(eventvwr.msc)を開き、 アプリケーションとサービスログAD FSAdmin からエラーの詳細を確認してください。

通信フロー

最後に、本構成におけるSAML SSOの通信フローを整理します。
各通信がインターネット経由か内部NW経由かに着目してください。

認証時のSAMLアサーションはブラウザ経由で運ばれ(③〜⑧)、ADFSとOCIが直接SAMLアサーションを送受信するわけではありません。

また、③〜⑤・⑧のブラウザ↔ADFS間の通信から、⑥⑦のAD認証まで、すべて内部NW(VPC内)に閉じた通信です。

この構成により、ADFSを開発・本番で分けて内部NWのFWで通信制御することで、OCI側のIPアドレスによるアクセス制御に頼らずに環境の分離を実現できます。

補足(全IAMユーザへのADFS強制について)

OCIの全IAMユーザに強制的にADFSを利用させる設定も可能です。

しかし、ADFSサーバや内部NWで障害が発生し、ADFS認証が利用できなくなったとき、暫定対応として一時的にIAMユーザのパスワード認証を利用することも想定されます。

そのため、本記事では、あくまでOCIコンソールの認証画面ではOCIのローカル認証(パスワードログイン)とADFS認証を選択できるようにし、IAMユーザ側の設定(STEP 7-2)でIdPをADFSに誘導してあげることを推奨します。
これにより、一般ユーザはADFS認証に限定するが、ルートユーザーや緊急アクセス用の特権ユーザーはADFS認証を利用しない、という設計が可能になります。

参考資料

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?