web-dev-qa-db-ja.com

カスタムヘッダーに基づく承認(Apache)

カスタムヘッダー「username」と「role」を使用してユーザーとその役割を識別する、Apache Reverse-Proxyの背後で実行されているサービスがあります。

Apache HTTPDで、カスタムHTTPヘッダー「groupmembership」に「viewer」、「publisher」、「administrator」のいずれかが含まれているユーザーへのアクセスを制限したい。

Apacheは、ユーザーを認証し、HTTPヘッダー「username」と「groupmembership」にデータを入力する別のプロキシの背後にあります。ここで、「groupmembership」の内容は、グループをコンマで区切ったリストです。

参考までに、アーキテクチャのドラフトを含めました。 http-proxy-auth

これはどのようにして可能でしょうか? Require expr %{HTTP:iv_groupmembership} in { 'viewer', 'publisher', 'administrator' }内で<Location />のようなrequireディレクティブを使用してみましたが、役に立ちませんでした。

代わりにこれはmod_rewriteで動作しますか?

Mod_proxyとmod_rewriteを使用したリバースプロキシ設定は次のとおりです。

RewriteEngine on
<Proxy *>
  Allow from all
</Proxy>
ProxyRequests Off

# store variable values with dummy rewrite rules
RewriteRule . - [E=req_scheme:%{REQUEST_SCHEME}]
RewriteRule . - [E=http_Host:%{HTTP_Host}]
RewriteRule . - [E=req_uri:%{REQUEST_URI}]

# set header with variables
RequestHeader set X-RSC-Request "%{req_scheme}e://%{http_Host}e%{req_uri}e"

RewriteCond %{HTTP:Upgrade} =websocket
RewriteRule /(.*) ws://localhost:3939/$1 [P,L]
RewriteCond %{HTTP:Upgrade} !=websocket
RewriteRule /(.*) http://localhost:3939/$1 [P,L]
ProxyPass / http://172.17.0.1:3939/  
ProxyPassReverse / http://172.17.0.1:3939/

ヒントをありがとう。

編集:基本的に、質問は次のようになります。groupmembershipヘッダーのカンマ区切りのリストに「管理者」、「発行者」、または「閲覧者」が含まれているかどうかを確認するにはどうすればよいですか。

1
juo

これでうまくいくはずです。ヘッダーgroupmembershipにカンマ区切りのリストがある場合は、最初の正規表現を使用します。アクセスを許可するには、リスト内の1つの値が一致する必要があります。

iv_groupmembershipの正確な値と一致させる場合は、 二番目 3番目の式(および最初のコメント)。

編集:

  • RequestHeader set roleの例を追加し、必要に応じてコメントを外します。私はこれをHeader set roleでテストしただけですが(レスポンスではバックエンドはありません)、RequestHeaderでも同じように機能するはずです。

Edit2:

  • 明確にするために<Location/>を削除
  • X-Auth-Tokenチェックとgroupmembershipを組み合わせた例を追加

サンプル設定:

    # test for string in comma-separated values, one of the values must match
    <If "%{HTTP:groupmembership} !~ /(^|,)(viewer|publisher|administrator)(,|$)/">

    # combined: X-Auth-Token must be set or one of the roles must exist
#   <If "%{HTTP:X-Auth-Token} == '' && %{HTTP:groupmembership} !~ /(^|,)(viewer|publisher|administrator)(,|$)/">

    # alternative: test for a single value in "iv_groupmembership" (exact match)
#   <If "! %{HTTP:iv_groupmembership} in { 'viewer', 'publisher', 'administrator' }">

        Require all denied
    </If>

    # set role of groupmembership
#   <If "%{HTTP:groupmembership} =~ /(^|,)viewer(,|$)/">
#       RequestHeader set role viewer
#   </If>
#   <ElseIf "%{HTTP:groupmembership} =~ /(^|,)publisher(,|$)/">
#       RequestHeader set role publisher
#   </ElseIf>
#   <ElseIf "%{HTTP:groupmembership} =~ /(^|,)administrator(,|$)/">
#       RequestHeader set role administrator
#   </ElseIf>

    # set role of iv_groupmembership
#   RequestHeader set role "expr=%{HTTP:iv_groupmembership}"

Apacheのヘッダー(RequestHeader set iv_groupmembership "viewer"など)を変更して構成をデバッグ/テストすることはできません。ヘッダーを非常に早く設定する必要があります。

https://httpd.Apache.org/docs/2.4/expr.html#vars

式パーサーは、%{HTTP_Host}という形式の多数の変数を提供します。変数の値は、それが評価される要求処理のフェーズに依存する場合があることに注意してください。たとえば、<If>ディレクティブで使用される式は、認証が行われる前に評価されます。したがって、この場合、%{REMOTE_USER}は設定されません。

コマンドラインからwgetを使用して構成をテストできます。localhostをホスト名に置き換えます。

# HTTP/1.1 403 Forbidden
wget -S -O - http://localhost
wget -S -O - --header='groupmembership: xviewer' http://localhost
wget -S -O - --header='groupmembership: administratorx' http://localhost
wget -S -O - --header='iv_groupmembership: xviewer' http://localhost

# HTTP/1.1 200 OK
wget -S -O - --header='groupmembership: foo,viewer' http://localhost
wget -S -O - --header='groupmembership: publisher,foo' http://localhost
wget -S -O - --header='iv_groupmembership: viewer' http://localhost
wget -S -O - --header='iv_groupmembership: publisher' http://localhost
wget -S -O - --header='iv_groupmembership: administrator' http://localhost

Apache/2.4.25(Debian)でテスト済み

1
Freddy

@Freddyに感謝します。承認部分のRequireおよびExpressionsディレクティブを使用し、<Virtualhost>内にRequestHeaderディレクティブを配置して、ロールヘッダーを設定しました。

最終的な設定は次のようになります。

<VirtualHost *:443>
  ServerName ...
  DocumentRoot /var/www/html

  SSLEngine on
  SSLProtocol all -SSLv2 -SSLv3
  SSLCipherSuite HIGH:3DES:!aNULL:!MD5:!SEED:!IDEA

  SSLCertificateFile /etc/httpd/ssl/...
  SSLCertificateKeyFile /etc/httpd/ssl/...

  RewriteEngine on
  #ProxyPreserveHost on

  <Proxy *>
    Allow from all
  </Proxy>
  ProxyRequests Off

  # store variable values with dummy rewrite rules
  RewriteRule . - [E=req_scheme:%{REQUEST_SCHEME}]
  RewriteRule . - [E=http_Host:%{HTTP_Host}]
  RewriteRule . - [E=req_uri:%{REQUEST_URI}]

  # set header with variables
  RequestHeader set X-RSC-Request "%{req_scheme}e://%{http_Host}e%{req_uri}e"

  RewriteCond %{HTTP:Upgrade} =websocket
  RewriteRule /(.*) ws://localhost:3939/$1 [P,L]
  RewriteCond %{HTTP:Upgrade} !=websocket
  RewriteRule /(.*) http://localhost:3939/$1 [P,L]

  # test for string in comma-separated values, one of the values must match
  <If "%{HTTP:iv_groupmembership} !~ /(^|,)(Viewer|Publisher|Administrator)(,|$)/ && -z %{HTTP:X-Auth-Token} && %{HTTP:Authorization} !~ /Key .+/">
    Require all denied
  </If>

  # set role of groupmembership
  <If "%{HTTP:iv_groupmembership} =~ /(^|,)Viewer(,|$)/">
     RequestHeader set Role viewer
  </If>
  <ElseIf "%{HTTP:iv_groupmembership} =~ /(^|,)Publisher(,|$)/">
     RequestHeader set Role publisher
  </ElseIf>
  <ElseIf "%{HTTP:iv_groupmembership} =~ /(^|,)Administrator(,|$)/">
    RequestHeader set Role administrator
  </ElseIf>
</Virtualhost>

どうもありがとう!

編集:Requireディレクティブにロジックを追加して、ヘッダーX-Auth-Tokenが存在する場合でもアクセスを許可する方法を教えてください。

Edit2: Apache式ロジックへのポインタに対して@Freddyに感謝します。「X-Auth-Token」ヘッダーの存在についてテストを-z %{HTTP:X-Auth-Token}で適合させ、別の条件を追加することができました「authorization」ヘッダー内にキーを含むリクエストをパススルーします。

1
juo