外部MongoDBサービスの利用
IstioのBookinfo例に基づいたシンプルなシナリオについて説明します。
外部TCPサービスの利用のブログ記事では、TCP経由でメッシュ内のIstioアプリケーションが外部サービスを利用する方法について説明しました。この記事では、外部MongoDBサービスの利用方法を示します。 Istio Bookinfoサンプルアプリケーション(本の評価データがMongoDBデータベースに永続化されているバージョン)を使用し、このデータベースをクラスタの外部にデプロイし、 *ratings* マイクロサービスがそれを利用するように構成します。外部MongoDBサービスへのトラフィック制御の複数のオプションとその長所と短所について学習します。
外部評価データベースを使用したBookinfo
まず、本の評価データを保持するMongoDBデータベースインスタンスをKubernetesクラスタの外部にセットアップします。次に、 Istio Bookinfoサンプルアプリケーション を修正して、このデータベースを使用します。
評価データベースのセットアップ
このタスクでは、 MongoDB のインスタンスをセットアップします。任意のMongoDBインスタンスを使用できます。私は Compose for MongoDB を使用しました。
admin
ユーザーのパスワードの環境変数を設定します。パスワードがBash履歴に保存されないように、コマンドを実行した直後に history -d を使用して履歴からコマンドを削除します。$ export MONGO_ADMIN_PASSWORD=<your MongoDB admin password>
作成する新しいユーザー(
bookinfo
)のパスワードの環境変数を設定します。history -d を使用して履歴からコマンドを削除します。$ export BOOKINFO_PASSWORD=<password>
MongoDBサービスの環境変数
MONGODB_HOST
とMONGODB_PORT
を設定します。bookinfo
ユーザーの作成$ cat <<EOF | mongo --ssl --sslAllowInvalidCertificates $MONGODB_HOST:$MONGODB_PORT -u admin -p $MONGO_ADMIN_PASSWORD --authenticationDatabase admin use test db.createUser( { user: "bookinfo", pwd: "$BOOKINFO_PASSWORD", roles: [ "read"] } ); EOF
評価を保持する *コレクション* を作成します。次のコマンドは、両方の評価を
1
に設定し、データベースがBookinfo *ratings* サービスで使用されている場合に視覚的な手がかりを提供します(デフォルトのBookinfo *ratings* は4
と5
です)。$ cat <<EOF | mongo --ssl --sslAllowInvalidCertificates $MONGODB_HOST:$MONGODB_PORT -u admin -p $MONGO_ADMIN_PASSWORD --authenticationDatabase admin use test db.createCollection("ratings"); db.ratings.insert( [{rating: 1}, {rating: 1}] ); EOF
bookinfo
ユーザーが評価を取得できることを確認します$ cat <<EOF | mongo --ssl --sslAllowInvalidCertificates $MONGODB_HOST:$MONGODB_PORT -u bookinfo -p $BOOKINFO_PASSWORD --authenticationDatabase test use test db.ratings.find({}); EOF
出力は次のようになります。
MongoDB server version: 3.4.10 switched to db test { "_id" : ObjectId("5b7c29efd7596e65b6ed2572"), "rating" : 1 } { "_id" : ObjectId("5b7c29efd7596e65b6ed2573"), "rating" : 1 } bye
Bookinfoアプリケーションの初期設定
外部データベースの使用シナリオを示すために、 Istioがインストールされた Kubernetesクラスタから始めます。次に、 Istio Bookinfoサンプルアプリケーション をデプロイし、 デフォルトの宛先ルールを適用し、 Istioをブロックするデフォルトポリシーに変更します。
このアプリケーションは、ratings
マイクロサービスを使用して本の評価(1〜5の数字)を取得します。評価は、各レビューごとに星として表示されます。ratings
マイクロサービスにはいくつかのバージョンがあります。次のセクションでは、 MongoDB を評価データベースとして使用するバージョンをデプロイします。
このブログ記事の例のコマンドは、Istio 1.0で動作します。
念のため、 Bookinfoサンプルアプリケーション のアプリケーションのエンドツーエンドアーキテクチャを次に示します。
Bookinfoアプリケーションで外部データベースを使用する
MongoDBデータベース( *ratings v2* )を使用する *ratings* マイクロサービスの仕様をデプロイします
$ kubectl apply -f @samples/bookinfo/platform/kube/bookinfo-ratings-v2.yaml@ serviceaccount "bookinfo-ratings-v2" created deployment "ratings-v2" created
MONGO_DB_URL
環境変数をMongoDBの値に更新します$ kubectl set env deployment/ratings-v2 "MONGO_DB_URL=mongodb://bookinfo:$BOOKINFO_PASSWORD@$MONGODB_HOST:$MONGODB_PORT/test?authSource=test&ssl=true" deployment.extensions/ratings-v2 env updated
*reviews* サービス宛てのすべてのトラフィックをその *v3* バージョンにルーティングします。これは、 *reviews* サービスが常に *ratings* サービスを呼び出すことを保証するためです。さらに、 *ratings* サービス宛てのすべてのトラフィックを、データベースを使用する *ratings v2* にルーティングします。
2つの 仮想サービス を追加して、上記の両方のサービスのルーティングを指定します。これらの仮想サービスは、Istioリリースアーカイブの
samples/bookinfo/networking/virtual-service-ratings-mongodb.yaml
に指定されています。 *重要:*次のコマンドを実行する前に、 デフォルトの宛先ルールを適用したことを確認してください。$ kubectl apply -f @samples/bookinfo/networking/virtual-service-ratings-db.yaml@
更新されたアーキテクチャを以下に示します。メッシュ内の青い矢印は、追加した仮想サービスに従って構成されたトラフィックを示しています。仮想サービスに従って、トラフィックは *reviews v3* と *ratings v2* に送信されます。
MongoDBデータベースはIstioサービスメッシュの外、より正確にはKubernetesクラスタの外にあることに注意してください。サービスメッシュの境界は破線で示されています。
ウェブページへのアクセス
イングレスIPとポートを決定した後、アプリケーションのウェブページにアクセスします。
まだ出力トラフィック制御を構成していないため、MongoDBサービスへのアクセスはIstioによってブロックされています。そのため、評価の星のかわりに、「評価サービスは現在使用できません」というメッセージが各レビューの下に表示されます。
以降のセクションでは、Istioでの出力制御のさまざまなオプションを使用して、外部MongoDBサービスへの出力アクセスを構成します。
TCPのエグレス制御
MongoDBワイヤプロトコル はTCP上に実行されるため、MongoDBへのエグレストラフィックを他の 外部TCPサービス と同様に制御できます。TCPトラフィックを制御するには、MongoDBホストのIPアドレスを含む CIDR 表記のIPブロックを指定する必要があります。ここで注意すべきは、MongoDBホストのIPが安定していない、または事前にわからない場合があることです。
MongoDBホストのIPが安定していない場合、エグレストラフィックは TLSトラフィックとして制御するか、または 直接 ルーティングしてIstioサイドカープロキシをバイパスできます。
MongoDBデータベースインスタンスのIPアドレスを取得します。オプションとして、 host コマンドを使用できます。
$ export MONGODB_IP=$(host $MONGODB_HOST | grep " has address " | cut -d" " -f4)
ゲートウェイなしでのTCPエグレストラフィックの制御
たとえば、メッシュから出るすべてのトラフィックをゲートウェイ経由で送信する必要がない場合など、 エグレスゲートウェイ を介してトラフィックを直接送信する必要がない場合は、このセクションの手順に従ってください。または、エグレスゲートウェイ経由でトラフィックを直接送信する場合は、 エグレスゲートウェイ経由でのTCPエグレストラフィックの直接送信 に進んでください。
TCPメッシュ外部サービスエントリの定義
$ kubectl apply -f - <<EOF apiVersion: networking.istio.io/v1alpha3 kind: ServiceEntry metadata: name: mongo spec: hosts: - my-mongo.tcp.svc addresses: - $MONGODB_IP/32 ports: - number: $MONGODB_PORT name: tcp protocol: TCP location: MESH_EXTERNAL resolution: STATIC endpoints: - address: $MONGODB_IP EOF
トラフィックが MongoDBプロトコルがTLS上で実行される場合 に暗号化される可能性があるため、プロトコルに
TCP
を指定し、MONGO
を指定しないことに注意してください。トラフィックが暗号化されている場合、暗号化されたMongoDBプロトコルはIstioプロキシによって解析できません。プレーンなMongoDBプロトコルが暗号化なしで使用されていることがわかっている場合は、プロトコルを
MONGO
として指定し、Istioプロキシに MongoDB関連の統計情報 を生成させることができます。また、プロトコルTCP
が指定されている場合、構成はMongoDBに固有のものではなく、TCP上のプロトコルを持つ他のデータベースでも同じであることに注意してください。MongoDBのホストはTCPルーティングでは使用されないため、
my-mongo.tcp.svc
などの任意のホストを使用できることに注意してください。STATIC
解決とMongoDBサービスのIPを持つエンドポイントに注意してください。このようなエンドポイントを定義すると、ドメイン名を持たないMongoDBサービスにアクセスできます。アプリケーションのウェブページを更新します。これで、アプリケーションはエラーなしで評価を表示するはずです。
正しく表示された本の評価 予想どおり、表示された両方のレビューに星1つの評価が表示されます。外部データベースが実際に使用されていることを確認するために、評価を星1つに設定しました。
エグレスゲートウェイ経由でトラフィックを直接送信する場合は、次のセクションに進んでください。それ以外の場合は、 クリーンアップ を実行します。
エグレスゲートウェイ経由でのTCPエグレストラフィックの直接送信
このセクションでは、 エグレスゲートウェイ を介してトラフィックを直接送信する必要がある場合を処理します。サイドカープロキシは、MongoDBホストのIP(長さ32のCIDRブロック)に一致させることで、MongoDBクライアントからのTCP接続をエグレスゲートウェイにルーティングします。エグレスゲートウェイは、ホスト名でMongoDBホストにトラフィックを転送します。
前のセクション の手順を実行していない場合は、ここで実行します。
MongoDBクライアントのサイドカープロキシとエグレスゲートウェイ間で、 相互TLS認証 を有効にして、エグレスゲートウェイがソースポッドのIDを監視し、そのIDに基づいてMixerポリシーの適用を有効にすることができます。相互TLSを有効にすると、トラフィックも暗号化されます。相互TLSを有効にしたくない場合は、 サイドカープロキシとエグレスゲートウェイ間の相互TLS セクションに進んでください。それ以外の場合は、次のセクションに進んでください。
サイドカーからエグレスゲートウェイへのTCPトラフィックの構成
エグレスゲートウェイ経由でトラフィックを直接送信するためのポート(例:
7777
)を保持するEGRESS_GATEWAY_MONGODB_PORT
環境変数を定義します。メッシュ内の他のサービスで使用されていないポートを選択する必要があります。$ export EGRESS_GATEWAY_MONGODB_PORT=7777
選択したポートを
istio-egressgateway
サービスに追加します。Istioのインストールに使用したのと同じ値を使用する必要があります。具体的には、以前に構成したistio-egressgateway
サービスのすべてのポートを指定する必要があります。$ helm template install/kubernetes/helm/istio/ --name istio-egressgateway --namespace istio-system -x charts/gateways/templates/deployment.yaml -x charts/gateways/templates/service.yaml --set gateways.istio-ingressgateway.enabled=false --set gateways.istio-egressgateway.enabled=true --set gateways.istio-egressgateway.ports[0].port=80 --set gateways.istio-egressgateway.ports[0].name=http --set gateways.istio-egressgateway.ports[1].port=443 --set gateways.istio-egressgateway.ports[1].name=https --set gateways.istio-egressgateway.ports[2].port=$EGRESS_GATEWAY_MONGODB_PORT --set gateways.istio-egressgateway.ports[2].name=mongo | kubectl apply -f -
istio-egressgateway
サービスに選択したポートが実際に存在することを確認します$ kubectl get svc istio-egressgateway -n istio-system NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE istio-egressgateway ClusterIP 172.21.202.204 <none> 80/TCP,443/TCP,7777/TCP 34d
istio-egressgateway
サービスの相互TLS認証を無効にします$ kubectl apply -f - <<EOF apiVersion: authentication.istio.io/v1alpha1 kind: Policy metadata: name: istio-egressgateway namespace: istio-system spec: targets: - name: istio-egressgateway EOF
MongoDBサービスのエグレス
Gateway
、宛先ルール、および仮想サービスを作成して、エグレスゲートウェイ経由で、そしてエグレスゲートウェイから外部サービスへのトラフィックを直接送信します。$ kubectl apply -f - <<EOF apiVersion: networking.istio.io/v1alpha3 kind: Gateway metadata: name: istio-egressgateway spec: selector: istio: egressgateway servers: - port: number: $EGRESS_GATEWAY_MONGODB_PORT name: tcp protocol: TCP hosts: - my-mongo.tcp.svc --- apiVersion: networking.istio.io/v1alpha3 kind: DestinationRule metadata: name: egressgateway-for-mongo spec: host: istio-egressgateway.istio-system.svc.cluster.local subsets: - name: mongo --- apiVersion: networking.istio.io/v1alpha3 kind: DestinationRule metadata: name: mongo spec: host: my-mongo.tcp.svc --- apiVersion: networking.istio.io/v1alpha3 kind: VirtualService metadata: name: direct-mongo-through-egress-gateway spec: hosts: - my-mongo.tcp.svc gateways: - mesh - istio-egressgateway tcp: - match: - gateways: - mesh destinationSubnets: - $MONGODB_IP/32 port: $MONGODB_PORT route: - destination: host: istio-egressgateway.istio-system.svc.cluster.local subset: mongo port: number: $EGRESS_GATEWAY_MONGODB_PORT - match: - gateways: - istio-egressgateway port: $EGRESS_GATEWAY_MONGODB_PORT route: - destination: host: my-mongo.tcp.svc port: number: $MONGODB_PORT weight: 100 EOF
サイドカープロキシとエグレスゲートウェイ間の相互TLS
以前の設定を削除します。
$ kubectl delete gateway istio-egressgateway --ignore-not-found=true $ kubectl delete virtualservice direct-mongo-through-egress-gateway --ignore-not-found=true $ kubectl delete destinationrule egressgateway-for-mongo mongo --ignore-not-found=true $ kubectl delete policy istio-egressgateway -n istio-system --ignore-not-found=true
istio-egressgateway
サービスに対して相互TLS認証を強制します。$ kubectl apply -f - <<EOF apiVersion: authentication.istio.io/v1alpha1 kind: Policy metadata: name: istio-egressgateway namespace: istio-system spec: targets: - name: istio-egressgateway peers: - mtls: {} EOF
MongoDBサービスのエグレス
Gateway
、宛先ルール、および仮想サービスを作成して、エグレスゲートウェイ経由で、そしてエグレスゲートウェイから外部サービスへのトラフィックを直接送信します。$ kubectl apply -f - <<EOF apiVersion: networking.istio.io/v1alpha3 kind: Gateway metadata: name: istio-egressgateway spec: selector: istio: egressgateway servers: - port: number: 443 name: tls protocol: TLS hosts: - my-mongo.tcp.svc tls: mode: MUTUAL serverCertificate: /etc/certs/cert-chain.pem privateKey: /etc/certs/key.pem caCertificates: /etc/certs/root-cert.pem --- apiVersion: networking.istio.io/v1alpha3 kind: DestinationRule metadata: name: egressgateway-for-mongo spec: host: istio-egressgateway.istio-system.svc.cluster.local subsets: - name: mongo trafficPolicy: loadBalancer: simple: ROUND_ROBIN portLevelSettings: - port: number: 443 tls: mode: ISTIO_MUTUAL sni: my-mongo.tcp.svc --- apiVersion: networking.istio.io/v1alpha3 kind: DestinationRule metadata: name: mongo spec: host: my-mongo.tcp.svc --- apiVersion: networking.istio.io/v1alpha3 kind: VirtualService metadata: name: direct-mongo-through-egress-gateway spec: hosts: - my-mongo.tcp.svc gateways: - mesh - istio-egressgateway tcp: - match: - gateways: - mesh destinationSubnets: - $MONGODB_IP/32 port: $MONGODB_PORT route: - destination: host: istio-egressgateway.istio-system.svc.cluster.local subset: mongo port: number: 443 - match: - gateways: - istio-egressgateway port: 443 route: - destination: host: my-mongo.tcp.svc port: number: $MONGODB_PORT weight: 100 EOF
次のセクションに進みます。
エグレストラフィックがエグレスゲートウェイ経由で直接送信されていることを確認します
アプリケーションのウェブページを再度更新し、レーティングが正しく表示されていることを確認します。
エグレスゲートウェイのEnvoyのログを確認し、MongoDBサービスへのリクエストに対応する行を確認します。Istioが
istio-system
名前空間にデプロイされている場合、ログを出力するコマンドは次のとおりです。$ kubectl logs -l istio=egressgateway -n istio-system [2019-04-14T06:12:07.636Z] "- - -" 0 - "-" 1591 4393 94 - "-" "-" "-" "-" "<Your MongoDB IP>:<your MongoDB port>" outbound|<your MongoDB port>||my-mongo.tcp.svc 172.30.146.119:59924 172.30.146.119:443 172.30.230.1:59206 -
TCPエグレストラフィック制御のクリーンアップ
$ kubectl delete serviceentry mongo
$ kubectl delete gateway istio-egressgateway --ignore-not-found=true
$ kubectl delete virtualservice direct-mongo-through-egress-gateway --ignore-not-found=true
$ kubectl delete destinationrule egressgateway-for-mongo mongo --ignore-not-found=true
$ kubectl delete policy istio-egressgateway -n istio-system --ignore-not-found=true
TLSのエグレス制御
現実世界では、外部サービスへの通信の大部分は暗号化されている必要があり、MongoDBプロトコルはTLS上で動作します。また、TLSクライアントは通常、ハンドシェイクの一部としてサーバー名インジケーション(SNI)を送信します。MongoDBサーバーがTLSを実行し、MongoDBクライアントがハンドシェイクの一部としてSNIを送信する場合は、他のTLS with SNIトラフィックと同様にMongoDBエグレストラフィックを制御できます。TLSとSNIを使用すると、MongoDBサーバーのIPアドレスを指定する必要はありません。代わりにホスト名を指定します。これは、IPアドレスの安定性に依存する必要がないため、より便利です。また、ホスト名のプレフィックスとしてワイルドカードを指定することもできます。たとえば、*.com
ドメインの任意のサーバーへのアクセスを許可することができます。
MongoDBサーバーがTLSをサポートしているかどうかを確認するには、次のコマンドを実行します。
$ openssl s_client -connect $MONGODB_HOST:$MONGODB_PORT -servername $MONGODB_HOST
上記のコマンドがサーバーから返された証明書を出力した場合、サーバーはTLSをサポートしています。そうでない場合は、前のセクションで説明されているように、TCPレベルでMongoDBエグレストラフィックを制御する必要があります。
ゲートウェイなしでのTLSエグレストラフィックの制御
もしエグレスゲートウェイが不要な場合は、このセクションの手順に従ってください。エグレスゲートウェイを介してトラフィックを転送する場合は、エグレスゲートウェイを介した直接TCPエグレストラフィックに進みます。
MongoDBサービスの
ServiceEntry
を作成します。$ kubectl apply -f - <<EOF apiVersion: networking.istio.io/v1alpha3 kind: ServiceEntry metadata: name: mongo spec: hosts: - $MONGODB_HOST ports: - number: $MONGODB_PORT name: tls protocol: TLS resolution: DNS EOF
アプリケーションのウェブページを更新します。アプリケーションはエラーなしでレーティングを表示するはずです。
TLSのエグレス設定のクリーンアップ
$ kubectl delete serviceentry mongo
エグレスゲートウェイを介した直接TLSエグレストラフィック
このセクションでは、エグレスゲートウェイを介してトラフィックを転送する必要がある場合の処理について説明します。サイドカープロキシは、MongoDBホストのSNIに一致させることで、MongoDBクライアントからのTLS接続をエグレスゲートウェイにルーティングします。エグレスゲートウェイはトラフィックをMongoDBホストに転送します。サイドカープロキシは送信先ポートを443に書き換えることに注意してください。エグレスゲートウェイはポート443でMongoDBトラフィックを受け入れ、SNIによってMongoDBホストに一致し、ポートをMongoDBサーバーのポートに再度書き換えます。
MongoDBサービスの
ServiceEntry
を作成します。$ kubectl apply -f - <<EOF apiVersion: networking.istio.io/v1alpha3 kind: ServiceEntry metadata: name: mongo spec: hosts: - $MONGODB_HOST ports: - number: $MONGODB_PORT name: tls protocol: TLS - number: 443 name: tls-port-for-egress-gateway protocol: TLS resolution: DNS location: MESH_EXTERNAL EOF
アプリケーションのウェブページを更新し、レーティングが正しく表示されていることを確認します。
MongoDBサービスのエグレス
Gateway
、およびトラフィックをエグレスゲートウェイを介して、そしてエグレスゲートウェイから外部サービスに転送するための宛先ルールと仮想サービスを作成します。アプリケーションポッドのサイドカープロキシとエグレスゲートウェイ間の相互TLS認証を有効にする場合は、次のコマンドを使用します。(エグレスゲートウェイにソースポッドのIDを監視させ、そのIDに基づいてMixerポリシーの適用を有効にするために、相互TLSを有効にしたい場合があります。)
$ kubectl apply -f - <<EOF apiVersion: networking.istio.io/v1alpha3 kind: Gateway metadata: name: istio-egressgateway spec: selector: istio: egressgateway servers: - port: number: 443 name: tls protocol: TLS hosts: - $MONGODB_HOST tls: mode: MUTUAL serverCertificate: /etc/certs/cert-chain.pem privateKey: /etc/certs/key.pem caCertificates: /etc/certs/root-cert.pem --- apiVersion: networking.istio.io/v1alpha3 kind: DestinationRule metadata: name: egressgateway-for-mongo spec: host: istio-egressgateway.istio-system.svc.cluster.local subsets: - name: mongo trafficPolicy: loadBalancer: simple: ROUND_ROBIN portLevelSettings: - port: number: 443 tls: mode: ISTIO_MUTUAL sni: $MONGODB_HOST --- apiVersion: networking.istio.io/v1alpha3 kind: VirtualService metadata: name: direct-mongo-through-egress-gateway spec: hosts: - $MONGODB_HOST gateways: - mesh - istio-egressgateway tls: - match: - gateways: - mesh port: $MONGODB_PORT sni_hosts: - $MONGODB_HOST route: - destination: host: istio-egressgateway.istio-system.svc.cluster.local subset: mongo port: number: 443 tcp: - match: - gateways: - istio-egressgateway port: 443 route: - destination: host: $MONGODB_HOST port: number: $MONGODB_PORT weight: 100 EOF
$ kubectl apply -f - <<EOF apiVersion: networking.istio.io/v1alpha3 kind: Gateway metadata: name: istio-egressgateway spec: selector: istio: egressgateway servers: - port: number: 443 name: tls protocol: TLS hosts: - $MONGODB_HOST tls: mode: PASSTHROUGH --- apiVersion: networking.istio.io/v1alpha3 kind: DestinationRule metadata: name: egressgateway-for-mongo spec: host: istio-egressgateway.istio-system.svc.cluster.local subsets: - name: mongo --- apiVersion: networking.istio.io/v1alpha3 kind: VirtualService metadata: name: direct-mongo-through-egress-gateway spec: hosts: - $MONGODB_HOST gateways: - mesh - istio-egressgateway tls: - match: - gateways: - mesh port: $MONGODB_PORT sni_hosts: - $MONGODB_HOST route: - destination: host: istio-egressgateway.istio-system.svc.cluster.local subset: mongo port: number: 443 - match: - gateways: - istio-egressgateway port: 443 sni_hosts: - $MONGODB_HOST route: - destination: host: $MONGODB_HOST port: number: $MONGODB_PORT weight: 100 EOF
エグレスゲートウェイを介したTLSエグレストラフィック転送のクリーンアップ
$ kubectl delete serviceentry mongo
$ kubectl delete gateway istio-egressgateway
$ kubectl delete virtualservice direct-mongo-through-egress-gateway
$ kubectl delete destinationrule egressgateway-for-mongo
任意のワイルドカードドメインへのMongoDB TLSエグレストラフィックの有効化
場合によっては、同じドメインから複数のホスト名へのエグレストラフィック、たとえば*.<your company domain>.com
からのすべてのMongoDBサービスへのトラフィックを設定したい場合があります。会社内のすべてのMongoDBサービスごとに設定項目を作成したくありません。単一の設定で同じドメインからのすべての外部サービスへのアクセスを設定するには、ワイルドカードホストを使用します。
このセクションでは、ワイルドカードドメインのエグレストラフィックを設定します。私はcomposedb.com
ドメインのMongoDBインスタンスを使用したので、*.com
のエグレストラフィックの設定はうまく機能しました(*.composedb.com
も使用できました)。MongoDBホストに応じてワイルドカードドメインを選択できます。
ワイルドカードドメインのエグレスゲートウェイトラフィックを設定するには、まず、追加のSNIプロキシを使用してカスタムエグレスゲートウェイをデプロイする必要があります。これは、標準のIstioエグレスゲートウェイで使用されるプロキシであるEnvoyの現在の制限によるものです。
SNIプロキシ付きの新しいエグレスゲートウェイの準備
この小節では、標準のIstio Envoyプロキシに加えて、SNIプロキシ付きのエグレスゲートウェイをデプロイします。任意の事前に設定されていないSNI値に従ってトラフィックをルーティングできるSNIプロキシを使用できます。この機能を実現するためにNginxを使用しました。
Nginx SNIプロキシの設定ファイルを作成します。必要に応じて、追加のNginx設定を指定するためにファイルを編集できます。
$ cat <<EOF > ./sni-proxy.conf user www-data; events { } stream { log_format log_stream '\$remote_addr [\$time_local] \$protocol [\$ssl_preread_server_name]' '\$status \$bytes_sent \$bytes_received \$session_time'; access_log /var/log/nginx/access.log log_stream; error_log /var/log/nginx/error.log; # tcp forward proxy by SNI server { resolver 8.8.8.8 ipv6=off; listen 127.0.0.1:$MONGODB_PORT; proxy_pass \$ssl_preread_server_name:$MONGODB_PORT; ssl_preread on; } } EOF
Nginx SNIプロキシの設定を保持するためのKubernetes ConfigMapを作成します。
$ kubectl create configmap egress-sni-proxy-configmap -n istio-system --from-file=nginx.conf=./sni-proxy.conf
次のコマンドは、編集してデプロイする
istio-egressgateway-with-sni-proxy.yaml
を生成します。$ cat <<EOF | helm template install/kubernetes/helm/istio/ --name istio-egressgateway-with-sni-proxy --namespace istio-system -x charts/gateways/templates/deployment.yaml -x charts/gateways/templates/service.yaml -x charts/gateways/templates/serviceaccount.yaml -x charts/gateways/templates/autoscale.yaml -x charts/gateways/templates/role.yaml -x charts/gateways/templates/rolebindings.yaml --set global.mtls.enabled=true --set global.istioNamespace=istio-system -f - > ./istio-egressgateway-with-sni-proxy.yaml gateways: enabled: true istio-ingressgateway: enabled: false istio-egressgateway: enabled: false istio-egressgateway-with-sni-proxy: enabled: true labels: app: istio-egressgateway-with-sni-proxy istio: egressgateway-with-sni-proxy replicaCount: 1 autoscaleMin: 1 autoscaleMax: 5 cpu: targetAverageUtilization: 80 serviceAnnotations: {} type: ClusterIP ports: - port: 443 name: https secretVolumes: - name: egressgateway-certs secretName: istio-egressgateway-certs mountPath: /etc/istio/egressgateway-certs - name: egressgateway-ca-certs secretName: istio-egressgateway-ca-certs mountPath: /etc/istio/egressgateway-ca-certs configVolumes: - name: sni-proxy-config configMapName: egress-sni-proxy-configmap additionalContainers: - name: sni-proxy image: nginx volumeMounts: - name: sni-proxy-config mountPath: /etc/nginx readOnly: true EOF
新しいエグレスゲートウェイをデプロイします。
$ kubectl apply -f ./istio-egressgateway-with-sni-proxy.yaml serviceaccount "istio-egressgateway-with-sni-proxy-service-account" created role "istio-egressgateway-with-sni-proxy-istio-system" created rolebinding "istio-egressgateway-with-sni-proxy-istio-system" created service "istio-egressgateway-with-sni-proxy" created deployment "istio-egressgateway-with-sni-proxy" created horizontalpodautoscaler "istio-egressgateway-with-sni-proxy" created
新しいエグレスゲートウェイが実行されていることを確認します。ポッドには2つのコンテナがあります(1つはEnvoyプロキシ、もう1つはSNIプロキシです)。
$ kubectl get pod -l istio=egressgateway-with-sni-proxy -n istio-system NAME READY STATUS RESTARTS AGE istio-egressgateway-with-sni-proxy-79f6744569-pf9t2 2/2 Running 0 17s
127.0.0.1(
localhost
)に等しい静的アドレスを持つServiceEntryを作成し、新しいServiceEntryに転送されるトラフィックで相互TLSを無効にします。$ kubectl apply -f - <<EOF apiVersion: networking.istio.io/v1alpha3 kind: ServiceEntry metadata: name: sni-proxy spec: hosts: - sni-proxy.local location: MESH_EXTERNAL ports: - number: $MONGODB_PORT name: tcp protocol: TCP resolution: STATIC endpoints: - address: 127.0.0.1 --- apiVersion: networking.istio.io/v1alpha3 kind: DestinationRule metadata: name: disable-mtls-for-sni-proxy spec: host: sni-proxy.local trafficPolicy: tls: mode: DISABLE EOF
新しいエグレスゲートウェイを使用して*.com
へのアクセスを設定します。
*.com
のServiceEntry
を定義します。$ cat <<EOF | kubectl create -f - apiVersion: networking.istio.io/v1alpha3 kind: ServiceEntry metadata: name: mongo spec: hosts: - "*.com" ports: - number: 443 name: tls protocol: TLS - number: $MONGODB_PORT name: tls-mongodb protocol: TLS location: MESH_EXTERNAL EOF
*.com、ポート443、プロトコルTLSのエグレス
Gateway
、ゲートウェイのSNIを設定する宛先ルール、および悪意のあるアプリケーションによるSNIの改ざんを防ぐEnvoyフィルター(フィルターは、アプリケーションによって発行されたSNIがMixerに報告されたSNIであることを確認します)を作成します。$ kubectl apply -f - <<EOF apiVersion: networking.istio.io/v1alpha3 kind: Gateway metadata: name: istio-egressgateway-with-sni-proxy spec: selector: istio: egressgateway-with-sni-proxy servers: - port: number: 443 name: tls protocol: TLS hosts: - "*.com" tls: mode: MUTUAL serverCertificate: /etc/certs/cert-chain.pem privateKey: /etc/certs/key.pem caCertificates: /etc/certs/root-cert.pem --- apiVersion: networking.istio.io/v1alpha3 kind: DestinationRule metadata: name: mtls-for-egress-gateway spec: host: istio-egressgateway-with-sni-proxy.istio-system.svc.cluster.local subsets: - name: mongo trafficPolicy: loadBalancer: simple: ROUND_ROBIN portLevelSettings: - port: number: 443 tls: mode: ISTIO_MUTUAL --- # The following filter is used to forward the original SNI (sent by the application) as the SNI of the mutual TLS # connection. # The forwarded SNI will be reported to Mixer so that policies will be enforced based on the original SNI value. apiVersion: networking.istio.io/v1alpha3 kind: EnvoyFilter metadata: name: forward-downstream-sni spec: filters: - listenerMatch: portNumber: $MONGODB_PORT listenerType: SIDECAR_OUTBOUND filterName: forward_downstream_sni filterType: NETWORK filterConfig: {} --- # The following filter verifies that the SNI of the mutual TLS connection (the SNI reported to Mixer) is # identical to the original SNI issued by the application (the SNI used for routing by the SNI proxy). # The filter prevents Mixer from being deceived by a malicious application: routing to one SNI while # reporting some other value of SNI. If the original SNI does not match the SNI of the mutual TLS connection, the # filter will block the connection to the external service. apiVersion: networking.istio.io/v1alpha3 kind: EnvoyFilter metadata: name: egress-gateway-sni-verifier spec: workloadLabels: app: istio-egressgateway-with-sni-proxy filters: - listenerMatch: portNumber: 443 listenerType: GATEWAY filterName: sni_verifier filterType: NETWORK filterConfig: {} EOF
*.com宛てのトラフィックをエグレスゲートウェイに、そしてエグレスゲートウェイからSNIプロキシにルーティングします。
$ kubectl apply -f - <<EOF apiVersion: networking.istio.io/v1alpha3 kind: VirtualService metadata: name: direct-mongo-through-egress-gateway spec: hosts: - "*.com" gateways: - mesh - istio-egressgateway-with-sni-proxy tls: - match: - gateways: - mesh port: $MONGODB_PORT sni_hosts: - "*.com" route: - destination: host: istio-egressgateway-with-sni-proxy.istio-system.svc.cluster.local subset: mongo port: number: 443 weight: 100 tcp: - match: - gateways: - istio-egressgateway-with-sni-proxy port: 443 route: - destination: host: sni-proxy.local port: number: $MONGODB_PORT weight: 100 EOF
アプリケーションのウェブページを再度更新し、レーティングが正しく表示されていることを確認します。
エグレスゲートウェイのEnvoyプロキシのログを確認します。Istioが
istio-system
名前空間にデプロイされている場合、ログを出力するコマンドは次のとおりです。$ kubectl logs -l istio=egressgateway-with-sni-proxy -c istio-proxy -n istio-system
次のような行が表示されるはずです。
[2019-01-02T17:22:04.602Z] "- - -" 0 - 768 1863 88 - "-" "-" "-" "-" "127.0.0.1:28543" outbound|28543||sni-proxy.local 127.0.0.1:49976 172.30.146.115:443 172.30.146.118:58510 <your MongoDB host> [2019-01-02T17:22:04.713Z] "- - -" 0 - 1534 2590 85 - "-" "-" "-" "-" "127.0.0.1:28543" outbound|28543||sni-proxy.local 127.0.0.1:49988 172.30.146.115:443 172.30.146.118:58522 <your MongoDB host>
SNIプロキシのログを確認します。Istioが
istio-system
名前空間にデプロイされている場合、ログを出力するコマンドは次のとおりです。$ kubectl logs -l istio=egressgateway-with-sni-proxy -n istio-system -c sni-proxy 127.0.0.1 [23/Aug/2018:03:28:18 +0000] TCP [<your MongoDB host>]200 1863 482 0.089 127.0.0.1 [23/Aug/2018:03:28:18 +0000] TCP [<your MongoDB host>]200 2590 1248 0.095
何が起こったのかを理解する
このセクションでは、ワイルドカードドメインを使用してMongoDBホストへのエグレストラフィックを設定しました。単一のMongoDBホストの場合、ワイルドカードドメインを使用しても利点はありません(正確なホスト名を指定できます)が、クラスタ内のアプリケーションがいくつかのワイルドカードドメインに一致する複数のMongoDBホストにアクセスする場合に役立つ可能性があります。たとえば、アプリケーションがmongodb1.composedb.com
、mongodb2.composedb.com
、およびmongodb3.composedb.com
にアクセスする場合、エグレストラフィックはワイルドカードドメイン*.composedb.com
の単一の設定で設定できます。
このセクションで使用されているワイルドカードドメインに一致するホスト名を持つ別のMongoDBインスタンスを使用するようにアプリを設定する場合、追加のIstio設定は不要であることを確認する演習を、読者にお任せします。
任意のワイルドカードドメインへのMongoDB TLSエグレストラフィックの設定のクリーンアップ
*.comの設定項目を削除します。
$ kubectl delete serviceentry mongo $ kubectl delete gateway istio-egressgateway-with-sni-proxy $ kubectl delete virtualservice direct-mongo-through-egress-gateway $ kubectl delete destinationrule mtls-for-egress-gateway $ kubectl delete envoyfilter forward-downstream-sni egress-gateway-sni-verifier
egressgateway-with-sni-proxy
デプロイメントの設定項目を削除します。$ kubectl delete serviceentry sni-proxy $ kubectl delete destinationrule disable-mtls-for-sni-proxy $ kubectl delete -f ./istio-egressgateway-with-sni-proxy.yaml $ kubectl delete configmap egress-sni-proxy-configmap -n istio-system
作成した設定ファイルを削除します。
$ rm ./istio-egressgateway-with-sni-proxy.yaml $ rm ./nginx-sni-proxy.conf
クリーンアップ
bookinfo
ユーザーを削除します。$ cat <<EOF | mongo --ssl --sslAllowInvalidCertificates $MONGODB_HOST:$MONGODB_PORT -u admin -p $MONGO_ADMIN_PASSWORD --authenticationDatabase admin use test db.dropUser("bookinfo"); EOF
ratingsコレクションを削除します。
$ cat <<EOF | mongo --ssl --sslAllowInvalidCertificates $MONGODB_HOST:$MONGODB_PORT -u admin -p $MONGO_ADMIN_PASSWORD --authenticationDatabase admin use test db.ratings.drop(); EOF
使用した環境変数をクリアします。
$ unset MONGO_ADMIN_PASSWORD BOOKINFO_PASSWORD MONGODB_HOST MONGODB_PORT MONGODB_IP
仮想サービスを削除します。
$ kubectl delete -f @samples/bookinfo/networking/virtual-service-ratings-db.yaml@ Deleted config: virtual-service/default/reviews Deleted config: virtual-service/default/ratings
ratings v2-mongodbをアンデプロイします。
$ kubectl delete -f @samples/bookinfo/platform/kube/bookinfo-ratings-v2.yaml@ deployment "ratings-v2" deleted
結論
このブログ投稿では、MongoDBエグレストラフィック制御のさまざまなオプションを示しました。適用可能な場合は、TCPまたはTLSレベルでMongoDBエグレストラフィックを制御できます。TCPとTLSの両方の場合、組織のセキュリティ要件に従って、サイドカープロキシから外部MongoDBホストに直接トラフィックを転送するか、エグレスゲートウェイを介してトラフィックを転送できます。後者の場合、サイドカープロキシとエグレスゲートウェイ間の相互TLS認証を適用または無効にすることも決定できます。*.com
のようなワイルドカードドメインを指定してTLSレベルでMongoDBエグレストラフィックを制御し、エグレスゲートウェイを介してトラフィックを転送する必要がある場合は、SNIプロキシ付きのカスタムエグレスゲートウェイをデプロイする必要があります。
このブログ投稿でMongoDBについて説明されている設定と考慮事項は、TCP/TLS上の他の非HTTPプロトコルについてもほぼ同じです。