#はじめに
IstioのAuthorization Policyを使って送信元IPアドレス制限を試してみたいと思います。
##Authorization Policyとは
Authorization Policyは、IstioのCRDでService mesh内のワークロードのアクセス制御を可能にします。
承認ポリシーは、許可ポリシーと拒否ポリシーの両方をサポートします。許可ポリシーと拒否ポリシーがワークロードに同時に使用される場合、拒否ポリシーが最初に評価されます。評価は、次のルールによって決定されます。
リクエストに一致するDENYポリシーがある場合は、リクエストを拒否します。
ワークロードにALLOWポリシーがない場合は、要求を許可します。
ALLOWポリシーのいずれかが要求に一致する場合は、要求を許可します。
リクエストを拒否します。
Istio 1.7
https://istio.io/latest/docs/reference/config/security/authorization-policy/
Istio 1.6
https://istio.io/v1.6/docs/tasks/security/authorization/authz-ingress/
##確認した環境
GKEバージョン:1.17.12-gke.1504
Anthos Service Mesh(ASM, Istio):1.6.11
Anthos Service Meshは、Googleのフルマネージドサービスメッシュです。Istio 互換の API, コントロールプレーンを Google が管理します。
https://cloud.google.com/anthos/service-mesh
#試した構成
Authorization Policyを、istio-system namespaceで有効にして、Istio Ingress Gatewayに対する通信において、送信元IPアドレス制限を実現します。
namespace単位でenforce可能です。また、細かく制御したい場合は、Selectorでも指定可能です。
#設定内容
以下のPolicyでは、istio-systemに存在するワークロードは、指定したIPアドレス(X.X.X.X)からの通信のみ許可されます。つまり、X.X.X.X以外のIPアドレスからの通信は拒否されます
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
name: ingress-policy
namespace: istio-system
spec:
action: ALLOW
rules:
- from:
- source:
ipBlocks: ["X.X.X.X"]
#試してみます
以下を参考にASMをインストールします。
https://cloud.google.com/service-mesh/docs/scripted-install/gke-asm-onboard-1-7
以下を参考にサンプルアプリケーションをインストールします。
https://cloud.google.com/service-mesh/docs/onlineboutique-install-kpt
AuthorizationPolicyを作成します。
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
name: ingress-policy
namespace: istio-system
spec:
action: ALLOW
rules:
- from:
- source:
ipBlocks: ["X.X.X.X"]
istio ingress gatewayに対して接続してみる。
$ k get svc istio-ingressgateway -n istio-system
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
istio-ingressgateway LoadBalancer 10.228.5.0 34.X.X.X 15021:32664/TCP,80:31208/TCP,443:31006/TCP,15443:30608/TCP 10d
接続試してみます。access deniedになります。
$ curl 34.X.X.X
RBAC: access denied
これは、Istio Ingress Gatewayへの通信がNATされていて、送信元IPアドレスが設定したしたものと異なるために発生します。docker.io/kennethreitz/httpbinをデプロイしてみて、送信元IPアドレスを確認してみます。
https://istio.io/v1.6/docs/tasks/security/authorization/authz-ingress/
apiVersion: v1
kind: Service
metadata:
name: http-bin
spec:
selector:
app: httpbin
version: v1
type: LoadBalancer
ports:
- port: 80
targetPort: 80
apiVersion: apps/v1
kind: Deployment
metadata:
name: httpbin
spec:
replicas: 1
selector:
matchLabels:
app: httpbin
version: v1
template:
metadata:
labels:
app: httpbin
version: v1
spec:
containers:
- image: docker.io/kennethreitz/httpbin
imagePullPolicy: IfNotPresent
name: httpbin
ports:
- containerPort: 80
Localから接続確認した場合、IPアドレスはVPCのアドレスにNATされます。
$ curl 34.Y.Y.Y/ip
{
"origin": "10.224.3.1"
}
こちらを防ぐには、serviceの設定に externalTrafficPolicy: Localを記載します。externalTrafficPolicyを設定して、再度確認してみます。
apiVersion: v1
kind: Service
metadata:
name: http-bin
spec:
selector:
app: httpbin
version: v1
type: LoadBalancer
ports:
- port: 80
targetPort: 80
externalTrafficPolicy: Local
Localの送信IPアドレスがそのまま使えるようになりました。
$ curl 34.Y.Y.Y/ip
{
"origin": "164.70.X.X"
}
Istio Ingress GatewayのサービスにもexternalTrafficPolicy: Localを設定します。
k edit svc istio-ingressgateway -n istio-system
$ curl 34.X.X.X -o /dev/null -w '%{http_code}\n' -s
200
接続できました。
Authorization Policyで指定したIPアドレスと異なる送信元からだとエラーになります。
$ curl 34.X.X.X -o /dev/null -w '%{http_code}\n' -s
403
$ curl 34.X.X.X
RBAC: access denied
#注意点
externalTrafficPolicy: Localにした場合、リクエストを受け取ったNodeに該当のPodがいない場合、リクエストが破棄されます。
ASMバージョンアップ時に、Istio Ingress Gatewayの設定が上書きされる可能性があります。