Istioエグレスゲートウェイを使用したレガシーサービスのプロキシ

メッシュからのエグレス通信をきめ細かく制御するために、複数のIstioエグレスゲートウェイを独立してデプロイします。

2020年12月16日 | 著者: Antonio Berben - Deutsche Telekom - PAN-NET

Deutsche Telekom Pan-Netでは、サービスを包括するためにIstioを採用しています。残念ながら、まだKubernetesに移行されていない、または移行できないサービスがあります。

これらのアップストリームサービスに対するプロキシサービスとしてIstioを設定できます。これにより、レガシーサービスがそのままの状態であっても、認証/認可、トレーサビリティ、可観測性などの機能を利用できます。

この記事の最後には、シナリオをシミュレートできる実践的な演習があります。演習では、https://httpbin.orgでホストされているアップストリームサービスがIstioエグレスゲートウェイによってプロキシされます。

Istioに詳しい方であれば、アップストリームサービスに接続するために提供される方法の1つがエグレスゲートウェイであることはご存知でしょう。

すべてのアップストリームトラフィックを制御するために1つデプロイすることも、きめ細かい制御を行い、この図に示すように単一責任の原則を満たすために複数デプロイすることもできます。

Overview multiple Egress Gateways
複数のエグレスゲートウェイの概要

このモデルでは、1つのエグレスゲートウェイが1つのアップストリームサービスを正確に担当します。

Operatorの仕様では複数のエグレスゲートウェイをデプロイできますが、マニフェストが管理しにくくなる可能性があります。

apiVersion: install.istio.io/v1alpha1
kind: IstioOperator
[...]
spec:
    egressGateways:
    - name: egressgateway-1
      enabled: true
    - name: egressgateway-2
      enabled: true
    [egressgateway-3, egressgateway-4, ...]
    - name: egressgateway-N
      enabled: true
[...]

エグレスゲートウェイをOperatorマニフェストから切り離すことで、サービス(ゲートウェイとアップストリームサービス)の両方を整合させるために、カスタムの readiness プローブを設定できるようになります。

また、OPAをサイドカーとしてポッドに注入して、複雑なルールで認証を実行することもできます(OPA Envoyプラグイン)。

Authorization with OPA and `healthcheck` to upstream service
OPAによる認証と外部への`healthcheck`

ご覧のとおり、可能性が広がり、Istioは非常に拡張性が高くなります。

このパターンを実装する方法を見てみましょう。

ソリューション

このタスクを実行する方法はいくつかありますが、ここでは複数のOperatorを定義し、生成されたリソースをデプロイする方法を紹介します。

次のセクションでは、アップストリームサービス: httpbinhttps://httpbin.org/)に接続するためのエグレスゲートウェイをデプロイします。

最終的に、次のものが得られます

Communication
通信

実践

前提条件

Kind

これをconfig.yamlとして保存します。

kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
kubeadmConfigPatches:
  - |
    apiVersion: kubeadm.k8s.io/v1beta2
    kind: ClusterConfiguration
    metadata:
      name: config
    apiServer:
      extraArgs:
        "service-account-issuer": "kubernetes.default.svc"
        "service-account-signing-key-file": "/etc/kubernetes/pki/sa.key"
$ kind create cluster --name <my-cluster-name> --config config.yaml

ここで、<my-cluster-name>はクラスターの名前です。

Istioctlを使用したIstio Operator

Operatorをインストールします

$ istioctl operator init --watchedNamespaces=istio-operator
$ kubectl create ns istio-system

これをoperator.yamlとして保存します。

apiVersion: install.istio.io/v1alpha1
kind: IstioOperator
metadata:
  name: istio-operator
  namespace: istio-operator
spec:
  profile: default
  tag: 1.8.0
  meshConfig:
    accessLogFile: /dev/stdout
    outboundTrafficPolicy:
      mode: REGISTRY_ONLY
$ kubectl apply -f operator.yaml

エグレスゲートウェイのデプロイ

このタスクの手順では、次のことを前提としています。

Istio 1.8では、作成されたリソースをきめ細かく制御するために、オーバーレイ構成を適用する機能が導入されました。

これをegress.yamlとして保存します。

apiVersion: install.istio.io/v1alpha1
kind: IstioOperator
spec:
  profile: empty
  tag: 1.8.0
  namespace: httpbin
  components:
    egressGateways:
    - name: httpbin-egress
      enabled: true
      label:
        app: istio-egressgateway
        istio: egressgateway
        custom-egress: httpbin-egress
      k8s:
        overlays:
        - kind: Deployment
          name: httpbin-egress
          patches:
          - path: spec.template.spec.containers[0].readinessProbe
            value:
              failureThreshold: 30
              exec:
                command:
                  - /bin/sh
                  - -c
                  - curl https://#:15021/healthz/ready && curl https://httpbin.org/status/200
              initialDelaySeconds: 1
              periodSeconds: 2
              successThreshold: 1
              timeoutSeconds: 1
  values:
    gateways:
      istio-egressgateway:
        runAsRoot: true

エグレスゲートウェイをインストールする名前空間を作成します

$ kubectl create ns httpbin

ドキュメントで説明されているように、複数のOperatorリソースをデプロイできます。ただし、事前に解析してからクラスターに適用する必要があります。

$ istioctl manifest generate -f egress.yaml | kubectl apply -f -

Istioの設定

次に、https://httpbin.orgのアップストリームサービスへの接続を許可するようにIstioを設定します。

TLSの証明書

クラスター外部からエグレスサービスへの安全な接続を行うには、証明書が必要です。

証明書の生成方法については、Istio イングレスドキュメントで説明しています。

この記事の最後に、クラスター外部からサービスにアクセスするために使用する証明書を作成して適用します(<my-proxied-service-hostname>

$ kubectl create -n istio-system secret tls <my-secret-name> --key=<key> --cert=<cert>

ここで、<my-secret-name>Gatewayリソースに使用される名前です。<key><cert>は証明書のファイルです。<cert>

イングレスゲートウェイ

リクエストを受け入れるようにイングレスゲートウェイを操作するためのGatewayリソースを作成します。

apiVersion: networking.istio.io/v1beta1
kind: Gateway
metadata:
  name: my-ingressgateway
  namespace: istio-system
spec:
  selector:
    istio: ingressgateway
  servers:
  - hosts:
    - "<my-proxied-service-hostname>"
    port:
      name: http
      number: 80
      protocol: HTTP
    tls:
     httpsRedirect: true
  - port:
      number: 443
      name: https
      protocol: https
    hosts:
    - "<my-proxied-service-hostname>"
    tls:
      mode: SIMPLE
      credentialName: <my-secret-name>

ここで、<my-proxied-service-hostname>my-ingressgatewayを介してサービスにアクセスするためのホスト名であり、<my-secret-name>は証明書を含むシークレットです。

エグレスゲートウェイ

別のGatewayオブジェクトを作成しますが、今回はすでにインストールしたエグレスゲートウェイを操作するためのものです

apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
  name: "httpbin-egress"
  namespace: "httpbin"
spec:
  selector:
    istio: egressgateway
    service.istio.io/canonical-name: "httpbin-egress"
  servers:
  - hosts:
    - "<my-proxied-service-hostname>"
    port:
      number: 80
      name: http
      protocol: HTTP

ここで、<my-proxied-service-hostname>my-ingressgatewayを介してアクセスするためのホスト名です。

Virtual Service

3つのユースケースに対応するVirtualServiceを作成します。

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: "httpbin-egress"
  namespace: "httpbin"
spec:
  hosts:
  - "<my-proxied-service-hostname>"
  gateways:
  - mesh
  - "istio-system/my-ingressgateway"
  - "httpbin/httpbin-egress"
  http:
  - match:
    - gateways:
      - "istio-system/my-ingressgateway"
      - mesh
      uri:
        prefix: "/"
    route:
    - destination:
        host: "httpbin-egress.httpbin.svc.cluster.local"
        port:
          number: 80
  - match:
    - gateways:
      - "httpbin/httpbin-egress"
      uri:
        prefix: "/"
    route:
    - destination:
        host: "httpbin.org"
        subset: "http-egress-subset"
        port:
          number: 443

ここで、<my-proxied-service-hostname>my-ingressgatewayを介してアクセスするためのホスト名です。

Service Entry

アップストリームサービスへの通信を許可するためのServiceEntryを作成します

apiVersion: networking.istio.io/v1alpha3
kind: ServiceEntry
metadata:
  name: "httpbin-egress"
  namespace: "httpbin"
spec:
  hosts:
  - "httpbin.org"
  location: MESH_EXTERNAL
  ports:
  - number: 443
    name: https
    protocol: TLS
  resolution: DNS

Destination Rule

ドキュメントで説明されているように、エグレストラフィックのTLSオリジネーションを許可するためのDestinationRuleを作成します

apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
  name: "httpbin-egress"
  namespace: "httpbin"
spec:
  host: "httpbin.org"
  subsets:
  - name: "http-egress-subset"
    trafficPolicy:
      loadBalancer:
        simple: ROUND_ROBIN
      portLevelSettings:
      - port:
          number: 443
        tls:
          mode: SIMPLE

ピア認証

サービス間を安全にするには、mTLSを強制する必要があります

apiVersion: "security.istio.io/v1beta1"
kind: "PeerAuthentication"
metadata:
  name: "httpbin-egress"
  namespace: "httpbin"
spec:
  mtls:
    mode: STRICT

テスト

オブジェクトがすべて正しく指定されていることを確認します

$ istioctl analyze --all-namespaces

外部アクセス

ingressgatewayサービスのポートを転送し、サービスを呼び出して、クラスター外部からエグレスゲートウェイをテストします

$ kubectl -n istio-system port-forward svc/istio-ingressgateway 15443:443
$ curl -vvv -k -HHost:<my-proxied-service-hostname> --resolve "<my-proxied-service-hostname>:15443:127.0.0.1" --cacert <cert> "https://<my-proxied-service-hostname>:15443/status/200"

ここで、<my-proxied-service-hostname>my-ingressgatewayを介してアクセスするためのホスト名であり、<cert>ingressgatewayオブジェクト用に定義された証明書です。これは、TLSを終端しないtls.mode: SIMPLEが原因です

サービス間アクセス

スリープサービスをデプロイして、クラスター内からエグレスゲートウェイをテストします。これはフェイルオーバーを設計する場合に役立ちます。

$ kubectl label namespace httpbin istio-injection=enabled --overwrite
$ kubectl apply -n httpbin -f  https://raw.githubusercontent.com/istio/istio/release-1.24/samples/sleep/sleep.yaml
$ kubectl -n httpbin "$(kubectl get pod -n httpbin -l app=sleep -o jsonpath={.items..metadata.name})" -- curl -vvv http://<my-proxied-service-hostname>/status/200

ここで、<my-proxied-service-hostname>my-ingressgatewayを介してアクセスするためのホスト名です。

次に、他のアップストリームサービスを指す2番目、3番目、4番目のエグレスゲートウェイを作成します。

終わりに

Istioは構成が複雑に見えるかもしれません。しかし、サービスにもたらす大きなメリット(Kialiにもオレー!)を考えると、間違いなく価値があります。

Istioの開発方法により、この記事で紹介したような特殊な要件を最小限の労力で満たすことができます。

最後に、優れたクラウドネイティブテクノロジーとしてのIstioは、大規模なチームによる保守を必要としないことを指摘しておきたいと思います。たとえば、現在のチームは3人のエンジニアで構成されています。

Istioとその可能性についてさらに議論するには、私たちの一人にご連絡ください

この記事を共有する