Cloud Armor + Cloud IAPでKubernetes Podへセキュアにアクセスする
機械学習モデルの開発やデータ解析において、Jupyterはデファクトツールと言えるでしょう。また、分析結果をRedash などのBIツールを通してチームメンバーにシェアすることは日常茶飯事だと思います。
そういったWebツールを構築する場合には、少なからず実業務のデータを取り扱うという性質上、常にセキュリティの問題がつきまといます。
- IP制限
- 個人単位での認証管理
- SSL通信
etc…
こういったセキュリティ要件を、ツールが導入されるたびに設定するのはとてもめんどうですし、また設定漏れにも注意が必要です。
今回、GCPの機能を使って、Kubernetes(k8s)のPodを立てたら、上記セキュリティ対策が(なるべく)自動で設定されるような仕組みを作ってみました。
全体構成 :
それぞれ、下記の機能で実現します。
- IP制限… Cloud Armor
- 個人単位の認証 … Cloud IAP
- SSL通信 … Cloud Load Balancer
事前構築
以下はすでに構築 or インストール済みとします。
- GKEクラスタ
- kubectlコマンド
- jqコマンド
Pod ~ Service ~ Ingressによる外部公開まで
今回はnginxをウェブアプリとして、80番ポートに対して外部からアクセスできるよう、ServiceとIngressで外部と通信できるようにします。
まずはPodを作ります。
# deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: sample-app
spec:
replicas: 1
selector:
matchLabels:
app: sample-app
template:
metadata:
labels:
app: sample-app
spec:
containers:
- name: nginx-container
image: nginx:1.15.7
マニフェストを作成したら、クラスタにデプロイします。
$ kubectl apply -f deployment.yaml
deployment.apps "sample-app" created
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
sample-app-647897db5d-r2467 1/1 Running 0 19s
k8s Ingressの追加
続いて、Ingressを構築していきます。
PodへのアクセスはService単体でできますが、そのルーティングはL4になります。
一方、KubernetesのIngressはL7のロードバランサを実現するもので、後述するCloud ArmorやCloud IAPと組み合わせるために必要です。
L7のため、パスに応じたルーティングを設定することもできます。
NodePort Serviceのデプロイ
Ingressは直接Podにつながるわけではなく、Serviceへの通信をルーティングするものであるため、先にIngress用のServiceを type: Nodeport
で作ります。
# serivce.yaml
apiVersion: v1
kind: Service
metadata:
name: sample-app-service
spec:
type: NodePort
ports:
- name: "http-port"
protocol: "TCP"
port: 8080
targetPort: 80
selector:
app: sample-app
Nginxの80ポートにNodePort:8080をつなげています。
$ kubectl apply -f service.yaml
service "sample-app-service" created
デプロイできたら、接続を確認します。kubectl port-forward
でlocalの8000番と、Serviceの8080番をつなげます。
$ kubectl port-forward service/sample-app-service 8000:8080
Forwarding from 127.0.0.1:8000 -> 80
Forwarding from [::1]:8000 -> 80
Handling connection for 8000
Handling connection for 8000
http://localhost:8000 にアクセスすると、正常に表示されることが確認できます。
Ingressのデプロイ
続いてIngressでHTTP Load Balancerを構築します。
今回はあらかじめStatic IPを作成しておいてから、それをIngressのLBに割り当てます。
# LBに割り当てる場合、Static IPはGlobal IPである必要があるみたいです。
$ gcloud compute addresses create --global sample-app-ip
Created
$ IP_ADDR=$(gcloud --format=json compute addresses describe sample-app-ip --global | jq -r ".address")
次に、SSL通信用の(オレオレ)シークレットを作成します。
今回ドメインを取るのは面倒なので、xip.io を利用します。
xip.ioは任意のIPアドレスに対してドメイン名によるアクセスを可能にしてくれるので、「ドメイン取るほどではなけいどSSLにしたい」、という用途で重宝します。
$ openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout ./tls.key -out ./tls.crt -subj "/CN=${IP_ADDRESS}.xip.io"
$ kubectl create secret tls --save-config sample-app-tls --key tls.key --cert tls.crt
作成したシークレットとIPアドレスを使って、Ingressを作ります。
#ingress.yaml
echo """apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: sample-app-ingress
annotations:
kubernetes.io/ingress.allow-http: \"false\"
kubernetes.io/ingress.global-static-ip-name: "sample-app-ip"
spec:
rules:
- host: ${IP_ADDR}.xip.io
http:
paths:
- path: /*
backend:
serviceName: sample-app-service
servicePort: 8080
tls:
- hosts:
- ${IP_ADDR}.xip.io
secretName: sample-app-tls
""" > ingress.yaml
Ingressをデプロイします。
$ kubectl apply -f ingress.yaml
ingress.extensions "sample-app-ingress" created
作成したサービスに対してもport-forwardして接続に問題がないことを確認します。
特に認証が必要なければここまででもよいのですが、サービスが全世界に公開されてしまっていますので、さらにアクセス制限をかけていきます。
Cloud IAPの設定
Cloud IAPについてはGCPのドキュメントが詳しいです。
IAPを使えばGCPのLBにGoogleアカウントによる認証をかけることができます。LBの段階で認証をかけるので、その先に存在するサービスでは難しい認証機構を用意しなくとも済む、というのがメリットです。
またHTTPヘッダーにアカウント名がついてくるので、それを使えばアプリケーション側で独自に認可機構を加えることもできます。
このCloud IAP、エンタープライズでは非常に強力な機能で、例えば企業でGSuiteを導入していれば、従業員のアカウントをそのまま認証用アカウントに設定できます。
また、Google Groupも登録できるので、ロールごとにグループを作成して、そのロールに対してアクセス許可をする、ということもできます。ここらへんはGCPの IAMのメリットでもありますね。
今回はIngressで立てたLBにCloud IAPを設定します。
まずはCloud IAPをGCP Consoleからセットアップします。
初回の場合は、OAuthの同意画面設定が必要です。
「アプリケーション名」: sample-app
「ドメイン名」: xip.io
上記手順で作成した場合、IAPの設定画面にはすでにIngressで作成したLBが表示されているかと思います。
また、Cloud IAPでは、該当のServiceへのアクセス経路がIAP経由以外に存在する場合、「警告」を出してくれます。今回VPCネットワーク内の通信は許可しているので警告が出ていますが、そのまま続行します。
Cloud IAPを有効にすると、権限設定画面が表示されので、どのgmailアカウントに対してCloud IAP経由のアクセスを許可するか、アカウント単位で設定します。
以上で、Cloud IAPの設定は完了です。
Cloud Armor
続いて、Cloud ArmorによるIPアドレス制限を追加します。
GCPのLBは単体ではIP制限の機能はありませんが、Cloud Armorを設定すれば通信元IPアドレスのブラックリスト/ホワイトリスト管理ができます。
GCP Consoleから手動で設定してもいいのですが、GKEでは(ベータですが)IngressマニフェストのメタデータでCloud Armorの紐づけを記述できるので、これを利用するとよいでしょう。
まずはCloud Armorの設定を作成します。ここでは、作業中のマシンのIPアドレス以外のトラフィックを弾くようにします。
$ gcloud compute security-policies create sample-app-policy --description "sample app armor policy"
$ gcloud compute security-policies rules create 10000 \
--security-policy sample-app-policy \
--description "deny all" \
--src-ip-ranges="*" \
--action "deny-404"
# 作業PCのIPアドレス取得
$ MY_IP_ADDR=$(curl ifconfig.me)
$ gcloud compute security-policies rules create 1000 \
--security-policy sample-app-policy \
--description "allow traffic from local machine" \
--src-ip-ranges "$MY_IP_ADDR/32" \
--action "allow"
Backend Configマニフェストに、作成したCloud Armorのポリシー名を spec.securityPolicy.name
に指定してデプロイします。
# backendconfig.yaml
apiVersion: cloud.google.com/v1beta1
kind: BackendConfig
metadata:
name: sample-app-backendconfig
spec:
securityPolicy:
name: "sample-app-policy"
(ちなみに、BackendConfigでは様々な設定を追加でき、先のCloud IAPもBackend Config経由で設定できるようです。)
つづいて、作成したBackend ConfigをServiceのポートに紐づけます。先程作成した service.yaml
に、metadataを1つ追加します。
# service.yaml
apiVersion: v1
kind: Service
metadata:
name: sample-app-service
# 追加
annotations:
beta.cloud.google.com/backend-config: '{
"ports": {
"8080": "sample-app-backendconfig"
}
}'
spec:
type: NodePort
# <省略>
追加するのはbeta.cloud.google.com/backend-config
annotationで、Serviceのポートと、作成したBackend Config名を1:1で記述します。
この設定により、8080ポートに対して、BackendConfig( sample-app-backendconfig
)を紐づけました。
両者をクラスタにデプロイします。
$ kubectl apply -f backendconfig.yaml
$ kubectl apply -f service.yaml
アクセス確認
以上で構築は完了です。
ブラウザで 作成したIngress(LB)に対して、httpsでアクセスしてみます。設定がうまく行っていれば、GoogleのOAuth認証を挟んだあと、Podへのアクセスができるかと思います。
また、他のIPアドレスからアクセスすると「404」になることも確認できますし、Cloud IAPで許可したアカウント以外でアクセスしても弾かれることが確認できればOKです。
まとめ
今回、GCP + GKE (k8s)の機能を使って、Podへのアクセス認証とIPアドレス制限を実施しました。新しいWebアプリを追加したい場合には、
- WebアプリのPod のデプロイ
- Serviceの追加
- Ingressに2のServiceへのルーティングを追加
だけで、上記アクセス制限が再利用できるかと思います。
本格的な認証認可には及びませんが、この仕組であれば新しくWebアプリのPodを追加しても、最低限のアクセス制限をさくっと適用できるかと思います。
補足
ブラウザで「Error: redirect_uri_mismatch 」が表示される
OAuthでアクセスする場合に表示されることがあります。OAuthのリダイレクトURIがGoogle OAuthに登録されていないためで、表示される指示に従い、リダイレクト先URIを登録します。
リダレクトURIも登録先URLも画面に表示されますが、今回の例ではリダレクトURIは「https://「IPアドレス」.xip.io/_gcp_gatekeeper/authenticate」になります。
追加してしばらく経ったあとにアクセスすれば直ると思います。
Author And Source
この問題について(Cloud Armor + Cloud IAPでKubernetes Podへセキュアにアクセスする), 我々は、より多くの情報をここで見つけました https://qiita.com/soymsk/items/99548f0cd086dada69bf著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Content is automatically searched and collected through network algorithms . If there is a violation . Please contact us . We will adjust (correct author information ,or delete content ) as soon as possible .