Active Directory Federation Servicesを使用してRedshiftへ接続してみた

2022.07.07

どーもsutoです。

Active Directory Federation Services(ADFS)による認証を経由してRedshiftへ接続する検証を行う機会がありましたので、その備忘録をかねて記事にしようと思います。

やりたいこと

まずは本検証における構成を図に表します。

その上で以下の要件を満たすように設定します。

  • 上図の仕組みでRedshiftにADサーバー上のユーザー情報を使ってRedshiftにログイン
  • 既存のRedshiftユーザー名と、ADサーバーのユーザー名が一致していればログイン可能とする

接続対象のRedshiftクラスターは、以下のとおり事前に作成済であることとします。

  • クラスター名 - redshift-cluster-1
  • データベース名 - dev
  • リージョン - ap-northeast-1
  • 以下のとおり、ユーザー名を作成済
ALTER USER suto PASSWORD DISABLE;

ドメインコントローラーとADFSのセットアップ

  • 検証用のADFSサーバーをEC2で作成します。こちらのCloudFormationテンプレートを起動します。

  • スタック名と以下のパラメーターを指定してください。

    • Amild – デフォルトのままにします
    • DomainDNSName – adfsredshift.com
    • DomainNetBIOSName – adfsredshift
    • InstanceType –デフォルトのままにします(m5.large)
    • KeyName - このEC2インスタンスで使用するキーペアを指定してください
    • RestoreModePassword – ご自身で選択したパスワードを入力します(忘れないように注意してください)
    • SourceCidrForRDP – ご自身の作業端末のIPアドレス(x.x.x.x/32)を入力します
  • 最後の画面まで進み、「スタックの作成」を選択してCompleteになるまで待機します。これによってWIndows2016のEC2インスタンスが作成されます。

  • 次に上記EC2インスタンスのセキュリティグループの設定を変更します。

  • インバウンドの編集を選択して、プロトコル[HTTPS]でソース[マイIP]を追加して保存します。

  • 次にRDPクライアントを使用してADFSサーバー(WindowsEC2インスタンスにRDP接続します。キーペアから管理者パスワードを取得してAdministratorでログインします。

  • Windowsコマンドプロンプトを使用してADでテストユーザーとグループを作成します(今回はユーザー名[suto]とユーザーグループ名[AWS-Production]、ADFS構成用のサービスアカウント[ADFSSVC]を作成します。

dsadd user "cn=Suto,cn=Users,dc=adfsredshift,dc=com" -samid suto -upn suto@adfsredshift.com -email suto@adfsredshift.com -fn Suto -ln Smith -display "Suto Test" -disabled no -pwd "任意のパスワードを指定"

dsadd group "cn=AWS-Production, cn=Users, dc=adfsredshift, dc=com" -members "cn=Suto, cn=Users, dc=adfsredshift, dc=com"

dsadd user "cn=ADFSSVC,cn=Users,dc=adfsredshift,dc=com" -display "ADFS Service" -disabled no -pwd " 任意のパスワードを指定“
  • PowerShellを使用してADFS2016の役割をインストールします。
PS C:\Users\Administrator> Install-windowsfeature adfs-federation –IncludeManagementTools

フェデレーションサーバーは、インターネットインフォメーションサービス(IIS)のSecure Sockets Layer(SSL)証明書などのサーバー認証証明書を使用します。詳細については、フェデレーションサーバーの証明書要件を参照してください。

今回は検証なので、IISで作成した自己署名証明書を使用しますが、推奨されるベストプラクティスとして、本番環境では自己署名SSL証明書は推奨されません。

  • 自己署名証明書を作成するには、PowerShellを使用してIISをインストールおよび構成します。
PS C:\Users\Administrator> Install-WindowsFeature -name Web-Server -IncludeManagementTools
  • インストールが完了したら、[管理ツール]で、IISを開きます。

  • IISサーバーを選択し、[サーバー証明書]を選択します。

  • [アクション]で、 [自己署名証明書の作成]を選択します。

  • ADFSCertificateなどの任意の名前を入力し、[OK]を選択します。

これでADFS構成に必要な設定を用意できました。

ADFSでのフェデレーションの構成

  • Windows 2016 EC2インスタンスで、サーバーマネージャーを開きます。

  • フラグアイコンを選択します。

  • [Configure the federation server on this server]を選択します。

  • [Create the first federation server in a federation server farm]を選択します。

  • 次を選択

  • [SSL証明書]ドロップダウンメニューで、IISのセットアップ中に作成した自己署名証明書を選択します。(フェデレーションサービス名は自動入力されます。)

  • フェデレーションサービスの表示名に、 ADFSRedshiftDemoと入力します。

  • [次へ]を選択します。

  • サービスアカウントのユーザー名[ADFSSVC]を入力して[Check Name]で確認し、[OK]を選択します。

  • サービスアカウントのユーザー名[ADFSSVC]のパスワードを入力してつ[次へ]を選択します。

  • 次へをさらに2回選択します。

  • 前提条件チェックを確認して実行し、[Configure]を選択します。

インストールの進行状況を確認し、ADFSのインストールを開始します。

警告メッセージが表示される場合がありますが、このウォークスルーでは無視してかまいません。また、Windows2016EC2インスタンスを再起動する必要があります。

  • RDPでWindows2016EC2インスタンスに戻り、ADFSからフェデレーションメタデータをダウンロードします。ブラウザはGoogleChromeを使用しますので、未インストールの場合はここで入れておきましょう。
$LocalTempDir = $env:TEMP; $ChromeInstaller = "ChromeInstaller.exe"; (new-object System.Net.WebClient).DownloadFile('http://dl.google.com/chrome/install/375.126/chrome_installer.exe', "$LocalTempDir\$ChromeInstaller"); & "$LocalTempDir\$ChromeInstaller" /silent /install; $Process2Monitor =  "ChromeInstaller"; Do { $ProcessesFound = Get-Process | ?{$Process2Monitor -contains $_.Name} | Select-Object -ExpandProperty Name; If ($ProcessesFound) { "Still running: $($ProcessesFound -join ', ')" | Write-Host; Start-Sleep -Seconds 2 } else { rm "$LocalTempDir\$ChromeInstaller" -ErrorAction SilentlyContinue -Verbose } } Until (!$ProcessesFound)
  • ホスト名を取得するために、Windowsの[管理ツール]で[ ADFSManager ]を選択します。

  • [Edit Federation Service Properties]を選択します。

  • フェデレーションサービス名をコピーします(例:YourInstanceHostname.adfsredshift.com) 。

  • GoogleChromeを起動して、コピーしたホスト名を使用して次のURLを入力します。

https://<<YourInstanceHostname.adfsredshift.com>>/FederationMetadata/2007-06/FederationMetadata.xml

※エラーメッセージが表示された場合は、詳細アイコンを選択し、[続行... ]を選択してファイルをダウンロードします。

  • ダウンロードしたFederationMetadata.xmlファイルをコピーし、自身の作業端末側に保存します。(後の工程で使用します)

ADFSを使用した証明書利用者としてのAWSの設定

ここからは、作業端末でAWSコンソールにログインして作業を行います。

SAMLプロバイダーの作成

  • IAMコンソールで、[ IDプロバイダー]を選択します。

  • [プロバイダーを追加]を選択します。

  • プロバイダータイプとして[SAML]を選択します。

  • プロバイダー名には[ADFZ]と入力します。

  • [ファイルの選択]で、前にダウンロードしたFederationMetadata.xmlを選択します。

  • [プロバイダーを追加]を選択します。すると以下のようにプロバイダーが作成されます。(この名前は後の工程で作成するADFSのクレームルールで使用します)

SAMLフェデレーションIAMロールの作成

  • IAMコンソールで、[ロール]を選択し、ロールの作成を選択します。

  • SAML2.0フェデレーションを選択します。

  • SAMLプロバイダーは、ADFZと入力します。

  • [属性]で、[SAML:aud]を選択します。

  • [値]に[https://signin.aws.amazon.com/saml]と入力、[次へ]を選択します。

  • ロールに必要なポリシーを選択します。

    • ここでは仮で「RedshiftFullAccess」を選択します。(実際にアタッチするポリシーはこの後の手順で作成します)
  • [次へ]を2回選択します。

  • ロール名として、 ADFZ-Productionと入力します。

  • ロールが作成されたら、AWS CLIで以下のコマンドから"RoleId"の値を取得します。

aws iam get-role --role-name ADFZ-Production
{
    "Role": {
        "Path": "/",
        "RoleName": "ADFZ-Production",
        "RoleId": "AROAXXXXXXXXXXXXXXXX",
        "Arn": "arn:aws:iam::123456789012:role/ADFZ-Production",
以下略
  • AWSコンソールに戻り、IAMで[ポリシー]を選択し、[ポリシーの作成]を選択します。

  • [ JSON ]タブで、次のポリシーを入力してポリシーを作成します。(RoleId、RedshiftのDB名などのパラメータは適宜変更して使用してください)

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "redshift:ListSchemas",
                "redshift:DescribeQuery",
                "redshift:ListDatabases",
                "redshift:DescribeClusters",
                "redshift:ExecuteQuery",
                "redshift:FetchResults",
                "redshift:DescribeTable",
                "redshift:CreateClusterUser",
                "redshift:ListTables",
                "redshift:CancelQuery",
                "tag:GetResources"
            ],
            "Resource": "*"
        },
        {
            "Effect": "Allow",
            "Action": "redshift:JoinGroup",
            "Resource": "*"
        },
        {
            "Effect": "Allow",
            "Action": "redshift:GetClusterCredentials",
            "Resource": [
                "arn:aws:redshift:ap-northeast-1:123456789012:dbname:redshift-cluster-1/dev",
                "arn:aws:redshift:ap-northeast-1:123456789012:dbuser:redshift-cluster-1/${redshift:DbUser}"
            ],
            "Condition": {
                "StringEquals": {
                    "aws:userid": "AROAXXXXXXXXXXXXXXXX:${redshift:DbUser}@adfsredshift.com"
                }
            }
        }
    ]
}

上記の内容は、IdP のユーザー名(session name) が "@adfsredshift.com" である際のみに redshift:GetClusterCredentials API を実行できるように制限しています。

つまり、ADサーバーのユーザー名とRedshiftで作成されているユーザー名が一致しないとRedshiftにログインできないことになります。

  • IAMロール[ADFZ-Production]の画面に戻り、[ポリシーの添付]から上記で作成したポリシーをアタッチし、「RedshiftFullAccess」をデタッチします。

AWSを証明書利用者として設定する

ここからRDPでWindows2016EC2インスタンスにログインして作業します。

  • [管理ツール]から[AD FS Management]で、Actionsから[Add Relying Party Trust]を選択します。

  • [Claims aware]を選択し、Startを選択します。

  • 次のページの[Federation metadata address]欄に[https://signin.aws.amazon.com/static/saml-metadata.xml]と入力して[次へ]を選択します。

  • 表示名を入力し[次へ]を選択します。(例:Amazon Web Services)

  • [アクセス制御ポリシー]で、 [全員に許可]を選択します。

  • [完了]ページが表示されるまで、デフォルトの選択肢で[次へ]を選択します。

  • [閉じる]を選択します。

クレームルールの構成

前の手順が完了後、クレームルールを定義するウィンドウにリダイレクトされます。これが発生しない場合、[AD FS Management]で[ Relying Party Trusts]を選択して、アクション[Edit ClaimIssuesPolicy]を選択します。

今回は[NameID],[RoleSessionName],[Get AD Groups],[Roles]の4つのルールを作成します。

クレームルール[NameID]作成

  1. [ルールタイプの選択]を選択します。
  2. クレームルールテンプレートで、[受信クレームの変換]を選択します。
  3. [次へ]を選択します。
  4. [クレームルール名]に、NameIdと入力します。
  5. [受信クレームの種類]で、[Windowsアカウント名]を選択します。
  6. [送信クレームの種類]に、Name IDと入力します。
  7. 送信名ID形式には、永続識別子を選択します。
  8. [すべてのクレーム値を通過]を選択します。
  9. [完了]を選択します。

クレームルール[RoleSessionName]作成

  1. [ルールタイプの選択]を選択します。
  2. [クレームルールテンプレート]で、[LDAP属性をクレームとして送信]を選択します。
  3. [クレームルール名]に、RoleSessionNameと入力します。
  4. [属性ストア]で、[ActiveDirectory]を選択します。
  5. LDAPには、[属性電子メールアドレス]を選択します。
  6. [送信クレームの種類]に、https://aws.amazon.com/SAML/Attributes/RoleSessionNameと入力します。
  7. [完了]を選択します。

クレームルール[Get AD Groups]作成

  1. [ルールタイプの選択]を選択します。
  2. [クレームルールテンプレート]で、[カスタムルールを使用してクレームを送信]を選択します。
  3. [次へ]を選択します。
  4. [クレームルール名]に、Get AD Groupsと入力します。
  5. 次のカスタムルールを追加して[完了]を選択します。
c:[Type == "http://schemas.microsoft.com/ws/2008/06/identity/claims/windowsaccountname", Issuer == "AD AUTHORITY"] => add(store = "Active Directory", types = ("http://temp/variable"), query = ";tokenGroups;{0}", param = c.Value);

クレームルール[Roles]作成

  1. [ルールタイプの選択]を選択します。
  2. [クレームルールテンプレート]で、[カスタムルールを使用してクレームを送信]を選択します。
  3. [次へ]を選択します。
  4. [クレームルール名]に、Rolesと入力します。
  5. 次のカスタムルールを追加して[完了]を選択します。
c:[Type == "http://temp/variable", Value =~ "(?i)^AWS-"] => issue(Type = "https://aws.amazon.com/SAML/Attributes/Role", Value = RegExReplace(c.Value, "AWS-", "arn:aws:iam::<AWSAccountID>:saml-provider/ADFZ,arn:aws:iam::<AWSAccountID>:role/ADFZ-"));

※上記、はご自身のアカウントIDに置き換えてください。

  • 4つのルールが正しいことを確認し、[OK]を選択

以上でADFSの設定は完了です。

DBeaverを使ってADFS認証経由でRedshiftに接続してみた

実際に「DBeaver」というツールを使ってRedshiftにADFS認証経由で接続できるか確認します。

RedshiftのJDBCドライバーは事前にダウンロードして適用してください。

  • DBeaverを起動し[ドライバーマネージャー]を選択します。

  • Redshiftを検索して選択し、[コピー]を選択します。

  • [URLテンプレート]に jdbc:redshift:iam://{host}/{database} と入力して[OK]を選択します。

  • メニュー[データベース]から新しい接続を選択し、接続タイプで先ほど作成した[Redshift Copy]を選択します。

  • 次の画面でドライバーダウンロードの画面が出るかもしれませんが、ここでは一応ダウンロードして次へ進みます。

  • 接続設定の画面の一般タブで必要なパラメータを入力します。
    • Host - Redshiftクラスター名:リージョン の形で指定
    • Database - 接続するデータベース名
    • ユーザー名 - ADサーバードメイン名(バックスラッシュ)ADサーバーユーザー名 の形で指定
    • パスワード - ADサーバーユーザー名のパスワードを指定

  • 次にドライバのプロパティタブに移り必要なパラメータを追加します。
    • DbUser - Redshiftで作成したユーザー名(suto)を入力
    • plugin_name - com.amazon.redshift.plugin.AdfsCredentialsProvider
  • さらにユーザーのプロパティを追加していきます。左下の+マークをクリックすると項目名と値を独自に作成できるので、以下を追加します。
    • idp_port - 443
    • idp_host - YourInstanceHostname.adfsredshift.com を入力
    • priority_role - SAMLフェデレーションIAMロールのArnを入力
    • ssl_insecure - true

  • 次にSSLタブに移り、[SSLを使用する]にチェックを入れます。

  • ここまで設定が完了したら[テスト接続]を選択してみます。

上記の画面が出たら接続成功で、RedshiftにADFS認証経由でログインできたことになります。

ちなみにRedshiftに別のユーザー名(cm_suto)を作成して、DBeaverでそれを指定してRedshiftへログインを試してみると、

上記のようにADサーバーのユーザー名(suto)と、Redshiftユーザー名(cm_suto)が完全に一致していないため、接続エラーとなります。

まとめ

今回は、ADFS認証+ADサーバー側のユーザー名とRedshift側ユーザー名が同一の時のみRedshiftへ接続できる構成を検証しました。

こうすることで、Redshift利用者が増えてRedshift内ユーザーの管理が大変だからADサーバーと連携したい時に1つの有効な設計パターンになるかと思います。

参考