Active Directory Federation Servicesを使用してRedshiftへ接続してみた
どーも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]作成
- [ルールタイプの選択]を選択します。
- クレームルールテンプレートで、[受信クレームの変換]を選択します。
- [次へ]を選択します。
- [クレームルール名]に、
NameId
と入力します。 - [受信クレームの種類]で、[Windowsアカウント名]を選択します。
- [送信クレームの種類]に、
Name ID
と入力します。 - 送信名ID形式には、永続識別子を選択します。
- [すべてのクレーム値を通過]を選択します。
- [完了]を選択します。
クレームルール[RoleSessionName]作成
- [ルールタイプの選択]を選択します。
- [クレームルールテンプレート]で、[LDAP属性をクレームとして送信]を選択します。
- [クレームルール名]に、
RoleSessionName
と入力します。 - [属性ストア]で、[ActiveDirectory]を選択します。
- LDAPには、[属性電子メールアドレス]を選択します。
- [送信クレームの種類]に、
https://aws.amazon.com/SAML/Attributes/RoleSessionName
と入力します。 - [完了]を選択します。
クレームルール[Get AD Groups]作成
- [ルールタイプの選択]を選択します。
- [クレームルールテンプレート]で、[カスタムルールを使用してクレームを送信]を選択します。
- [次へ]を選択します。
- [クレームルール名]に、
Get AD Groups
と入力します。 - 次のカスタムルールを追加して[完了]を選択します。
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]作成
- [ルールタイプの選択]を選択します。
- [クレームルールテンプレート]で、[カスタムルールを使用してクレームを送信]を選択します。
- [次へ]を選択します。
- [クレームルール名]に、
Roles
と入力します。 - 次のカスタムルールを追加して[完了]を選択します。
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つの有効な設計パターンになるかと思います。