あるドメインのクライアントが、異なるドメインのサービス、または同じドメインだがクライアントとは異なるポートを使用するサービスにアクセスすると、クライアントはクロスオリジンリクエストを開始します。サービスがオリジン間のリソースアクセスを許可していない場合、クライアントはそのサービスにアクセスできません。この場合、オリジン間リソース共有 (CORS) を実装することで、Web アプリケーションサーバーがオリジン間のリソースアクセスをサポートできるように設定できます。このトピックでは、Service Mesh (ASM) の仮想サービスで CORS ポリシーを設定して CORS を実装する方法について説明します。
CORS の概要
セキュリティ上の理由から、ブラウザはスクリプトから開始されるクロスオリジン HTTP リクエストを制限します。オリジン間リソースアクセスの要件を満たすために、ASM では CORS を実装できます。CORS は HTTP ヘッダーに基づくメカニズムであり、サーバーが自身のドメイン、プロトコル、またはポートとは異なるオリジンからのリソース読み込みをブラウザに許可するかどうかを識別できるようにします。
CORS メカニズムは、単純リクエストとプリフライトリクエストの 2 種類のリクエストをサポートします。
単純リクエスト
ブラウザがクロスオリジンリクエストを送信します。リクエストには `Origin` ヘッダーが指定されます。これは、リクエストがクロスオリジンリクエストであることを示します。宛先サーバーがクロスオリジンリクエストを受信した後、サーバーは設定された CORS ルールに基づいてリクエストを許可するかどうかを決定します。応答として、サーバーは `Access-Control-Allow-Origin` および `Access-Control-Allow-Methods` ヘッダーを返し、リクエストが許可されたかどうかを示します。
プリフライトリクエスト
ブラウザがプリフライトリクエストを送信します。このリクエストは HTTP の `OPTIONS` リクエストであり、宛先サーバーが現在のドメインからのクロスオリジンリクエストを許可するかどうかを確認するために使用されます。宛先サーバーが現在のドメインからのクロスオリジンリクエストを許可する場合、ブラウザは実際のクロスオリジンリクエストを送信します。
`OPTIONS` リクエストには、`Origin`、`Access-Control-Request-Method`、および `Access-Control-Request-Headers` ヘッダーが含まれます。宛先サーバーが `OPTIONS` リクエストを受信した後、サーバーは応答に `Access-Control-Allow-Origin`、`Access-Control-Allow-Method`、`Access-Control-Allow-Headers`、および `Access-Control-Max-Age` ヘッダーを指定して、リクエストが許可されるかどうかを示します。プリフライトリクエストが許可された場合、ブラウザは実際のクロスオリジンリクエストを送信します。
リクエストが以下の 3 つの要件を満たす場合、CORS メカニズムはそのリクエストを単純リクエストとして処理します。それ以外の場合、CORS メカニズムはそのリクエストをプリフライトリクエストとして処理します。
リクエストが以下のいずれかのメソッドを使用している:
GET、HEAD、POST
リクエストの `Content-Type` ヘッダーが以下のいずれかの値に設定されている:
text/plain、application/x-www-form-urlencoded、multipart/form-data
リクエストが、Fetch 標準で定義されている以下の CORS セーフリストヘッダーのいずれかを使用している:
Accept、Accept-Language、Content-Language、Content-Type。`Content-Type` ヘッダーの値は、2 番目の要件にリストされている値のいずれかに設定する必要があることにご注意ください。
仮想サービスでの CORS ポリシーの設定
ブラウザは自動的に CORS 通信を実装します。サービスに対して開始されるクロスオリジンリクエストを許可し、CORS 通信を実装するには、そのサービス用に定義された仮想サービスの corsPolicy フィールドを設定する必要があります。
パラメーター | 説明 |
allowOrigins | サービスへのアクセスが許可されているオリジンのアドレス。正規表現がサポートされています。認証情報のないリクエストの場合、サーバーはこのパラメーターをワイルドカード (*) に設定して、すべてのオリジンがサービスにアクセスできるようにすることができます。 |
allowMethods | クロスオリジンリクエストを開始するために使用できる HTTP メソッド。 |
allowHeaders | 実際のクロスオリジンリクエスト中に使用できるヘッダー。指定されたヘッダーは、プリフライトリクエストへの応答で使用される `Access-Control-Allow-Headers` ヘッダーにシリアル化されます。 |
exposeHeaders | サーバーがブラウザにアクセスを許可するヘッダー。 |
maxAge | ブラウザがプリフライトリクエストへの応答をキャッシュできる最大時間。 |
allowCredentials | クロスオリジンリクエストを認証情報付きで行えるかどうかを指定します。有効な認証情報のみがクロスオリジンリクエストの送信に使用できます。 |
CORS のベストプラクティス
前提条件
-
defaultとfooの名前空間を作成し、それらに対してサイドカープロキシの自動インジェクションを有効にしていること。詳細については、「グローバル名前空間の管理」をご参照ください。
手順 1:アプリケーションのデプロイ
バックエンドアプリケーションをデプロイします。
クラスターの kubeconfig ファイルを取得し、kubectl を使用してクラスターに接続します。詳細については、「クラスターの kubeconfig ファイルを取得し、kubectl を使用してクラスターに接続する」をご参照ください。
details.yaml という名前のファイルを作成し、次の内容をファイルに追加します。
次のコマンドを実行して、details アプリケーションを default 名前空間にデプロイします。
kubectl apply -f details.yaml -n default
フロントエンドアプリケーションをデプロイします。
istio-cors-demo.yaml という名前のファイルを作成し、次の内容をファイルに追加します。
次のコマンドを実行して、istio-cors-demo アプリケーションを foo 名前空間にデプロイします。
kubectl apply -f istio-cors-demo.yaml -n foo
手順 2:イングレスゲートウェイのデプロイ
-
ASM コンソールにログインします。左側のナビゲーションウィンドウで、 を選択します。
-
メッシュ管理 ページで、ASM インスタンスの名前をクリックします。左側のナビゲーションウィンドウで、 を選択します。
-
Ingress Gateway ページで、Create をクリックします。
-
Create ページで、Name を ingressgateway に設定し、デプロイ先の Cluster を選択し、CLB instance type を Internet Access に設定します。新規 CLB で、Classic Load Balancer (CLB) インスタンスの仕様を選択します。他のパラメーターはデフォルト値のままにし、Create をクリックします。
手順 3:ルーティングルールの作成
-
バックエンドアプリケーションのルーティングルールを作成します。
-
Istio ゲートウェイを作成し、details アプリケーションを ingressgateway ゲートウェイに関連付けます。
-
ASM コンソールにログインします。左側のナビゲーションウィンドウで、 を選択します。
-
メッシュ管理 ページで、ASM インスタンスの名前をクリックします。左側のナビゲーションウィンドウで、 を選択します。
-
Gateway ページで、Create from YAML をクリックします。
-
Create ページで、Namespaces を default に設定します。任意の Scenario Template を選択します。YAML エディターの内容を次の設定に置き換え、Create をクリックします。
apiVersion: networking.istio.io/v1beta1 kind: Gateway metadata: name: bookinfo-gateway namespace: default spec: selector: istio: ingressgateway servers: - hosts: - '*' port: name: http number: 80 protocol: HTTP
-
-
仮想サービスを作成します。
-
メッシュ詳細ページの左側のナビゲーションウィンドウで、 を選択します。表示されたページで、Create from YAML をクリックします。
-
Create ページで、Namespaces を default に設定します。任意の Scenario Template を選択します。YAML エディターの内容を次の設定に置き換え、Create をクリックします。
apiVersion: networking.istio.io/v1beta1 kind: VirtualService metadata: name: bookinfo namespace: default spec: gateways: - bookinfo-gateway hosts: - '*' http: - match: - uri: prefix: /details route: - destination: host: details port: number: 9080
-
-
バックエンドアプリケーションにアクセスします。
ingressgateway ゲートウェイの IP アドレスを取得します。詳細については、「イングレスゲートウェイの作成」をご参照ください。
-
ブラウザのアドレスバーに http://<ingressgateway ゲートウェイの IP アドレス>/details/2 と入力します。
{"id":2,"author":"William Shakespeare","year":1595,"type":"paperback","pages":200,"publisher":"PublisherA","language":"English","ISBN-10":"1234567890","ISBN-13":"123-1234567890"}上記の図のメッセージが返された場合、details バックエンドアプリケーションへのリクエストが成功したことを示します。
-
-
フロントエンドアプリケーションのルーティングルールを作成します。
-
Istio ゲートウェイを作成します。
Istio ゲートウェイを作成し、istio-cors-demo アプリケーションを ingressgateway2 ゲートウェイに関連付けます。
-
メッシュ詳細ページの左側のナビゲーションウィンドウで、 を選択します。Gateway ページで、Create from YAML をクリックします。
-
Create ページで、Namespaces を foo に設定します。任意の Scenario Template を選択します。YAML エディターの内容を次の設定に置き換え、Create をクリックします。
apiVersion: networking.istio.io/v1beta1 kind: Gateway metadata: name: istio-cors-demo-gateway namespace: foo spec: selector: istio: ingressgateway2 servers: - hosts: - '*' port: name: http number: 80 protocol: HTTP
-
-
仮想サービスを作成します。
-
左側のナビゲーションウィンドウで、 を選択します。VirtualService ページで、Create from YAML をクリックします。
-
Create ページで、Namespaces を foo に設定します。任意の Scenario Template を選択します。YAML エディターの内容を次の設定に置き換え、Create をクリックします。
apiVersion: networking.istio.io/v1beta1 kind: VirtualService metadata: name: istio-cors-demo namespace: foo spec: gateways: - istio-cors-demo-gateway hosts: - '*' http: - route: - destination: host: istio-cors-demo port: number: 8000
-
-
-
フロントエンドアプリケーションを使用してバックエンドアプリケーションにアクセスします。
ingressgateway2 ゲートウェイの IP アドレスを取得します。詳細については、「イングレスゲートウェイの作成」をご参照ください。
Google Chrome のアドレスバーに http://<ingressgateway2 ゲートウェイの IP アドレス> と入力します。
-
URL テキストボックスに http://<ingressgateway ゲートウェイの IP アドレス>/details/2 と入力し、送信 をクリックします。
-
Google Chrome の右上隅にある
アイコンをクリックし、 を選択します。Access to XMLHttpRequest at 'http://47.111.xxx/details/2' from origin 'http://116.62.xxx' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. Failed to load resource: net::ERR_FAILED Access to XMLHttpRequest at 'http://47.111.xxx/details/2' from origin 'http://116.62.xxx' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. Failed to load resource: net::ERR_FAILED Access to XMLHttpRequest at 'http://47.111.xxx/details/2' from origin 'http://116.62.xxx' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. Failed to load resource: net::ERR_FAILED DevTools failed to load source map: Could not load content for https://unpkg.com/axios/dist/axios.min.map: HTTP error: status code 404, net::ERR_HTTP_RESPONSE_CODE_FAILURE上記のエラーメッセージは、リクエストが失敗したことを示しています。これは、istio-cors-demo フロントエンドアプリケーションが details バックエンドアプリケーションにアクセスするためにクロスオリジンリクエストを送信したためです。
手順 4:CORS ポリシーの設定
-
ASM コンソールにログインします。左側のナビゲーションウィンドウで、 を選択します。
-
メッシュ管理 ページで、ASM インスタンスの名前をクリックします。左側のナビゲーションウィンドウで、 を選択します。
-
VirtualService ページで、bookinfo 仮想サービスを見つけ、Actions 列の View YAML をクリックします。
-
Edit ダイアログボックスで、http パラメーターの下に次の
corsPolicy設定を追加し、OK をクリックします。- corsPolicy: allowCredentials: false allowMethods: - POST - GET allowOrigins: - prefix: 'http://<ingressgateway2 ゲートウェイの IP アドレス>' maxAge: 24h# corsPolicy 追加後の最終的な YAML http: - match: - uri: prefix: /details route: - destination: host: details port: number: 9080 corsPolicy: allowCredentials: false allowMethods: - POST - GET allowOrigins: - prefix: 'http://<ingressgateway2 ゲートウェイの IP アドレス>' # ご利用の ingressgateway2 ゲートウェイの IP を使用してください。 maxAge: 24h
手順 5:CORS ポリシーが有効になったことの確認
Google Chrome のアドレスバーに http://<ingressgateway2 ゲートウェイの IP アドレス> と入力します。
-
URL テキストボックスに http://<ingressgateway ゲートウェイの IP アドレス>/details/2 と入力し、送信 をクリックします。
success {"id":2,"author":"William Shakespeare","year":1595,"type":"paperback","pages":200,"publisher":"PublisherA","language":"English","ISBN-10":"1234567890","ISBN-13":"123-1234567890"}上記の図のメッセージが返された場合、istio-cors-demo フロントエンドアプリケーションが details バックエンドアプリケーションに正常にアクセスしたことを示します。これは、CORS ポリシーが有効になったことを意味します。