YARNアプリケーションを作成する人は誰でも、短期間のアプリケーションまたは長期稼働サービスを作成するために、プロセスを理解する必要があります。また、実際に動作するコードを作成するために、開発の初期段階でセキュアクラスタでのテストを開始する必要があります。
YARNリソースマネージャー(RM)とノードマネージャー(NM)は、ユーザーのアプリケーションを、そのユーザーのID、したがってアクセス権限を使用して実行するために連携します。
(アクティブな)リソースマネージャー
アプリケーションのコアであるアプリケーションマスター(AM)をデプロイするためのクラスタ内のスペースを見つけます。
そのノードのNMに、コンテナを割り当て、その中でAMを開始するように要求します。
AMと通信し、AMが新しいコンテナを要求し、現在のコンテナを操作/解放できるようにし、割り当てられた実行中のコンテナに関する通知を提供できるようにします。
ノードマネージャー
リソースをローカライズします:HDFSまたは他のファイルシステムからローカルディレクトリにダウンロードします。これは、コンテナ起動コンテキストに添付された委任トークンを使用して行われます。(非HDFSリソースの場合は、クラスタ構成ファイルでオブジェクトストアのログイン詳細などの他の認証情報を使用します)
アプリケーションをユーザーとして起動します。
アプリケーションを監視し、RMに障害を報告します。
クラスタでコードを実行するには、YARNアプリケーションは次のことを行う必要があります。
起動する内容を詳しく説明するApplicationSubmissionContext
を設定するクライアント側アプリケーションを用意します。これには以下が含まれます。
起動時にYARN RMに登録し、イベントをリッスンするアプリケーションマスターを用意します。他のコンテナで作業を実行しようとするAMは、RMからそれらを要求する必要があり、割り当てられたら、実行するコマンド、コマンドを実行する環境、ローカライズするバイナリ、およびすべての関連するセキュリティ認証情報を含むContainerLaunchContext
を作成する必要があります。
NMがローカライズプロセスを処理する場合でも、AM自体は、起動時に提供されたセキュリティ認証情報を取得できるようにする必要があります。これにより、AM自体がHDFSおよび他のサービスと連携し、これらの認証情報の一部またはすべてを起動されたコンテナに渡すことができます。
YARNアプリケーションに必要な委任トークンは、認証されたユーザーとして実行されているプログラムから取得する必要があります。 YARNアプリケーションの場合、これはアプリケーションを起動するユーザーを意味します。これを行う必要があるのは、YARNアプリケーションのクライアント側部分です。
UserGroupInformation
を介してログインします。ApplicationSubmissionContext
内のContainerLaunchContext
に追加します。どのトークンが必要ですか?通常、少なくともHDFSにアクセスするためのトークンが必要です。
アプリケーションは、対話する予定のすべてのファイルシステム(クラスタのメインFSを含む)から委任トークンを要求する必要があります。 FileSystem.addDelegationTokens(renewer, credentials)
を使用してこれらを収集できます。これは、トークンを発行しないファイルシステム(Kerberos化されていないHDFSクラスタを含む)ではnoopです。
Apache HBaseやApache Hiveなどの他のサービスと通信するアプリケーションは、これらのサービスのライブラリを使用して委任トークンを取得し、これらのサービスからトークンを要求する必要があります。すべてのトークンを同じ認証情報のセットに追加してから、送信用にバイトバッファーに保存できます。
アプリケーションタイムラインサーバーも委任トークンが必要です。これは、AM起動時に自動的に処理されます。
アプリケーションマスターが起動され、ユーザーログインをトリガーするUGI/Hadoop操作のいずれかが呼び出されると、UGIクラスは、環境変数HADOOP_TOKEN_FILE_LOCATION
で名前が付けられたファイルに保存されているすべてのトークンを自動的にロードします。
これは、セキュアクラスタとともに非セキュアクラスタで、およびアプリケーションでkeytabが使用されている場合でもセキュアクラスタで発生します。なぜですか? YARN RMでアプリケーションを認証するために必要なAM/RMトークンは、常にこの方法で提供されるためです。
これは、セキュアクラスタと非セキュアクラスタで比較的同様のワークフローがあることを意味します。
AMの起動中に、Kerberosにログインします。 UserGroupInformation.isSecurityEnabled()
の呼び出しは、この操作をトリガーします。
UserGroupInformation.getCurrentUser().getCredentials()
の呼び出しを通じて、現在のユーザーの認証情報を列挙します。
AMRMトークンをフィルタリングして、新しい認証情報のセットを作成します。非セキュアクラスタでは、認証情報のリストは空になります。セキュアクラスタでは、それらに含まれます
起動するすべてのコンテナの認証情報を、この(空の場合もある)認証情報のリストに設定します。
更新するトークンのフィルタリングされたリストが空でない場合は、それらを更新するスレッドを起動します。
トークンは期限切れになります。つまり、有効期間が限られています。この有効期限を過ぎてトークンを使用したいアプリケーションは、トークンの有効期限が切れる前にトークンを更新する必要があります。
Hadoopは、必要な場合に委任トークン更新スレッドであるDelegationTokenRenewer
を自動的に設定します。
AMRMトークンとタイムライントークン以外のすべてのトークンを更新するのは、アプリケーションの責任です。
異なる戦略は次のとおりです
トークンの更新が必要ないほどアプリケーションの有効期間が短いことに依存しないでください。有効期間が常に数分または数十分で測定できるアプリケーションの場合、これは実行可能な戦略です。
トークンを定期的に更新するために、バックグラウンドスレッド/Executorを起動します。これは、ほとんどのYARNアプリケーションが行うことです。
AM/RMトークンは自動的に更新されます。RMは、allocate
メッセージ内で新しいトークンをAMに送信します。プロセスを確認するには、AMRMClientImpl
クラスを参照してください。AMコードはこのプロセスを気にする必要はありません
アプリケーションがトークンを定期的に更新している場合でも、AMが失敗して再起動した場合、元のApplicationSubmissionContext
から再起動されます。そこにあるトークンは期限切れになっている可能性があるため、他のサービスと通信するための認証情報を発行する前でさえ、ローカライズが失敗する可能性があります。
この問題はどのように解決されますか? YARNリソースマネージャーは、必要な場合、ノードマネージャーの新しいトークンを取得します。
より正確には
これは主に、長期稼働サービス(下記を参照)の問題です。
非管理型アプリケーションマスターは、RMおよびNMによって設定されたコンテナで起動されないため、起動時にAM/RMトークンを自動的に取得できません。 YarnClient.getAMRMToken()
APIを使用すると、非管理型AMはAM/RMトークンを要求できます。詳細については、UnmanagedAMLauncher
を参照してください。
HADOOP_USER_NAME
セキュアでないクラスタでは、アプリケーションはノードマネージャーのアカウント(yarn
やmapred
など)のIDとして実行されます。デフォルトでは、アプリケーションはHDFSにそのユーザーとしてアクセスし、異なるホームディレクトリを持ち、監査ログやファイルシステムの所有者属性では異なるユーザーとして識別されます。
これは、クライアントがアプリケーションが実行されるべきHDFS/HadoopユーザーのIDを識別することで回避できます。これはOSレベルのユーザーや、ローカルマシンに対するアプリケーションのアクセス権には影響しません。
Kerberosが無効になっている場合、Hadoopは最初に環境変数HADOOP_USER_NAME
から、次にOSレベルのユーザー名(例えば、システムプロパティuser.name
)からユーザーのIDを取得します。
YARNアプリケーションは、この環境変数を設定することにより、アプリケーションを起動したユーザーのユーザー名を伝播する必要があります。
Map<String, String> env = new HashMap<>(); String userName = UserGroupInformation.getCurrentUser().getUserName(); env.put(UserGroupInformation.HADOOP_USER_NAME, userName); containerLaunchContext.setEnvironment(env);
この環境変数は、hadoopライブラリを介してHDFSと通信するすべてのアプリケーションで取得されることに注意してください。つまり、設定されている場合、この環境変数が設定されているYARNコンテナの環境内で実行されるHBaseやその他のアプリケーションによって取得されるIDになります。
HADOOP_TOKEN_FILE_LOCATION
Apache Oozieは、関連するすべてのクレデンシャルを取得し、ローカルファイルシステムのファイルに保存してから、このファイルへのパスを環境変数HADOOP_TOKEN_FILE_LOCATION
に設定することにより、セキュアなクラスタでアプリケーションを起動できます。これはもちろん、YARNが起動されたコンテナに渡す環境変数と同じであり、同様の内容(クレデンシャルを含むバイト配列)が含まれます。
ただし、ここでは、環境変数はYARNクライアントを実行する環境に設定されます。このクライアントは、独自のトークンを取得する代わりに、指定されたファイルに保存されたトークン情報を使用する必要があります。
トークンファイルの読み込みは自動的に行われます。UGIがユーザーログイン時に行います。
クライアントは、同じクレデンシャルをAM起動コンテキストに渡す責任があります。これは、現在のクレデンシャルを渡すだけで簡単に行うことができます。
credentials = new Credentials( UserGroupInformation.getCurrentUser().getCredentials());
アプリケーションタイムラインサーバーは、セキュアなサービスとしてデプロイできます。その場合、アプリケーションは認証のために関連するトークンが必要になります。このプロセスは、セキュアなクラスタでATSが有効になっている場合、YarnClientImpl
で自動的に処理されます。同様に、AM側のTimelineClient
YARNサービスクラスは、ATSのSPNEGO認証されたREST APIを介してトークン更新を自動的に管理します。
Oozie経由でYARNアプリケーションを起動するために委任トークンのセットを準備する必要がある場合は、タイムラインクライアントAPIを介して行うことができます。
try(TimelineClient timelineClient = TimelineClient.createTimelineClient()) { timelineClient.init(conf); timelineClient.start(); Token<TimelineDelegationTokenIdentifier> token = timelineClient.getDelegationToken(rmprincipal)); credentials.addToken(token.getService(), token); }
アプリケーションは、AMを終了するときに保持しているトークンをキャンセルする場合があります。これにより、トークンが無効になります。
これは必須ではなく、YARNアプリケーションの正常なシャットダウンは保証できないため、アプリケーションの終了時にトークンが常にキャンセルされることを保証することはできません。ただし、盗まれたトークンに対する脆弱性の期間を短縮します。
すべてのトークン更新には時間制限があり、それを過ぎるとトークンは更新されなくなり、アプリケーションが動作を停止します。これは72時間から7日の間です。
長期間実行することを目的としたYARNサービスは、必ずクレデンシャルを更新するための戦略を持っている必要があります。
以下に戦略を示します。
Keytabは、すべてのノードでのアプリケーションの使用のために提供されます。
これは、次の方法で行います。
UserGroupInformation.loginUserFromKeytab()
を使用してクレデンシャルをロードするアプリケーション。Keytabは、サービス(およびその他の信頼できるアカウント)のみが読み取ることができる安全なディレクトリパスにある必要があります。配布は、クラスタ運用チームの責任になります。
これは、事実上、すべての静的なHadoopアプリケーションがセキュリティクレデンシャルを取得する方法です。
KeytabはHDFSにアップロードされます。
AMを起動するとき、KeytabはAMのコンテナにローカライズするリソースとしてリストされます。
Application Masterは、Keytabへの相対パスで構成され、UserGroupInformation.loginUserFromKeytab()
でログインします。
AMがコンテナを起動するとき、KeytabへのHDFSパスをローカライズするリソースとしてリストします。
コンテナをローカライズできるように、HDFS委任トークンをコンテナ起動コンテキストに追加します。
起動されたコンテナは、UserGroupInformation.loginUserFromKeytab()
を介して自身でログインする必要があります。UGIがログインを処理し、バックグラウンドスレッドをスケジュールして、ユーザーを定期的に再ログインさせます。
トークンの作成は、Hadoop IPCおよびREST APIで自動的に処理され、コンテナはKerberosを介してその期間中ずっとログインしたままになります。
これにより、クラスタ全体で特定のサービスのKeytabをインストールする管理タスクを回避できます。
クライアントはKeytabにアクセスする必要があり、分散ファイルシステムにアップロードされるため、適切なパスパーミッション/ACLを介して保護する必要があります。
すべてのコンテナがKeytabにアクセスできるため、コンテナで実行されるすべてのコードは信頼できる必要があります。悪意のあるコード(または何らかの形式のサンドボックスを回避するコード)はKeytabを読み取ることができ、キーが期限切れになるか取り消されるまで、クラスタにアクセスできます。
これは、Apache Slider(incubating)によって実装されている戦略です。
KeytabはクライアントによってHDFSにアップロードされます。
AMを起動するとき、KeytabはAMのコンテナにローカライズするリソースとしてリストされます。
Application Masterは、Keytabへの相対パスで構成され、UserGroupInformation.loginUserFromKeytab()
でログインします。UGIコードパスは、$HADOOP_TOKEN_FILE_LOCATION
で参照されるファイルも自動的にロードします。これがAMRMトークンが取得される方法です。
AMがコンテナを起動すると、そのコンテナに必要なすべての委任トークンを取得し、コンテナのコンテナ起動コンテキストに追加します。
起動されたコンテナは、$HADOOP_TOKEN_FILE_LOCATION
から委任トークンをロードし、更新を含めて、更新できなくなるまでそれらを使用する必要があります。
AMは、コンテナが新しい委任トークンのセットを要求できるようにするIPCインターフェースを実装する必要があります。このインターフェース自体は、認証と、できれば有線暗号化を使用する必要があります。
委任トークンが期限切れになる前に、コンテナで実行されているプロセスは、IPCチャネルを介してApplication Masterから新しいトークンを要求する必要があります。
コンテナが新しいトークンを必要とするとき、KeytabでログインしたAMは、さまざまなクラスタサービスに新しいトークンを要求します。
(更新操作には別の方向があることに注意してください。AMからコンテナへ、再びAMとコンテナの間で実装されているIPCチャネルを介してです)。アルゴリズムの残りの部分:AMで再生成されたトークンがIPCを介してコンテナに渡されます。
これは、Apache Spark 1.5以降で使用されている戦略で、トークン更新のためにコンテナとAMの間にnettyベースのプロトコルを使用しています。
AMのみがKeytabに直接アクセスできるため、露出が少なくなります。コンテナで実行されているコードは、委任トークンにのみアクセスできます。
ただし、これらのコンテナはコンテナ起動時に渡されたトークンからHDFSにアクセスできるようになり、AMの起動に使用されるKeytabのコピーにアクセスできるようになります。AMは起動時にそのKeytabを削除できますが、そうすると、YARNが障害後にAMを正常に再起動できなくなります。
この戦略は、厳格な運用チームに受け入れられる唯一の戦略となる可能性があります。Kerberos TGTを保持するアカウントで実行されているクライアントプロセスは、必要なすべてのクラスタサービスと新しい委任トークンについてネゴシエートし、その後、何らかのRPCインターフェースを介してApplication Masterにプッシュされます。
これには、クライアントプロセスを定期的に再実行する必要があります。cronまたはOozieジョブでこれを行うことができます。AMは、更新されたトークンを提供できるIPC APIを実装する必要があります。(Oozieがトークン自体を収集できるため、実行されるたびにアップデーターアプリケーションが行う必要があるのは、AMとのIPC接続を設定し、現在のユーザーのクレデンシャルを渡すことだけであることに注意してください)。
YARNは、すべてのYARNアプリケーションにSPNEGO認証されたWebページを提供する簡単な方法を提供します。RMはリソースマネージャープロキシでSPNEGO認証を実装し、YarnアプリケーションのWeb UIへのアクセスをRMプロキシのみに制限します。これを行うには、2つの方法があります。
YARNアプリケーションのWebサーバーは、Web UIを設定するときにAMプロキシフィルター(AmFilterInitializer
クラスを参照)をロードする必要があります。このフィルターは、RMプロキシホスト以外のホストからのすべてのHTTPリクエストをRMプロキシにリダイレクトします。クライアントアプリ/ブラウザは、リクエストを再発行する必要があります。クライアントはRMプロキシのプリンシパル(通常はyarn
)に対して認証を行い、認証されると、リクエストが転送されます。
このオプションの既知の弱点は次のとおりです。
AMプロキシフィルターはRMプロキシのIP/ホストのみをチェックするため、これらのホストで実行されているアプリケーションは、YARNアプリケーションのWeb UIへの無制限のアクセス権を持ちます。これが、セキュアなクラスタでプロキシホストがエンドユーザーコードを実行しないクラスタノードで必ず実行される必要がある理由です(つまり、YARN NodeManagerを実行せず、YARNコンテナをスケジュールしない。また、エンドユーザーによるログインをサポートしません)。
RMプロキシとYarnアプリケーション間のHTTPリクエストは現在暗号化されていません。つまり、HTTPSはサポートされていません。
デフォルトでは、YARNアプリケーションのWeb UIは暗号化されていません(つまり、HTTPS)。HTTPSのサポートを提供するかどうかはアプリケーション次第です。これは、RMまたはJVMが信頼するように構成されているパブリックCAまたはソースからの有効なHTTPS証明書を使用して完全に独立して行うことも、代替として、RMが制限付きCAとして機能し、アプリケーションが使用できる証明書をアプリケーションに提供することもできます。これはRMプロキシでのみ受け入れられ、他のクライアント(Webブラウザなど)では受け入れられません。これは、アプリケーションが発行された証明書を盗んだり、その他の悪意のある動作を実行したりしないとは限らないため重要です。RMが発行する証明書は、(a)期限切れになり、(b)一般的なCN=<hostname|domain>
の代わりにCN=<application-id>
を含むサブジェクトを持ち、(c)RMによって生成された自己署名CA証明書によって発行されます。
アプリケーションがこの機能を利用するには、提供されたキーストアを任意のWebサーバーにロードするだけです。キーストアの場所はKEYSTORE_FILE_LOCATION
環境変数にあり、そのパスワードはKEYSTORE_PASSWORD
環境変数にあります。これは、yarn.resourcemanager.application-https.policy
がNONE
に設定されていない限り(下の表を参照)、HTTPSトラッキングURLが提供されていれば利用可能です。
さらに、アプリケーションは、HTTPS相互認証を介してRMプロキシが実際にRMであることを検証できます。提供されたキーストアに加えて、RMプロキシのクライアント証明書を含むトラストストアも提供されています。このトラストストアをロードし、選択したWebサーバーでneedsClientAuth
(または同等のもの)を有効にすることで、AMのWebサーバーはクライアント(つまり、RMプロキシ)が信頼された証明書を提供することを自動的に要求し、そうしない場合は接続を失敗させる必要があります。これにより、クライアントが認証したRMプロキシのみがアクセスできるようになります。
yarn.resourcemanager.application-https.policy |
動作 |
---|---|
NONE |
RMは特別なことは何も行いません。 |
LENIENT |
RMは、AMがその追跡URL WebサーバーでHTTPSを使用するために自由に使えるキーストアとトラストストアを生成して提供します。RMプロキシは、HTTPSを使用しないことを選択したAMへのHTTP接続を許可します。 |
STRICT |
これはLENIENTと同じですが、RMプロキシはAMへのHTTPS接続のみを許可します。HTTP接続はブロックされ、ユーザーに警告ページが表示されます。 |
デフォルト値はOFF
です。
YARNアプリケーションの登録済みWeb UIと同じポートで実行されているYARN REST APIは、RMプロキシでSPNEGO認証によって自動的に認証されます。
別のポートで起動されたRESTエンドポイント(および同様に、任意のWeb UI)は、YARNアプリケーション自体で実装されていない限り、SPNEGO認証をサポートしません。
YARNクラスターでYARNアプリケーションを正常に起動するために、YARNアプリケーションが実行する必要があるコアアクションのチェックリストを以下に示します。
[ ]
クライアントは、UserGroupInformation.isSecurityEnabled()
を介してセキュリティが有効になっているかを確認します。
セキュアクラスターの場合
[ ]
HADOOP_TOKEN_FILE_LOCATION
が設定されていない場合、クライアントはローカルファイルシステムの委任トークンを取得し、RMプリンシパルを更新者として設定します。
[ ]
HADOOP_TOKEN_FILE_LOCATION
が設定されていない場合、クライアントはYARNアプリケーションで使用される他のすべてのサービスの委任トークンを取得します。
[ ]
HADOOP_TOKEN_FILE_LOCATION
が設定されている場合、クライアントは、コンテナ起動コンテキストに追加するすべてのトークンのソースとして現在のユーザーの資格情報を使用します。
[ ]
クライアントは、すべてのトークンをAMのContainerLaunchContext.setTokens()
に設定します。
[ ]
推奨:クライアントの環境で設定されている場合は、クライアントはAMのコンテナ起動コンテキストで環境変数HADOOP_JAAS_DEBUG=true
を設定します。
非セキュアクラスターの場合
[ ]
環境変数HADOOP_USER_NAME
を介して、ローカルユーザー名をYARN AMに伝播し、それによってHDFS IDを伝播します。
[ ]
セキュアクラスターでは、AMはHADOOP_TOKEN_FILE_LOCATION
環境変数からセキュリティトークンを取得します(UGIによって自動的に行われます)。
[ ]
トークンセットのコピーは、AM/RMトークンとタイムライントークンを削除するようにフィルタリングされます。
[ ]
スレッドを定期的に更新するために、スレッドまたはエグゼキューターが起動されます。
[ ]
推奨:アプリケーションが完了したら、AMはトークンをキャンセルします。
[ ]
コンテナに渡されるトークンは、ContainerLaunchContext.setTokens()
を介して渡されます。
[ ]
非セキュアクラスターでは、環境変数HADOOP_USER_NAME
を伝播します。
[ ]
推奨:AMの環境で設定されている場合、AMはコンテナ起動コンテキストで環境変数HADOOP_JAAS_DEBUG=true
を設定します。
[ ]
セキュリティ設定をトリガーするには、UserGroupInformation.isSecurityEnabled()
を呼び出します。
[ ]
スレッドを定期的に更新するために、スレッドまたはエグゼキューターが起動されます。
[ ]
アプリケーション開発者は、トークン更新戦略(共有キータブ、AMキータブ、またはクライアント側のトークン更新)を選択して実装しました。
[ ]
セキュアクラスターでは、キータブはすでにHDFSにある(そしてチェックされる)か、クライアントのローカルFSにあります。その場合、ローカライズするリソースのリストにアップロードして追加する必要があります。
[ ]
HDFSに保存されている場合、キータブの権限をチェックする必要があります。キータブが現在のユーザー以外のプリンシパルによって読み取り可能な場合は、警告し、実際に起動に失敗することを検討してください(通常のssh
アプリケーションと同様)。
[ ]
クライアントはHDFS委任トークンを取得し、AMコンテナ起動コンテキストに添付します。
[ ]
AMはloginUserFromKeytab()
を介してキータブのプリンシパルとしてログインします。
[ ]
(AMはHADOOP_TOKEN_FILE_LOCATION
環境変数からAM/RMトークンを抽出します)。
[ ]
起動されたコンテナの場合、キータブが伝播されるか、AMは、NMに必要なHDFS委任トークンと一緒に、必要なすべての委任トークンを取得/添付します。
YARNアプリケーションがセキュアクラスターで動作すると確信するのは簡単です。そうするためのプロセスは、セキュアクラスターでテストすることです。
単一のVMクラスターでさえ、セキュリティを有効にしてセットアップできます。その場合は、SPNEGO認証されたWeb UI(したがってRMプロキシ)とIPCワイヤ暗号化を使用して、セキュリティを最も厳格にすることをお勧めします。Kerberosトークンの有効期限を1時間未満に設定すると、Kerberosの有効期限の問題を早期に見つけることができるため、推奨されます。
[ ]
セキュアクラスターで起動されたアプリケーション。
[ ]
起動されたアプリケーションは、ジョブを送信するユーザーとして実行されます(ヒント:AMのuser.name
システムプロパティをログに記録します)。
[ ]
セキュアクラスターで検証されたWebブラウザのインタラクション。
[ ]
テスト済みのRESTクライアントのインタラクション(GET操作)。
[ ]
Kerberosトークンの有効期限が切れた後もアプリケーションは実行を継続します。
[ ]
ユーザーがKerberos資格情報を持っていない場合、アプリケーションは起動しません。
[ ]
アプリケーションがタイムラインサーバーをサポートしている場合は、セキュアクラスターでイベントを公開することを確認します。
[ ]
アプリケーションがHBaseやHiveなどの他のアプリケーションと統合されている場合は、セキュアクラスターでインタラクションが機能することを確認します。
[ ]
アプリケーションがリモートHDFSクラスターと通信する場合は、セキュアクラスターで通信できることを確認します(つまり、クライアントが起動時にこれに対する委任トークンを抽出したことを確認します)。
セキュアなHadoopクラスターでYARNアプリケーションをテストしないと、動作しません。
そして、これらのテストがないと:ユーザーがセキュアクラスターでアプリケーションが動作しないことを発見することになります。
Kerberosサポートにどれだけの開発労力を費やすかを検討する際に、それを念頭に置いてください。