デフォルト拒否からL7まで積み上げる
目標
標準のNetworkPolicyで、デフォルト拒否とセレクターベースの許可を実際に適用してみて、CiliumNetworkPolicyでしかできないL7・FQDN・明示的な拒否をマニフェストとして作成します。
なぜ重要なのか
ネットワークポリシーは、applyが成功したからといって、意図どおりに動作する保証はありません。特に次の3つが、静かに人をだまします。
1つ目は、方向ごとの独立です。ingressポリシーだけをかけて「隔離した」と思っていると、egressは依然としてインターネット全体に開いたままです。データ流出の経路は、ほとんどがegress側です。
2つ目は、セレクターのタイプミスはエラーにならず、「何も選択しない」という形で静かに失敗することです。適用後に、実際にいくつのエンドポイントが強制状態になっているかを確認する必要があります。
3つ目は、toFQDNsはDNSルールなしでは永遠にマッチしないことです。これはCiliumポリシーで最もよくある設定ミスであり、試験にも繰り返し出題されます。
標準のNetworkPolicyは実際にapplyし、CiliumNetworkPolicyは/root/cca-policy/の下にファイルとして作成します。ラボのクラスターにCilium CRDがインストールされていないためで、試験で求められる能力も、マニフェストを正確に書くことです。
ステップ
- ネームスペース
cca-shopとcca-monを作成し、cca-monにはラベルtier=monitoringを付けてください。 - ネームスペース
cca-shopに、Deploymentfrontendとbackendを、それぞれレプリカ1でデプロイしてください。Podのラベルはそれぞれapp=frontend、app=backendで、イメージはnginx:1.27-alpineです。そして、Servicebackendをポート8080で作成してください。 - ネームスペース
cca-shopにNetworkPolicydefault-denyを作成してください。podSelectorは空で、policyTypesにはIngressとEgressの両方を書き、許可ルールは1つも置きません。 - 同じネームスペースにNetworkPolicy
allow-frontend-to-backendを作成してください。podSelectorはapp=backend、policyTypesはIngressのみ、ingressルールは、podSelectorがapp=frontendである送信元からの、ポート8080/ プロトコルTCPだけを許可します。 - 同じネームスペースにNetworkPolicy
allow-monitoringを作成してください。podSelectorはapp=backendで、ingressルールのfrom項目は、namespaceSelectorでtier=monitoringであるネームスペース1つだけを置き、ポートは9090です。 /root/cca-policy/cnp-l7.yamlにCiliumNetworkPolicyを作成してください。apiVersionはcilium.io/v2、metadata.namespaceはcca-shop、endpointSelectorはapp: backendです。ingressルールは、fromEndpointsがapp: frontendで、toPortsのポート8080/TCPの下のrules.httpに2つの項目を置きます。1つ目はmethodGET/ path/api/v1/orders、2つ目はmethodPOST/ path/api/v1/ordersです。/root/cca-policy/cnp-fqdn.yamlにCiliumNetworkPolicyを作成してください。endpointSelectorはapp: frontendで、egressルールはちょうど2つです。1つ目は、toEndpointsがk8s-app: kube-dnsである宛先にポート53/UDPを開き、rules.dnsにmatchPattern: "*"を置きます。2つ目は、toFQDNsのmatchNameがapi.pgprovider.exampleで、ポート443/TCPを開きます。/root/cca-policy/cnp-deny.yamlに、名前がblock-metadataのCiliumNetworkPolicyを作成してください。endpointSelectorは空で、egressルールにtoCIDRSetでcidr: 0.0.0.0/0を許可しつつ、exceptに169.254.169.254/32を置き、さらにegressDenyのtoCIDRにも169.254.169.254/32を明示してください。
参考
kubectl get netpol -n cca-shop -o yamlで適用結果を読み直し、意図と合っているかを確認してください。- CiliumNetworkPolicyのポートは、文字列で書くのが慣例です。
port: "8080"の形です。 - よくある間違い1: デフォルト拒否の
policyTypesに、片方の方向だけを書くこと。反対の方向はそのまま開いています。 - よくある間違い2:
fromEndpoints: []とfromEndpoints: [{}]を混同すること。前者は何も許可せず、後者は同じネームスペース全体を許可します。 - よくある間違い3: toFQDNsだけを書いて、DNSルールを抜かすこと。プロキシが応答を学習できなければ、その名前は永遠にマッチしません。
アプリケーション用とモニタリング用のネームスペースを作成する
ネームスペースcca-shopとcca-monを作成し、cca-monにはラベルtier=monitoringを付けてください。
namespaceSelectorは、ネームスペースのラベルしか見られません。名前では選べないので、ラベルをあらかじめ付けておいてください。
フロントエンドとバックエンドをデプロイする
ネームスペースcca-shopに、Deployment frontendとbackendを、それぞれレプリカ1でデプロイしてください。Podのラベルはそれぞれapp=frontend、app=backendで、イメージはnginx:1.27-alpineです。そして、Service backendをポート8080で作成してください。
ポリシーはラベルで対象を選びます。Podテンプレートのappラベルが正確であってこそ、後のステップがすべて噛み合います。
双方向のデフォルト拒否を作成する
ネームスペースcca-shopにNetworkPolicy default-denyを作成してください。podSelectorは空で、policyTypesにはIngressとEgressの両方を書き、許可ルールは1つも置きません。
方向は互いに独立しています。片方だけを書くと、反対の方向は依然としてすべて開いたままです。許可ルールは1つも入れないでください。
Podセレクターで1つの経路だけを開く
同じネームスペースにNetworkPolicy allow-frontend-to-backendを作成してください。podSelectorはapp=backend、policyTypesはIngressのみ、ingressルールは、podSelectorがapp=frontendである送信元からの、ポート8080 / プロトコルTCPだけを許可します。
ポリシーのpodSelectorはトラフィックを受ける側を選び、fromのpodSelectorは送る側を選びます。このステップでは同じネームスペースの中だけを許可するので、namespaceSelectorは一緒に置かないでください。
ネームスペースセレクターで別のネームスペースを開く
同じネームスペースにNetworkPolicy allow-monitoringを作成してください。podSelectorはapp=backendで、ingressルールのfrom項目は、namespaceSelectorでtier=monitoringであるネームスペース1つだけを置き、ポートは9090です。
ステップ1で付けたネームスペースのラベルを使います。開くべきポートは、アプリケーションのポートではなく、メトリクスのポートです。
HTTPメソッドとパスで制限する
/root/cca-policy/cnp-l7.yamlにCiliumNetworkPolicyを作成してください。apiVersionはcilium.io/v2、metadata.namespaceはcca-shop、endpointSelectorはapp: backendです。ingressルールは、fromEndpointsがapp: frontendで、toPortsのポート8080/TCPの下のrules.httpに2つの項目を置きます。1つ目はmethod GET / path /api/v1/orders、2つ目はmethod POST / path /api/v1/ordersです。
標準のNetworkPolicyでは不可能な領域です。toPortsの下にrules.httpを置き、メソッドとパスを列挙してください。マッチしないリクエストは、遮断ではなく403で返ってきます。
ドメイン名で外部APIを許可する
/root/cca-policy/cnp-fqdn.yamlにCiliumNetworkPolicyを作成してください。endpointSelectorはapp: frontendで、egressルールはちょうど2つです。1つ目は、toEndpointsがk8s-app: kube-dnsである宛先にポート53/UDPを開き、rules.dnsにmatchPattern: "*"を置きます。2つ目は、toFQDNsのmatchNameがapi.pgprovider.exampleで、ポート443/TCPを開きます。
toFQDNsだけを書いても、決して動作しません。DNSプロキシが応答を学習することでIPが登録されるので、DNSクエリを許可して観察の対象にするルールが、必ず対になっている必要があります。
メタデータエンドポイントを封じる
/root/cca-policy/cnp-deny.yamlに、名前がblock-metadataのCiliumNetworkPolicyを作成してください。endpointSelectorは空で、egressルールにtoCIDRSetでcidr: 0.0.0.0/0を許可しつつ、exceptに169.254.169.254/32を置き、さらにegressDenyのtoCIDRにも169.254.169.254/32を明示してください。
許可ルールに例外を設ける方法と、明示的な拒否をもう一重敷く方法の、両方を使います。denyはallowに勝つので、2つの層が互いに矛盾することはありません。