Amazon FSx for Windows File Server の Active Directory 検証ツールを試してみた

2021.03.17

しばたです。

Amazon FSx for Windows File Server(以後 FSx for Windows)では認証基盤としてオンプレ環境などにあるActive Directoryを直接使用することができます。

FSx for WindowsでセルフマネージドなActive Directoryを利用するには所定の前提条件を満たしておく必要があり、前提条件を満たしているか確認するための検証ツールも提供されています。

本記事ではこの検証ツールの概要と検証内容について解説します。

事前準備

この検証ツールはPowerShellモジュールとして提供されています。
FSx for Windowsを展開するサブネットに検証用EC2を用意し、EC2内部からPowerShellモジュールのコマンドを実行することで検証を行います。

ドキュメントでは検証ツールを実行するにあたり以下の事前準備が必要とされていますが、検証内容によっては不要なものもありますので環境に応じて必要な分を準備しておけば良いでしょう。

  • (必須) EC2インスタンスはWindows Serverであること
    • 検証ツールでは内部でAWS Tools for PowerShellの機能を使う
    • 検証ツールでは内部でAcitveDirectoryモジュールを使うためPowerShell on Linuxは不可
    • OSバージョンに対する要件は明記されていない
  • (ほぼ必須) EC2インスタンスにec2:DescribeSubnets, ec2:DescribeVpcsの権限を持つIAMロールをアタッチする
    • ドキュメントではAmazonEC2ReadOnlyAccessロールを与えておく手順となっている
    • 検証ツールでポートスキャンするだけなら不要。それ以外の検証では必須
  • (ほぼ必須) EC2インスタンスが対象Active Directoryドメインに参加していること
    • ドキュメントでは対象ドメインへの参加を要求されているが、不参加でもなんとかなる
    • 検証ツールでポートスキャンするだけならドメインへの参加は不要

特に対象ドメインへの参加については、そもそもドメインに参加できるなら検証は半分くらい終わっているわけで個人的には微妙な要件だと感じています。

私が試した限りではEC2が参照するDNSサーバーを当該ドメインコントローラーに向けておけばドメイン不参加の状態でも検証を実行することができましたので、まずはドメイン不参加の状態で検証を試し必要が出た時点でドメイン参加するのが良いのではないかと思います。
(なお、DNSサーバーの設定を変えないと後述の検証Test 7でエラーとなる)

EC2の準備

本記事では具体的なEC2インスタンスの構築手順は割愛します。
CLI、マネジメントコンソール、好きな方法で用意してください。

前述の通りOSバージョンに対する要件は明記されていないのですが、最新のWindows Server 2019にしておけば問題ないでしょう。

IAMロールについても適宜設定してください。
本記事ではAmazonEC2ReadOnlyAccess権限を持つロールのCloudFormation Templateを一例として紹介しておきます。

AWSTemplateFormatVersion: 2010-09-09
Parameters:
  RoleName:
    Description: "Input role name."
    Type: String
    Default: "EC2RoleforFSxADValidation"
Resources:
  # IAM Role
  FSxRole:
    Type: AWS::IAM::Role
    Properties:
      RoleName:
        Fn::Sub: "${RoleName}"
      AssumeRolePolicyDocument:
        Version: "2012-10-17"
        Statement:
          - Effect: "Allow"
            Principal:
              Service:
                - "ec2.amazonaws.com"
            Action:
              - "sts:AssumeRole"
      Path: "/"
      ManagedPolicyArns:
        - "arn:aws:iam::aws:policy/AmazonEC2ReadOnlyAccess"
  # Instance Profile
  FSxRoleInstanceProfile:
    Type: "AWS::IAM::InstanceProfile"
    Properties:
      InstanceProfileName:
        Fn::Sub: "${RoleName}"
      Path: "/"
      Roles:
        - Ref: FSxRole

検証ツールのインストール

EC2を構築した後は検証ツールのインストールを行います。

前述の通り検証ツールでは内部でAcitveDirectoryモジュールを使用するため、Install-WindowsFeatureを使ってモジュールを含むリモート管理ツールをインストールします。

# (要管理者権限) Active Directoryリモート管理ツールをインストール
Install-WindowsFeature RSAT-AD-PowerShell

次に、管理ツールはAWSのサイト上でZipファイル形式で提供されているので任意のフォルダにダウンロードして展開します。
以下の例ではC:\fsxというフォルダを用意しそこにツールを展開しています。

# 今回は C:\fsx というディレクトリを作りそこで諸々の作業を実施
mkdir C:\fsx
cd C:\fsx\

# FSx 検証ツールのダウンロードと解凍
Invoke-WebRequest "https://docs.aws.amazon.com/fsx/latest/WindowsGuide/samples/AmazonFSxADValidation.zip" -OutFile "AmazonFSxADValidation.zip"
Expand-Archive -Path "AmazonFSxADValidation.zip"

これでC:\fsx\AmazonFSxADValidationに検証ツールが展開され利用可能な状態になります。
以上で事前準備は完了です。

試してみた

ここからは検証ツールを実際に試していきます。

はじめに前項で展開したモジュールをImport-Moduleで明示的にインポートします。

# 前項で展開したモジュールをインポートする
cd C:\fsx\
Import-Module .\AmazonFSxADValidation

警告: 既定のドライブを初期化中にエラーが発生しました: 'Active Directory Web サービスが実行されている状態で既定のサーバーを検索することはできません。'。

環境によっては上記の警告が出ることもありますが、これは無視して構いません。

Get-Commandを使い検証ツールで公開されているコマンドを調べると以下の3コマンド用意されていることがわかります。

Get-Command -Module AmazonFSxADValidation

CommandType     Name                                               Version    Source
-----------     ----                                               -------    ------
Function        Test-FSxADConfiguration                            1.0        AmazonFSxADValidation
Function        Test-FSxADControllerConnection                     1.0        AmazonFSxADValidation
Function        Test-FSxADDnsConnection                            1.0        AmazonFSxADValidation

1. ポートスキャン (Test-FSxADDnsConnection, Test-FSxADControllerConnection)

公開されているコマンドのうちTest-FSxADDnsConnectionTest-FSxADControllerConnectionについてはポートスキャンを行うものになります。
これらについてはドメイン不参加、IAMロール未設定の状態でも実行可能です。

Test-FSxADDnsConnectionはDNSサーバーに対するポートスキャンを行い、TCP 53、UDP 53番ポートへの疎通をチェックします。

# DNSサーバーへのポートスキャンは Test-FSxADDnsConnection
Test-FSxADDnsConnection -ADDnsIp <対象サーバーのIP> -OutVariable result

# 実行結果の詳細は以下
$result.Success
$result.TcpDetails
$result.UdpDetails

Test-FSxADControllerConnectionはドメインコントローラーに対するポートスキャンを行い、TCP 88,135,389,445,464,636,3268,9389、UDP 88,123,389,464番ポートへの疎通をチェックします。

# ドメインコントローラーへのポートスキャンは Test-FSxADControllerConnection
Test-FSxADControllerConnection -ADControllerIp <対象サーバーのIP> -OutVariable result

# 実行結果の詳細は以下
$result.Success
$result.TcpDetails
$result.UdpDetails

2のコマンドで微妙にパラメーター名が異なりますが細かい説明無くお使いいただけるかと思います。

スキャンした全体の結果についてはSuccessプロパティから取得可能で、プロトコルごとの結果はそれぞれTcpDetailsUdpDetailsプロパティから取得できます。
ポート毎のスキャン結果についてはPortQryの内容に準じ、

  • Listening : ポートが解放されている
  • Listening or Filtered : ポートが解放されているかブロックされているか不明
  • その他 : エラーの場合

を返します。

【注意】UDPのスキャン結果について

ここで補足なのですが、残念ながらこの検証ツールではUDPのポートスキャンの実装が悪く常に「Listening or Filtered」を返してしまいます。
(TCPのポートスキャンは問題ありません)

UDPはTCPの様に"わかりやすい"ハンドシェイクが無いため元来ポートスキャンが面倒な事情があります。
UDPでは正しいパケットを送り付けないとポートが空いていても応答を返さないものがあり、検証ツールで検査するポートは全てその類です。

この検証ツールでは以下の様にシンプルに?(0x3f)を送り付ける実装となっているためどのプロトコルも応答を返してくれません。

#
# UDPのポートスキャン実装から一部抜粋
#
$Result = "Unknown"
$UdpClient = New-Object System.Net.Sockets.UdpClient
$UdpClient.Client.ReceiveTimeout = $Timeout
Try {
    $Connect = $UdpClient.Connect($Server, $Port)
    $Acsii = New-Object System.Text.ASCIIEncoding
    $Bytes = $Acsii.GetBytes("?");
    [void]$UdpClient.Send($Bytes, $Bytes.length)
    $RemoteEndpoint = New-Object System.Net.IpEndpoint([System.Net.IpAddress]::Any, 0)
    $ReceiveBytes = $UdpClient.Receive([ref\]$RemoteEndpoint)
    [string]$ReturnData = $Acsii.GetString($ReceiveBytes)
    If ($ReturnData) {
        $Result = "Listening"
    }
} Catch [System.Net.Sockets.SocketException] {
    $SocketException = $_.Exception
    # https://msdn.microsoft.com/en-us/library/ms740668.aspx
    If (($SocketException.ErrorCode -eq 10054) -or ($SocketException.ErrorCode -eq 10061)) {
        $Result = "SocketError $SocketException.ErrorCode"
    } Else {
        # Treat everything other than explicitly refused to be success for UDP.
        $Result = "Listening or Filtered"
    }
} Finally {
    $UdpClient.Dispose()
}

UDPのポートスキャンを正確に行いたい場合はこのツールではなく、PortQryNmapを使うと良いでしょう。
とはいえPortQryやNmapでも限界はあり、私が調べた限り以下の対応状況でした。

ポート プロトコル PortQry 2.0 Nmap 7.91 (デフォルト設定)
UDP 53 DNS 〇:正しい結果を返す 〇:正しい結果を返す
UDP 88 Kerberos認証 ×:非対応 ×:非対応 (ただしkrb5-enum-usersスクリプトによる調査は可)
UDP 123 NTP ×:非対応 〇:正しい結果を返す
UDP 389 LDAP 〇:正しい結果と詳細情報を返す ×:非対応 (ただしldap-searchスクリプトによる調査は可)
UDP 464 Kerberosパスワード変更(kpasswd5) ×:非対応 ×:非対応

2. Active Directoryの検証 (Test-FSxADConfiguration)

Active Directoryの検証にはTest-FSxADConfigurationコマンドを使います。
このコマンドの実行には

  • EC2に対するIAMロールの設定は必須
  • 最低限EC2のDNS設定を切り替えておく事(最悪ドメインに参加させる)

の前提条件が必要となります。

このコマンドは以下の様な感じで多数の引数を取ります。
各パラメーターの詳細はモジュールに付属しているREADMEを一読いただきたいですが、以下の例を環境に合わせて改変して実行する形でも良いかと思います。

# FSx管理者ユーザーの認証情報を指定 (ユーザー指定はSPNでなく単純なユーザー名にする必要あり)
$password = ConvertTo-SecureString '<平文のパスワード>' -AsPlainText -Force
$credential = New-Object System.Management.Automation.PSCredential ('fsxadmin', $password)

# 各種パラメーター設定+コマンド実行
$FSxADValidationArgs = @{
    # 対象ドメインのDNS名を指定
    DomainDNSRoot = 'corp.contoso.com'

    # 対象ドメインのDNSサーバーのIPアドレスを指定
    DnsIpAddresses = @('xxx.xxx.xxx.xxx', 'yyy.yyy.yyy.yyy')

    # FSx管理用OUを識別名で指定
    OrganizationalUnit = 'OU=FSxOU,DC=corp,DC=contoso,DC=com'

    # FSx管理者の所属するグループ名を指定
    AdminGroup = 'FSxGroup'

    # FSxを配備するサブネットのサブネットIDを指定
    SubnetIds = @('subnet-1234567890', 'subnet-9876543210')

    Credential = $credential
}
$result = Test-FSxADConfiguration @FSxADValidationArgs

コマンドを実行すると以下の様な感じで「対象ドメインにテスト用のオブジェクトを作成するが良いか?」と聞かれますので問題なければ「y」を入力し検証を続行してください。

Testing service account permissions is not currently enabled. If enabled, script will create test Active Directory computer objects in the organizational unit. This will be cleaned up by the script unless delete permissions are not properly configured on the provided service account in which case manual cleanup may be necessary. Do you want to enable testing? [y/n]:

テスト用オブジェクトはFSx管理用OUに作成され検証が終わると同時に削除されます。
私が調べた限りではFSx管理用OU以外の場所に対する更新はありませんでしたので、あまり気にせずテストを続行して構わないと思います。

検証は全部で16個のテストから構成されており、途中でエラーがでると以降のテストは全てスキップされます。

全てテストが無事完了すると以下の様な感じになります。

テスト結果は$result変数に格納されますので、こちらの各種プロパティから詳細情報を取得できます。

Test-FSxADConfiguration の検証一覧

Test-FSxADConfigurationで行われる16個のテストの一覧は以下となります。

Test 1 - Validate EC2 Subnets

EC2にインストール済みのAWS Tools for PowerShell(Get-Ec2Subnet, Get-Ec2Vpc)を使い、指定のサブネット群がすべて同一のVPCにあるか、別々のAZに分かれているかをチェックします。
テストに合格するとVPC、サブネット情報が戻り値に追加されます。

当然ですが、EC2にIAMロールが割り当てられていないとこのテストには合格しません。

Test 2 - Validate connectivity with DNS Servers

指定のDNSサーバーに対して特定のSRVレコード(_ldap._tcp.dc._msdcs.<ドメイン名>等)の存在チェックを行い、DNSサーバーに対する疎通を確認します。
テストに合格するとドメインコントローラの情報が戻り値に追加されます。

Test 3 - Validate FSx service user credentials

指定されたFSx管理ユーザーがドメインに存在するかチェックします。同時にドメイン情報の取得も行います。
テストに合格するとドメイン情報が戻り値に追加されます。

FSx管理ユーザーの認証情報に誤りがある場合はここでエラーになります。

Test 4 - Validate domain properties

Test 3の結果を元に

を確認します。

Test 5 - Validate organizational unit

指定のFSx管理用OUがドメインに存在するかチェックします。
テストに合格するとOU情報が戻り値に追加されます。

Test 6 - Validate Admin Group

指定のFSx管理ユーザー用グループがドメインに存在するかチェックします。
テストに合格するとグループ情報が戻り値に追加されます。

Test 7 - Validate that provided EC2 Subnets belong to a single AD Site

指定のサブネットがどのActive Directoryサイトに存在するか、複数のサイトにまたがる様なアドレスになっていないかをチェックします。
テストに合格するとサイト情報が戻り値に追加されます。

Test 8 - Looking up DNS entries for domain controllers in site <サイト名>

指定のDNSサーバーに対して特定のSRVレコード(_ldap._tcp.<サイト名>._sites.dc._msdcs.<ドメイン名>等)の存在チェックを行い、サイトに関連するDNSレコードが正しく取得できるかチェックします。

Test 9 - Validate connectivity with at least one AD Domain Controller in AD site <サイト名>

これまでのテストで取得した情報を踏まえてドメインコントローラーへの疎通チェックを行います。

内部でTest-FSxADControllerConnectionを使用しているため、残念ながらUDPのチェックは当てになりません。

Test 10 - Validate 'Create Computer Objects' permission

指定のFSx管理用OUに対しコンピューターオブジェクトが作成可能かチェックします。

このテストではamznfsxtestXXXX (XXXXはランダムな16進数)というオブジェクトを実際に作成します。

Test 11 - Validate 'Validated write to DNS host name' permission

FSx管理者ユーザーがコンピューターオブジェクトに対するDNS名の更新権限を持っているかチェックします。
Test 10で作成したテスト用コンピューターオブジェクトを更新すること(Set-ADComputer)で権限を確認しています。

Test 12 - Validate 'Validated write to service principal name' permission

FSx管理者ユーザーがコンピューターオブジェクトに対するサービスプリンシパル名(SPN)の更新権限を持っているかチェックします。
Test 10で作成したテスト用コンピューターオブジェクトを更新すること(Set-ADComputer)で権限を確認しています。

Test 13 - Validate 'Reset Password' permission

FSx管理者ユーザーがパスワードリセットの権限を持っているかチェックします。
Test 10で作成したテスト用コンピューターオブジェクトにランダムなパスワードを設定すること(Set-ADAccountPassword)で権限を確認しています。

Test 14 - Validate 'This Organization' list children permission

指定のFSx管理用OUの子要素に対する参照権限があるかチェックします。
Test 10で作成したテスト用コンピューターオブジェクトの認証情報を使い自分自身を参照(Get-ADComputer)可能か確認しています。

Test 15 - Validate 'Read and write Account Restrictions' permission

FSx管理者ユーザーがコンピューターオブジェクトに対するアカウント制限の更新権限を持っているかチェックします。
Test 10で作成したテスト用コンピューターオブジェクトの属性を更新すること(Set-ADAccountControl -PasswordNotRequired $False)で権限を確認しています。

Test 16 - Validate 'Delete Computer Objects' permission

FSx管理者ユーザーがコンピューターオブジェクトに対する削除権限を持っているかチェックします。
Test 10で作成したテスト用コンピューターオブジェクトを削除することで確認しています。

これですべてのテストが完了です。

最後に

以上となります。

導入までのハードルが若干高いツールですが詳細な検証を行っていると感じました。
ポートスキャンについてはちょっと残念なところがありましたが他ツールを併用すれば問題にはならないでしょう。

FSx for Windowsの導入に際し必要に応じて使ってみてください。