イングレスアクセス制御
このタスクでは、承認ポリシーを使用してIstioイングレスゲートウェイでIPベースのアクセス制御を強制する方法を示します。
始める前に
このタスクを開始する前に、次の手順を実行してください。
Istioの承認に関する概念をお読みください。
Istioインストールガイドを使用してIstioをインストールします。
サイドカーインジェクションが有効になっている名前空間
fooにワークロードhttpbinをデプロイします。$ kubectl create ns foo $ kubectl label namespace foo istio-injection=enabled $ kubectl apply -f @samples/httpbin/httpbin.yaml@ -n fooイングレスゲートウェイを介して
httpbinを公開します。
次のコマンドを使用して、
httpbinワークロードとイングレスゲートウェイが期待通りに動作していることを確認します。$ curl "$INGRESS_HOST:$INGRESS_PORT"/headers -s -o /dev/null -w "%{http_code}\n" 200
KubernetesとIstioへのトラフィックの取り込み
Kubernetesにトラフィックを取り込むすべての方法は、すべてのワーカーノードでポートを開くことを含みます。これを実現する主な機能は、NodePortサービスとLoadBalancerサービスです。KubernetesのIngressリソースでさえ、NodePortサービスまたはLoadBalancerサービスを作成するイングレスコントローラーによってバックアップされる必要があります。
NodePortは、各ワーカーノードの30000〜32767の範囲でポートを開き、ラベルセレクターを使用してトラフィックを送信するPodを識別します。ワーカーノードの前に何らかのロードバランサーを手動で作成するか、ラウンドロビンDNSを使用する必要があります。LoadBalancerはNodePortと似ていますが、ワーカーノードへのトラフィックの分散を処理するための環境固有の外部ロードバランサーも作成します。たとえば、AWS EKSでは、LoadBalancerサービスはワーカーノードをターゲットとして持つClassic ELBを作成します。Kubernetes環境にLoadBalancerの実装がない場合は、NodePortのように動作します。IstioイングレスゲートウェイはLoadBalancerサービスを作成します。
NodePortまたはLoadBalancerからのトラフィックを処理しているPodが、トラフィックを受信したワーカーノードで実行されていない場合はどうなりますか?Kubernetesには、パケットを受信して正しいノードに転送するkube-proxyと呼ばれる独自の内部プロキシがあります。
元のクライアントの送信元IPアドレス
パケットが外部プロキシロードバランサーとkube-proxyを通過する場合、クライアントの元の送信元IPアドレスは失われます。次のセクションでは、さまざまなロードバランサーの種類について、ログ記録またはセキュリティの目的で元のクライアントIPを保持するためのいくつかの戦略について説明します。
参考までに、一般的なマネージドKubernetes環境でLoadBalancerサービスを使用してIstioによって作成されるロードバランサーの種類を以下に示します。
| クラウドプロバイダー | ロードバランサー名 | ロードバランサーの種類 |
|---|---|---|
| AWS EKS | Classic Elastic Load Balancer | TCPプロキシ |
| GCP GKE | TCP/UDPネットワークロードバランサー | ネットワーク |
| Azure AKS | Azureロードバランサー | ネットワーク |
| IBM IKS/ROKS | ネットワークロードバランサー | ネットワーク |
| DO DOKS | ロードバランサー | ネットワーク |
TCP/UDPプロキシロードバランサー
TCP/UDPプロキシ外部ロードバランサー(AWS Classic ELB)を使用している場合は、PROXYプロトコルを使用して、元のクライアントIPアドレスをパケットデータに埋め込むことができます。動作させるには、外部ロードバランサーとIstioイングレスゲートウェイの両方がPROXYプロトコルをサポートする必要があります。
AWS EKSでイングレスゲートウェイがPROXYプロトコルをサポートするようにする方法を示すサンプル構成を以下に示します。
ネットワークロードバランサー
クライアントIPアドレスを保持するTCP/UDPネットワークロードバランサー(AWSネットワークロードバランサー、GCP外部ネットワークロードバランサー、Azureロードバランサー)を使用している場合、またはラウンドロビンDNSを使用している場合は、externalTrafficPolicy: Local設定を使用して、kube-proxyをバイパスし、他のノードへのトラフィックの送信を防ぐことで、Kubernetes内部でもクライアントIPを保持できます。
次のコマンドを使用して、イングレスゲートウェイを更新し、externalTrafficPolicy: Localを設定して、イングレスゲートウェイで元のクライアント送信元IPを保持します。
HTTP/HTTPSロードバランサー
HTTP/HTTPS外部ロードバランサー(AWS ALB、GCPなど)を使用している場合は、元のクライアントIPアドレスをX-Forwarded-Forヘッダーに配置できます。Istioは、いくつかの設定を行うことで、このヘッダーからクライアントIPアドレスを抽出できます。ゲートウェイネットワークトポロジの設定を参照してください。Kubernetesの前に単一のロードバランサーを使用する場合の簡単な例
apiVersion: install.istio.io/v1alpha1
kind: IstioOperator
spec:
meshConfig:
accessLogEncoding: JSON
accessLogFile: /dev/stdout
defaultConfig:
gatewayTopology:
numTrustedProxies: 1
IPベースの許可リストと拒否リスト
ipBlocksとremoteIpBlocksを使用する場合:X-Forwarded-For HTTPヘッダーまたはPROXYプロトコルを使用して元のクライアントIPアドレスを決定する場合は、AuthorizationPolicyでremoteIpBlocksを使用する必要があります。externalTrafficPolicy: Localを使用する場合は、AuthorizationPolicyでipBlocksを使用する必要があります。
| ロードバランサーの種類 | クライアントIPのソース | ipBlocksとremoteIpBlocks |
|---|---|---|
| TCPプロキシ | PROXYプロトコル | remoteIpBlocks |
| ネットワーク | パケット送信元アドレス | ipBlocks |
| HTTP/HTTPS | X-Forwarded-For | remoteIpBlocks |
- 次のコマンドは、Istioイングレスゲートウェイの承認ポリシー
ingress-policyを作成します。次のポリシーは、actionフィールドをALLOWに設定して、ipBlocksに指定されたIPアドレスがイングレスゲートウェイにアクセスできるようにします。リストにないIPアドレスは拒否されます。ipBlocksは、単一のIPアドレスとCIDR表記の両方をサポートします。
イングレスゲートウェイへの要求が拒否されることを確認します。
$ curl "$INGRESS_HOST:$INGRESS_PORT"/headers -s -o /dev/null -w "%{http_code}\n" 403元のクライアントIPアドレスをenv変数に割り当てます。わからない場合は、次のコマンドを使用してEnvoyログで確認できます。
- クライアントIPアドレスを含むように
ingress-policyを更新します。
イングレスゲートウェイへの要求が許可されることを確認します。
$ curl "$INGRESS_HOST:$INGRESS_PORT"/headers -s -o /dev/null -w "%{http_code}\n" 200ingress-policy承認ポリシーを更新して、actionキーをDENYに設定し、ipBlocksに指定されたIPアドレスがイングレスゲートウェイにアクセスできないようにします。
イングレスゲートウェイへの要求が拒否されることを確認します。
$ curl "$INGRESS_HOST:$INGRESS_PORT"/headers -s -o /dev/null -w "%{http_code}\n" 403オンラインプロキシサービスを使用して、別のクライアントIPを使用してイングレスゲートウェイにアクセスし、要求が許可されていることを確認できます。
期待する応答が得られない場合は、RBACデバッグ情報が表示されるイングレスゲートウェイログを表示します。
クリーンアップ
- 承認ポリシーの削除
名前空間
fooの削除$ kubectl delete namespace foo