はじめに
こんにちは。enechainのPlatform Engineering Deskで働いているsoma00333です。
enechainではproductのdeploy先としてGKEを採用しており、Platform Engineering DeskではKubernetes Clusterの運用業務を行っています。 enechainは「エネルギーの取引所を作る」というmissionを持っており、productも増えてきています。 Platform Engineering Deskも今後ますますsecurityに力を入れていく予定です。
前回は、Platform Engineering Deskのsecurityに関する取り組みの一例として、Pod Security Admissionを紹介しました。
今回は、引き続きsecurityに関する取り組みの一例としてNetworkPolicyを紹介します。
NetworkPolicyについて
概要
NetworkPolicyはPodに対してPod間の通信や外部のendpointへの通信を制御するためのResourceです。 NetworkPolicyを利用することで、不正アクセスや意図しない通信を防ぎ、Kubernetesクラスタ内のセキュリティを向上させることができます。
defaultではPodは分離されていない状態となるため、すべてのsourceからのtrafficを受信してしまいます。しかし、Podに対してNetworkPolicyを正しく設定すると、Podは意図しないすべての通信を拒否するようになります。
Podが通信できる対象は以下の3つの識別子の組み合わせによって識別されます。
- podSelector: 許可されている他のPod
- namespaceSelector: 許可されているNamespace
- ibBlock: IPブロック
以下に公式documentで紹介されているmanifestの例を記載します。
apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: test-network-policy namespace: default spec: podSelector: matchLabels: role: db policyTypes: - Ingress - Egress ingress: - from: - ipBlock: cidr: 172.17.0.0/16 except: - 172.17.1.0/24 - namespaceSelector: matchLabels: project: myproject - podSelector: matchLabels: role: frontend ports: - protocol: TCP port: 6379 egress: - to: - ipBlock: cidr: 10.0.0.0/24 ports: - protocol: TCP port: 5978
podSelectorについて
このfieldでNetworkPolicyを適用するPodを選択します。
podSelectorを空にすると、NetworkPolicyの属するNamespace上の全てのPodが対象となります。
Policyの例では、label "role=db"を持つPodを選択しています。
podSelector: matchLabels: role: db
policyTypesについて
このfieldでNetworkPolicyがIngress(選択したPodへの内向きのtraffic)のPolicyか、Egress(選択したPodからの外向きのtraffic)のPolicyか、または両方なのかを指定します。 policyTypesを指定しなかった場合、defaultで常に Ingressが指定され、NetworkPolicyにegress ruleが1つでもあればEgressも設定されます。
Policyの例では、IngressとEgressの両方を選択しています。
policyTypes: - Ingress - Egress
ingress / egressについて
設定項目は以下のとおりです。
設定項目 | 概要 |
---|---|
ingress | このfieldで、許可するingressのruleをlistで指定します。各ruleはfromとports sectionの両方に一致するtrafficを許可します。sourceの選択方法はipBlock、namespaceSelector、podSelectorの3つがあります。また、fromを省略したり空で指定した場合は全てのtrafficが対象となります。 |
egress | このfieldで、許可するegressのruleをlistで指定します。各ruleはtoとports sectionの両方に一致するtrafficを許可します。sourceの選択方法はipBlock、namespaceSelector、podSelectorの3つがあります。また、toを省略したり空で指定した場合は全てのtrafficが対象となります。 |
ipBlock | 特定のIPのCIDRの範囲を選択して、ingressの送信元またはegressの送信先を許可します。指定できるfieldは以下の通りです。1.cidr : CIDR表記でIP addressの範囲を指定 2.except : cidr で指定した範囲内から除外したい範囲をCIDRで指定 |
namespaceSelector | 特定のNamespaceを選択して、そのNamespace内のすべてのPodについて、ingressの送信元またはegressの送信先を許可します。このfieldが与えられたが空だった場合、全てのNamespaceが選択されます。 |
podSelector | NetworkPolicyと同じNamespace上の特定のPodを選択して、ingressの送信元またはegressの送信先を許可します。このfieldが与えられたが空だった場合、NetworkPolicyが属しているNamespaceの全てのPodが選択されます。 |
ports | このfieldで、許可するport番号をlistで指定します。このfieldを省略したり空で指定した場合は全てのportが対象となります。指定できるfieldは以下の通りです。1.port : port名か番号でportを指定 2.protocol : TCP / UDP / SCTP からprotocolを指定 |
Policyの例
以上より、Policyの例ではingressとegressに対して以下のような制御を行なっています
- ingress: TCPの6379番portへの接続かつ次の送信元からのものを許可する
- default Namespace内のlabel "role=frontend"が付いたすべてのPod
- label "project=myproject"が付いたNamespace内のすべてのPod
- 172.17.1.0/24の範囲を除く172.17.0.0/16の範囲内のすべてのIP address
- egress: TCPの5978番port上でのCIDR 10.0.0.0/24への接続を許可する
ingress: - from: - ipBlock: cidr: 172.17.0.0/16 except: - 172.17.1.0/24 - namespaceSelector: matchLabels: project: myproject - podSelector: matchLabels: role: frontend ports: - protocol: TCP port: 6379 egress: - to: - ipBlock: cidr: 10.0.0.0/24 ports: - protocol: TCP port: 5978
NetworkPolicyの設定
enechainで行っているNetworkPolicyの設定を紹介します。
前提
enechainではGKEのStandard Clusterを運用しており、network制御はDataplane V2を使用しています。Dataplane V2ではdefaultでNetworkPolicyの使用が可能です。 また、環境へのアクセスをWhitelistでIP制限しており、AWS Client VPNを利用して、アクセスしています
enechainではapplicationの標準構成としてfrontend, bff, backendの3構成を使用するよう標準化が進んでおり、backendやmicroserviceはinternalな通信を行います。
以下の図のような構成です。
Platform Engineeringに関する詳細はこちらのblogをご覧ください。
狙い
全体
基本的な構成としてingressを全て拒否かつegressを全て許可し、podごとにingressを設定する方針をとっています。
egressを全て許可している理由は以下です
- Ingressを絞るだけでも外部からの不正アクセスを防ぎ、セキュリティリスクを十分に軽減することができる
- 初期設定としてシンプルで扱いやすく、また必要に応じて後からegressを制限する方が初期段階での設定ミスのリスクが少なくなる
- egressを絞ると、必要な外部アクセスにアクセスできなくなるリスクがあり、運用上の障害や利便性の低下につながる
ただ、一部Security要件の高いものに関してはegressも絞っています。enechainのSecurity要件は日に日に高くなってきており、今後egressの明示的な管理も視野に入れています。
frontend
frontendのingressで明示的に許可しているのは以下の内容です
- GCLBのhealth checkのSource IP Range
- DatadogのService Discoveryを利用するためのDatadog用のNamespace
bff
bffのingressで明示的に許可しているのは以下の内容です
- GCLBのhealth checkのSource IP Range
backend
backendのingressで明示的に許可しているのは以下の内容です
- bffのpod
microservice
microserviceのingressで明示的に許可しているのは以下の内容です
- 通信対象のpod
- (通信対象のpodが存在するNamespace)
一部namespace selectorが使用されていますが、明示的なpod selectorでの管理へと移行予定です。
dev環境の設定
dev環境ではdebug時にlocal pcからアクセスできるように、ingressでいくつかのIP Rangeを許可しています
- Debug用のIP Address
- enechainのofficeのIP Range
- AWS Client VPNのIP Range
実装
実際の実装例を紹介します。
全て
全てのPodに対してIngressの拒否とegressの許可設定をします
kind: NetworkPolicy apiVersion: networking.k8s.io/v1 metadata: name: deny-all-networkpolicy spec: policyTypes: - Ingress - Egress podSelector: {} egress: - {}
frontend
frontendのnetwork policyは実際に以下の内容を設定しています。
apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: <service-name>-frontend spec: podSelector: matchLabels: app.kubernetes.io/name: <service-name>-frontend app.kubernetes.io/component: frontend app.kubernetes.io/part-of: <service-name> policyTypes: - Ingress ingress: - from: ### GCLBのhealth checkのSource IP Range - ipBlock: cidr: 35.191.0.0/16 # ingress probe - ipBlock: cidr: 130.211.0.0/22 # ingress probe ### DatadogのService Discoveryを利用するためのDatadog用のNamespace - namespaceSelector: matchLabels: kubernetes.io/metadata.name: <datadog-namespace> ports: - protocol: TCP port: xxxx
bff
bffのnetwork policyは実際に以下の内容を設定しています。
apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: <service-name>-bff spec: podSelector: matchLabels: app.kubernetes.io/name: <service-name>-bff app.kubernetes.io/component: bff app.kubernetes.io/part-of: <service-name> policyTypes: - Ingress ingress: - from: ### GCLBのhealth checkのSource IP Range - ipBlock: cidr: 35.191.0.0/16 # ingress probe - ipBlock: cidr: 130.211.0.0/22 # ingress probe ports: - protocol: TCP port: xxxx
backend
backendのnetwork policyは実際に以下の内容を設定しています。
apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: <service-name>-backend spec: podSelector: matchLabels: app.kubernetes.io/name: <service-name>-backend app.kubernetes.io/component: backend app.kubernetes.io/part-of: <service-name> policyTypes: - Ingress ingress: - from: ### bffのpod - podSelector: matchLabels: app.kubernetes.io/name: <service-name>-bff app.kubernetes.io/component: bff app.kubernetes.io/part-of: <service-name> ports: - protocol: TCP port: xxxx
microservice
microserviceのnetwork policyは実際に以下の内容を設定しています。
apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: <service-name> spec: podSelector: matchLabels: app.kubernetes.io/name: <service-name> app.kubernetes.io/component: microservice app.kubernetes.io/part-of: <service-name> policyTypes: - Ingress ingress: - from: ### 他のserviceのpod - podSelector: matchLabels: app.kubernetes.io/name: <other-service-name> app.kubernetes.io/component: <other-component-name> app.kubernetes.io/part-of: <other-service-name> ports: - protocol: TCP port: xxxx
課題と今後の取り組み
現状の課題と今後の取り組みについてまとめます。
ingress/egressの設定を見直す
ingress
以下のような課題があり、セキュリティ要件が高まるのに合わせて設定を見直す予定です。
- 一部設定でpod selectorではなくnamespace selectorを利用してしまっている
- 一部設定でCloud Nat用のIP Range(CI/CD用のGKE Clusterの存在するGCP ProjectのCloud NatのIP Range)を許可している
- productionの一部設定でDebug用のIP Addressを許可している
egress
基本的にはegressは全て許可しているため、productのsecurity要件に応じて明示的な管理が必要です。
OPA(Open Policy Agent)等でポリシーを強制する
現状ポリシー制御を行っているわけではないので、reviewプロセスの中でどうしても漏れが発生します。設定ミスを無くしたり、設定漏れをなくすためにも、OPAをはじめとしたポリシー制御の仕組みの導入を検討しています。
また、security要件の高いproductを中心に、監視体制を強化していく予定です。
おわりに
今回はsecurityに関する取り組みの一例としてNetworkPolicyについて紹介しました。 enechainのPlatform Engineering Deskは横軸engineeringを推進できる非常に魅力的な環境です。
enechainではPlatform Engineerはもちろん、一緒に事業・組織を盛り上げてくれるSWE/Designer/EMを募集しています。
興味を持っていただけたら、是非カジュアルにお話しましょう。カジュアル面談は以下のフォームからお申し込みいただけます。お待ちしております!
カジュアル面談 herp.careers
SREポジション herp.careers herp.careers