0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

CilinumNetwokPolicy をしっかりと理解する

Last updated at Posted at 2024-12-10

目的

  • CilinumNetworkPolicy(以下、CNP) 設定方法をしっかりと理解する
  • 一部の CNI ネットワークプロバイダーでサポート可能な NetworkPolicy との違いを理解する
  • L7 設定時の認証要求設定を理解する(required?)

手段

マニュアルベースで手を動かしていきます。

ざっくり理解する

スライド1.JPG
スライド2.JPG
スライド3.JPG
スライド4.JPG

killercoda の Playgroud を活用。

概要を理解する

前提として、k8s 環境で下記 NetworkPolicy を利用できる。

  1. Kubernetes NetworkPolicy
  2. CNP <--- 今回の学習範囲
  3. CiliumClusterwideNetworkPolicy <--- "2" の派生形だと推測。(Namespaceを指定しないタイプの CNP とのこと)

k8s 環境は cilium をサポートしていれば、CNP は全ての node に対して配布及び適用される。(厳密には、CNP の設定方法に依存するようです(ex: CLI, API 経由、等々..)

CNP はポリシー適用の設定が存在する。いわゆる、WAF の検知モード、ブロッキング、のように、設定したポリシーの適用レベルを制御できる。

  • default:
    • policy enforcement のデフォルト設定。このモードでは、全ての ingress/egress トラフィックは許可される。ポリシーに該当するトラフィックは default-deny 状態に遷移する。つまり、明示的にポリシーで許可された通信のみが成功する。言い換えると、policy enforcement がデフォルト設定の場合、CNP ポリシーが無ければ、全ての通信が許可される。逆に特定エンドポイントと通信の方向(ingress or egress)で特定された通信はdefault-deny に遷移する。
  • always:
    • 全てのエンドポイントに対してポリシーは有効化/適用される設定。
  • never:
    • ポリシー設定自体を無効にする。全てのエンドポイントに対して設定したポリシーは適用されない設定。言い換えると、CNP を disable にした状態。全ての ingress/egress 通信は許可される。
EnableDefaultDeny.yaml
apiVersion: cilium.io/v2
kind: CiliumClusterwideNetworkPolicy # CNPを指定
metadata:
  name: intercept-all-dns
spec:
  endpointSelector: # endpointSelector で本ポリシー適用対象を指定。nodeSelector 設定も存在する
                    # nodeSelector は CiliumClusterwideNetworkPolicy でのみ利用可能
                    # 基本的に Namespace, Pod  に紐づく label で適用対象を指定
    matchExpressions:                       # matchExpressions で条件を指定可能
      - key: "io.kubernetes.pod.namespace"
        operator: "NotIn"                   # NotIn なので、key に対して value が含まれない、ことが条件
        values:
        - "kube-system"
      - key: "k8s-app"
        operator: "NotIn"
        values:
        - kube-dns
  enableDefaultDeny: # ここが DefaultDeny 設定を制御する設定項目
    egress: false    # この egress 及び ingress を false にすれば、default mode が適用されない(無視される)
    ingress: false
  egress:              # egress や ingress を指定して、どの方向のトラフィックを制御するのか指定する
    - toEndpoints:     # ここでは、to Endpionts で指定したアウトバウンド通信が適用対象となる
        - matchLabels: # 下記 label を有する Pod が適用対象
            io.kubernetes.pod.namespace: kube-system
            k8s-app: kube-dns
      toPorts: # ポートとプロトコルを指定
        - ports:
          - port: "53"
            protocol: TCP
          - port: "53"
            protocol: UDP
          rules:
            dns:
              - matchPattern: "*"

CiliumNetworkPolicy(以下、CNP) は下記設定を実現可能です。

  • 特定通信に対する allow 及び deny
  • 条件は L3/L4/L7 レイヤーで指定可能
    • L7 レイヤーは認証必須として設定可能

基本的な設定内容は CNP を適用する対象 Namespace or Pod(いずれも labelで指定)を指定する。まずは、基本的な設定項目を確認します。

L3 サンプル

L3 ポリシーは下記条件で指定可能です。

  • Endpoints Based: ポリシー内にアドレスのような固定値を含めない
  • Services Based: こちらもポリシー内にアドレスのハードコードを防げる。また、Servcie オブジェクトが IP アドレスを隠蔽してくれる
  • Entities Based: ローカルホストや外部の到達可能なエンドポイントが含まれる
  • NodeBased: remote-node エンティティの拡張版。node単位で設定したいときに使うようだ
  • IP/CIDR Based: いわゆる、192.168.1.1/32, 192.168.1.0/24 で設定する形式
  • DNS Based: DNS lookup で解決可能なエンティティを指定可能
SimpleIngressAllow.yaml
apiVersion: "cilium.io/v2"
kind: CiliumNetworkPolicy
metadata:
  name: "l3-rule"
spec:
  endpointSelector: # "role: backend " label を有する Pod が適用対象
    matchLabels:
      role: backend
  ingress:          # "role: backend " label を有するインバウンド通信が適用対象
  - fromEndpoints:  # つまり、"role: backend " label を有する Podに対する、
    - matchLabels:  # "role: backend " label を有する Pod からのインバウンド通信が許可される
        role: frontend
IngressAllowAllEndpoints.yaml
apiVersion: "cilium.io/v2"
kind: CiliumNetworkPolicy
metadata:
  name: "allow-all-to-victim"
spec:
  endpointSelector: # "role: victim" label を有する pod が対象
      matchLabels:
      role: victim
  ingress:
  - fromEndpoints: # fromEndPoints をブランク {} 指定で全ての Pod が対象になる
    - {}           # つまり、全 Pod から "role: victim" label を有する pod への通信が許可される

注意として、ポリシーはあくまで sender(egress) と recevier(ingress) の両方の設定で許可された通信でないと成功しない。上記設定のように、recevier のみの設定だけでは不十分で、sender の設定が存在しないと通信は成立しない。管理面で考えると、ingressとegressを併記した方が分かり易そうに思う。

SimpleEgressAllow.yaml
apiVersion: "cilium.io/v2"
kind: CiliumNetworkPolicy
metadata:
  name: "l3-egress-rule"
spec:
  endpointSelector: # "role: frontend" を有する Pod から "role: backend" を有する Pod へのアウトバウンド通信を許可
    matchLabels:    # 通信成功には受け側の igress ポリシーが必要
      role: frontend
  egress:
  - toEndpoints:
    - matchLabels:
        role: backend
Ingress-EgressDefaultDeny.yaml
apiVersion: "cilium.io/v2"
kind: CiliumNetworkPolicy
metadata:
  name: "deny-all-egress"
spec:
  endpointSelector: # 当該ポリシー以外にポリシーが存在しなければ、
    matchLabels:    # "role: restricted" を有する Pod の Ingress 及び Egress を default-deny にできる?
      role: restricted
  egress:
  - {}
AdditionalLabelRequirements.yaml
apiVersion: "cilium.io/v2"
kind: CiliumNetworkPolicy
metadata:
  name: "requires-rule"
specs:
  - description: "For endpoints with env=prod, only allow if source also has label env=prod"
    endpointSelector:
      matchLabels:
        env: prod
    ingress:
    - fromRequires:  # fromRequires は到達可能な基本要件を指定する
      - matchLabels: # "env: prod" label を有する Pod から "env: prod" label を有するエンドポイント 
          env: prod  # に通信可能

上記ポリシーだけでは通信を許可するポリシーとして成立しない。
下記ポリシーを組み合わせれば、通信を許可するポリシーとして成立する。

fromRequires.yaml
apiVersion: "cilium.io/v2"
kind: CiliumNetworkPolicy
metadata:
  name: "l3-rule"
specs:
  - description: "For endpoints with env=prod, allow if source also has label role=frontend"
    endpointSelector:  # 上記ポリシーと合わせると、"env: prod" に対するインバウンド通信は、
      matchLabels:     # "role: frontend" 及び "env: prod" を有するエンドポイントから許可される
        env: prod
    ingress:
    - fromEndpoints:
      - matchLabels:
          role: frontend

ここからはやってみようのコーナー!!

テスト環境は以下の通り。各 Namespace に nginx を1つ起動する。

  • namespace
    • dev
    • stg
dev.yaml
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Namespace
metadata:
  creationTimestamp: null
  name: dev
spec: {}
status: {}
EOF
stg.yaml
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Namespace
metadata:
  creationTimestamp: null
  name: stg
spec: {}
status: {}
EOF
  • pod * 2
    • type: source
    • type: dest
source.yaml
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
  creationTimestamp: null
  labels:
    type: source
  name: source
  namespace: dev
spec:
  containers:
  - image: nginx
    name: source
    resources: {}
  dnsPolicy: ClusterFirst
  restartPolicy: Always
status: {}
EOF
dest.yaml
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
  creationTimestamp: null
  labels:
    type: dest
  name: dest
  namespace: stg
spec:
  containers:
  - image: nginx
    name: dest
    resources: {}
  dnsPolicy: ClusterFirst
  restartPolicy: Always
status: {}
EOF

Pod 状態を確認する。

controlplane $ k get po -n dev -n stg
NAME     READY   STATUS    RESTARTS   AGE
dest     1/1     Running   0          12s
source   1/1     Running   0          45s

続いて、CNPを作成する。

fromRequires.yaml
cat <<EOF | kubectl apply -f -
apiVersion: "cilium.io/v2"
kind: CiliumNetworkPolicy
metadata:
  name: "requires-rule"
specs:
  - description: "For endpoints with env=prod, only allow if source also has label env=prod"
    endpointSelector:
      matchLabels:
        type: dest
    ingress:
    - fromRequires:
      - matchLabels:
          type: source 
EOF
controlplane $ k apply -f fromRequires.yaml 
ciliumnetworkpolicy.cilium.io/requires-rule created
controlplane $ k describe cnp requires-rule 
Name:         requires-rule
Namespace:    default # CNP に対して namespace 指定していないため、default
Labels:       <none>  # default だと dev,stg namespace に適用されないのでは?
Annotations:  <none>
API Version:  cilium.io/v2
Kind:         CiliumNetworkPolicy
Metadata:
  Creation Timestamp:  2024-12-03T09:41:52Z
  Generation:          1
  Resource Version:    4174
  UID:                 35d81c5a-0eec-4f22-ac59-e9fa43cfcb45
Specs:
  Description:  For endpoints with env=prod, only allow if source also has label env=prod
  Endpoint Selector:
    Match Labels:
      Type:  dest
  Ingress:
    From Requires:
      Match Labels:
        Type:  source
Status:
  Conditions:
    Last Transition Time:  2024-12-03T09:41:52Z
    Message:               Policy validation succeeded
    Status:                True
    Type:                  Valid
Events:                    <none>

続いて Pod の IP アドレスを確認する。

controlplane $ k get po -A -o wide |grep -E 'dev|stg'
dev                  source                                    1/1     Running   0             84s   192.168.0.40    controlplane   <none>           <none>
stg                  dest                                      1/1     Running   0             15m   192.168.0.113   controlplane   <none>           <none>
controlplane $ k exec -it -n dev source -- curl --HEAD http://192.168.0.113
HTTP/1.1 200 OK # sorce pod から dest pod の curl に成功

二つ目の CNP を設定する。

controlplane $ k apply -f fromRequires2.yaml 
ciliumnetworkpolicy.cilium.io/l3-rule created
controlplane $ k describe cnp l3-rule 
Name:         l3-rule
Namespace:    default # こちらの CNP も namesapce 指定無し
Labels:       <none>
Annotations:  <none>
API Version:  cilium.io/v2
Kind:         CiliumNetworkPolicy
Metadata:
  Creation Timestamp:  2024-12-03T09:50:58Z
  Generation:          1
  Resource Version:    5155
  UID:                 8a502978-d47c-4774-9fde-b7109beffca3
Specs:
  Description:  For endpoints with env=prod, allow if source also has label role=frontend
  Endpoint Selector:
    Match Labels:
      Type:  dest
  Ingress:
    From Endpoints:
      Match Labels:
        Role:  nginx
Status:
  Conditions:
    Last Transition Time:  2024-12-03T09:50:58Z
    Message:               Policy validation succeeded
    Status:                True
    Type:                  Valid
Events:                    <none>

sorce nginx に labels を追加する。

controlplane $ kubectl -n dev label pods source role=nginx
pod/source labeled
controlplane $ k get po -A -o wide --show-labels |grep -E 'dev|stg'        
dev                  source                                    1/1     Running   0             3m53s   192.168.0.40    controlplane   <none>           <none>            role=nginx,type=source
stg                  dest                                      1/1     Running   0             18m     192.168.0.113   controlplane   <none>           <none>            type=dest

source -> dest への curl は成功する。CNP は動作していない。
正確には、namespace は default なので、default 所属の pod に適用されるポリシーとなる。

controlplane $ k exec -it -n dev source -- curl --HEAD http://192.168.0.113
HTTP/1.1 200 OK

CNP の namespace を dev に変更する。

controlplane $ k edit cnp requires-rule
controlplane $ k replace -f /tmp/kubectl-edit-4148436964.yaml --force
controlplane $ k edit cnp l3-rule 
controlplane $ k replace -f /tmp/kubectl-edit-2320713019.yaml --force

controlplane $ k describe -n dev cnp requires-rule |grep -i namespace
Namespace:    dev
controlplane $ k describe -n dev cnp l3-rule |grep -i namespace
Namespace:    dev

正しい結果が得られていない。全 CNP を削除して、一つずつ確認する。

controlplane $ k describe -n stg cnp l3-allow 
Name:         l3-allow
Namespace:    stg # stg に適用する
Labels:       <none>
Annotations:  <none>
API Version:  cilium.io/v2
Kind:         CiliumNetworkPolicy
Metadata:
  Creation Timestamp:  2024-12-03T10:16:40Z
  Generation:          1
  Resource Version:    7959
  UID:                 9e48c541-744c-472f-8f6c-8e0b35b1e06e
Spec:
  Endpoint Selector:
    Match Labels:
      Type:  dest
  Ingress:
    From Endpoints:
      Match Labels:
        Type:  source # なぜ Type の T は大文字なのか?
Status:
  Conditions:
    Last Transition Time:  2024-12-03T10:16:40Z
    Message:               Policy validation succeeded
    Status:                True
    Type:                  Valid
Events:                    <none>

controlplane $ k exec -it -n dev source -- curl --HEAD -m 2 http://192.168.0.113
curl: (28) Connection timed out after 2000 milliseconds
command terminated with exit code 28 

# curl に失敗する。

controlplane $ k get po -A -o wide --show-labels |grep -E 'dev|stg'
dev                  source                                    1/1     Running   0             26m   192.168.0.40    controlplane   <none>           <none>            type=source
stg                  dest                                      1/1     Running   0             40m   192.168.0.113   controlplane   <none>           <none>            type=dest

# label は正しいように見える。

controlplane $ k get po -A -o wide --show-labels |grep -E 'dev|stg'
dev                  source                                    1/1     Running   0             28m   192.168.0.40    controlplane   <none>           <none>            Type=source,type=source
stg                  dest                                      1/1     Running   0             43m   192.168.0.113   controlplane   <none>           <none>            Type=dest,type=dest
controlplane $ k exec -it -n dev source -- curl --HEAD -m 2 http://192.168.0.113
curl: (28) Connection timed out after 2001 milliseconds
command terminated with exit code 28

# 大文字の Type=source タグを付与しても curl は失敗。
# 何か根本的に違う気がする。CNP 設定を見直す。

これは receiver のポリシーとなる。通信を許可するには sender のポリシーが必要となる。

apiVersion: "cilium.io/v2"
kind: CiliumNetworkPolicy
metadata:
  name: "l3-allow"
  namespace: stg
spec:
  endpointSelector:
    matchLabels:
      type: dest
  ingress:
  - fromEndpoints:
    - matchLabels:
        type: source
controlplane $ k exec -it -n dev source -- curl --HEAD -m 2 http://192.168.0.80
curl: (28) Connection timed out after 2001 milliseconds

ここまで receiver 及び sender の CNP を作成すれば良いと理解していました。しかし、正しく理解できていないようです。
Killercoda のシナリオを紐解いて理解を深める方針に切り替えます。

policy1.yaml
cat <<EOF | kubectl apply -f -
apiVersion: "cilium.io/v2"
kind: CiliumNetworkPolicy
metadata:
  name: policy1
  namespace: app
spec:
  endpointSelector:
    matchLabels: {}
  egress:
  - toEndpoints:
    - matchLabels:
        io.kubernetes.pod.namespace: data
        id: data
EOF

# CNP 作成

controlplane $ k get po -A -o wide --show-labels|grep -E 'id=app|id=data|id=manager'
app                  app1                                      1/1     Running   0             12m   192.168.0.206   controlplane   <none>           <none>            id=app
app                  app2                                      1/1     Running   0             12m   192.168.0.82    controlplane   <none>           <none>            id=app
app                  manager1                                  1/1     Running   0             12m   192.168.0.153   controlplane   <none>           <none>            id=manager
app                  manager2                                  1/1     Running   0             12m   192.168.0.87    controlplane   <none>           <none>            id=manager
data                 data-001                                  1/1     Running   0             12m   192.168.0.172   controlplane   <none>           <none>            id=data
data                 data-002                                  1/1     Running   0             12m   192.168.0.241   controlplane   <none>           <none>            id=data
# POD IP 確認

controlplane $ k -n app exec app1 -- curl --head 192.168.0.172
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
  0   615    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0
HTTP/1.1 200 OK
# data namespace 宛は成功

controlplane $ k -n app exec app1 -- curl --head -m 2 192.168.0.153
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
  0     0    0     0    0     0      0      0 --:--:--  0:00:02 --:--:--     0
curl: (28) Connection timed out after 2001 milliseconds
command terminated with exit code 28
# data namespace 宛は許可していない。CNP の namespace を default に変更してみる。

controlplane $ k describe cnp policy1 |grep -i namespace
Namespace:    default
# CNP の namespace を app -> default に変更

controlplane $ k -n app exec app1 -- curl --head 192.168.0.172
HTTP/1.1 200 OK
# data namespace 宛は成功

controlplane $ k -n app exec app1 -- curl --head -m 2 192.168.0.153
HTTP/1.1 200 OK
# manager namespace 宛は成功
# つまり、上記 CURL リクエストは CNP 対象ではない。namespace は spec.endpointSelector に
# 指定する対象が所属する namespace を指定するのか?

続いて、CNP の namespace を送信先(namespace: manager)に変更してみる。

controlplane $ k describe -n data cnp policy1 |grep -i namespace
Namespace:    data
# CNP の namespace を defatul -> data に変更

controlplane $  k -n app exec app1 -- curl --head 192.168.0.172
HTTP/1.1 200 OK
# data namespace 宛は成功

controlplane $ k -n app exec app1 -- curl --head -m 2 192.168.0.153
HTTP/1.1 200 OK
# manager namespace 宛は成功
# つまり、上記 CURL リクエストは CNP 対象ではない。

上記結果から、CNP が所属する namespace と CNP 適用対象のエンドポイント(pod等)は一致する必要がある。あと、receiver と sender の概念が理解できていない。片側の policy で動作してると思うんですが...振り返ると、policy enforcement のデフォルト設定は当該通信に該当するポリシーが存在しない場合、default-allow なので、今回のケースもsenderはdefault-allowであるため、通信が成功すると推測。

仕切り直して、namespace * 3で検証する。

  • namespace
    • dev
    • stg
    • prod
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Namespace
metadata:
  creationTimestamp: null
  name: dev
spec: {}
status: {}
EOF

cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Namespace
metadata:
  creationTimestamp: null
  name: stg
spec: {}
status: {}
EOF

cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Namespace
metadata:
  creationTimestamp: null
  name: prod
spec: {}
status: {}
EOF
  • pod * 3
    • type: source
    • type: dest
    • type: manager
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
  creationTimestamp: null
  labels:
    type: source
  name: source
  namespace: dev
spec:
  containers:
  - image: nginx
    name: source
    resources: {}
  dnsPolicy: ClusterFirst
  restartPolicy: Always
status: {}
EOF

cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
  creationTimestamp: null
  labels:
    type: dest
  name: dest
  namespace: stg
spec:
  containers:
  - image: nginx
    name: dest
    resources: {}
  dnsPolicy: ClusterFirst
  restartPolicy: Always
status: {}
EOF

cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
  creationTimestamp: null
  labels:
    type: manager
  name: manager
  namespace: prod
spec:
  containers:
  - image: nginx
    name: manager
    resources: {}
  dnsPolicy: ClusterFirst
  restartPolicy: Always
status: {}
EOF

controlplane $ k get po -A -o wide --show-labels | grep -E 'dev|stg|prod'
dev                  source                                    1/1     Running   0             2m     192.168.0.108   controlplane   <none>           <none>            type=source
prod                 manager                                   1/1     Running   0             67s    192.168.0.152   controlplane   <none>           <none>            type=manager
stg                  dest                                      1/1     Running   0             104s   192.168.0.37    controlplane   <none>           <none>            type=dest
# POD IP 確認

controlplane $ k exec -n dev source -- curl --head 192.168.0.37
HTTP/1.1 200

controlplane $ k exec -n dev source -- curl --head 192.168.0.152
 HTTP/1.1 200 OK 
# dev から stg 及び prod に curl 成功

cat <<EOF | kubectl apply -f -
apiVersion: "cilium.io/v2"
kind: CiliumNetworkPolicy
metadata:
  name: policy1
  namespace: dev
spec:
  endpointSelector:
    matchLabels: {}
  egress:
  - toEndpoints:
    - matchLabels:
        io/metadata.name: stg
        type: dest
EOF
# CNP 作成

k exec -n dev source -- curl --head -m 2 192.168.0.37
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
  0     0    0     0    0     0      0      0 --:--:--  0:00:02 --:--:--     0
curl: (28) Connection timed out after 2001 milliseconds
command terminated with exit code 28

k exec -n dev source -- curl --head -m 2 192.168.0.152
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
  0     0    0     0    0     0      0      0 --:--:--  0:00:02 --:--:--     0
curl: (28) Connection timed out after 2001 milliseconds
command terminated with exit code 28
# 両方とも失敗する

controlplane $ k get  -n dev cnp policy1 -oyaml
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
  annotations:
    kubectl.kubernetes.io/last-applied-configuration: |
      {"apiVersion":"cilium.io/v2","kind":"CiliumNetworkPolicy","metadata":{"annotations":{},"name":"policy1","namespace":"dev"},"spec":{"egress":[{"toEndpoints":[{"matchLabels":{"io/metadata.name":"stg","type":"dest"}}]}],"endpointSelector":{"matchLabels":{}}}}
  creationTimestamp: "2024-12-04T10:25:30Z"
  generation: 3
  name: policy1
  namespace: dev
  resourceVersion: "8185"
  uid: 3bd86930-7ea5-4d6e-b053-ebaf9c46b93f
spec:
  egress:
  - toEndpoints:
    - matchLabels:
        io.kubernetes.pod.namespace: stg # この labels を追加すると通信は成功する
        type: dest                       # この label 名はどのように可能可能か?
  endpointSelector:
    matchLabels: {}

k exec -n dev source -- curl --head -m 2 192.168.0.37
HTTP/1.1 200 OK

k exec -n dev source -- curl --head -m 2 192.168.0.152
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
  0     0    0     0    0     0      0      0 --:--:--  0:00:02 --:--:--     0
curl: (28) Connection timed out after 2000 milliseconds
# CNP は正しく動作している

"io.kubernetes.pod.namespace: stg" の確認方法は?

ここで議論されている。
マニュアルにも説明が存在する。
取り合えず、マニュアルを読んでみる。

ここのサンプルはとても分かり易い。
つまり、CNP において、namespace 単位で制限を掛けたい場合、"io.kubernetes.pod.namespace: stg" の記述方法がお作法となる。マニュアルに利用可能な label 一覧があるため、そちらを参照すると理解が深まると思います。

L4 サンプル

L4 レイヤポリシーは L3 ポリシーに追加可能、独立して設定も可能です。(注意:L4ポリシーが存在しない場合、ICMP を含むすべてのポートは許可される。)

Example(l4).yaml
apiVersion: "cilium.io/v2"
kind: CiliumNetworkPolicy
metadata:
  name: "l4-rule"
spec:
  endpointSelector: # 適用対象は "app: myService" を有するエンドポイント
    matchLabels:
      app: myService
  egress:
    - toPorts: # TCP かつ 80でアウトバウンド通信
      - ports:
        - port: "80"
          protocol: TCP
ExamplePortRanges.yaml
apiVersion: "cilium.io/v2"
kind: CiliumNetworkPolicy
metadata:
  name: "l4-port-range-rule"
spec:
  endpointSelector:
    matchLabels:
      app: myService
  egress:
    - toPorts:
      - ports:
        - port: "80" # 対象は TCP 80~444 ポートのアウトバウンド通信
          endPort: 444
          protocol: TCP

CIDR-dependentLayer4Rule.yaml
apiVersion: "cilium.io/v2"
kind: CiliumNetworkPolicy
metadata:
  name: "cidr-l4-rule"
spec:
  endpointSelector: # 対象は "role: crawler" を有するエンドポイント
    matchLabels:
      role: crawler
  egress: # 対象は、アウトバウンド通信、192.0.2.0/24 宛、TCP:80ポート通信
  - toCIDR:
    - 192.0.2.0/24
    toPorts:
    - ports:
      - port: "80"
        protocol: TCP
Example(ICMP/ICMPv6).yaml
apiVersion: "cilium.io/v2"
kind: CiliumNetworkPolicy
metadata:
  name: "icmp-rule"
spec:
  endpointSelector: # 対象は "app: myService" を有するエンドポイント
    matchLabels:
      app: myService
  egress: # アウトバウンド通信
  - icmps:
    - fields: 
      - type: 8 # IPv4 の type 8 
        family: IPv4
      - type: EchoRequest # IPv6 の EchoRequest
        family: IPv6

検証環境で 80 版を Deny する。

controlplane $  k get po -A -o wide --show-labels | grep -E 'dev|stg|prod'
dev                  source                                    1/1     Running   0             27s     192.168.0.141   controlplane   <none>           <none>            type=source
prod                 manager                                   1/1     Running   0             27s     192.168.0.106   controlplane   <none>           <none>            type=manager
stg                  dest                                      1/1     Running   0             27s     192.168.0.102   controlplane   <none>           <none>            type=dest
controlplane $ 
controlplane $ k exec -n dev source -- curl --head 192.168.0.106
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
 HTTP/1.1 200 OK   0    0     0      0      0 --:--:-- --:--:-- --:--:--     0
 # dev -> prod への 80ポートは成功

CNP を作成する。

cidr-l4-rule.yaml
cat <<EOF | kubectl apply -f -
apiVersion: "cilium.io/v2"
kind: CiliumNetworkPolicy
metadata:
  name: "cidr-l4-rule"
  namespace: dev
spec:
  endpointSelector: # 対象は "role: crawler" を有するエンドポイント
    matchLabels:
      type: source
      io.kubernetes.pod.namespace: dev
  egress: # 対象は、アウトバウンド通信、192.0.2.0/24 宛、TCP:80ポート通信
  - toCIDR:
    - 192.168.0.106/32
    toPorts:
    - ports:
      - port: "80"
        protocol: TCP
EOF

k exec -n dev source -- curl --head -m2 192.168.0.106
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
  0     0    0     0    0     0      0      0 --:--:--  0:00:02 --:--:--     0
curl: (28) Connection timed out after 2001 milliseconds
command terminated with exit code 28
# 192.168.0.106 宛は失敗する

CNP内容を変更してみる。

cat <<EOF | kubectl apply -f -
apiVersion: "cilium.io/v2"
kind: CiliumNetworkPolicy
metadata:
  name: "cidr-l4-rule"
  namespace: dev
spec:
  endpointSelector: # 対象は "role: crawler" を有するエンドポイント
    matchLabels:
      type: source
      io.kubernetes.pod.namespace: dev
  egress: # 対象は、アウトバウンド通信、192.0.2.0/24 宛、TCP:80ポート通信
  - toPorts:
    - ports:
      - port: "80"
        protocol: TCP
EOF

controlplane $ k exec -n dev source -- curl --head 192.168.0.106
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
  0   615    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0
HTTP/1.1 200 OK

controlplane $ k exec -n dev source -- curl --head 192.168.0.102
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
  0   615    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0
HTTP/1.1 200 OK
# 80 は allow

controlplane $ k exec -n dev source -- curl --head -m2 https://192.168.0.106
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
  0     0    0     0    0     0      0      0 --:--:--  0:00:02 --:--:--     0
curl: (28) Connection timed out after 2001 milliseconds
command terminated with exit code 28
controlplane $ k exec -n dev source -- curl --head -m2 https://192.168.0.102
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
  0     0    0     0    0     0      0      0 --:--:--  0:00:02 --:--:--     0
curl: (28) Connection timed out after 2000 milliseconds
command terminated with exit code 28
# 443通信は deny 

80 のみを deny に変更する。

cat <<EOF | kubectl apply -f -
apiVersion: "cilium.io/v2"
kind: CiliumNetworkPolicy
metadata:
  name: "cidr-l4-rule"
  namespace: dev
spec:
  endpointSelector: # 対象は "role: crawler" を有するエンドポイント
    matchLabels:
      type: source
      io.kubernetes.pod.namespace: dev
  egress: # 対象は、アウトバウンド通信、192.0.2.0/24 宛、TCP:80ポート通信
  - toPorts:
    - ports:
      - port: "80"
        protocol: TCP
EOF
# 80 番の Deny 設定作成に伴い、default-deny モードに移行する。故に、当該エンドポイントに対して、明示的に許可ポリシーを設定しない限り、アウトバウンド通信は許可されない。

### L7 サンプル

```AllowGET-public.yaml
apiVersion: "cilium.io/v2"
kind: CiliumNetworkPolicy
metadata:
  name: "rule1"
spec:
  description: "Allow HTTP GET /public from env=prod to app=service"
  endpointSelector:
    matchLabels:
      app: service # 対象
  ingress:
  - fromEndpoints: # 対象は "env: prod" を有するエンドポイントからのインバウンド通信
    - matchLabels: # かつ、TCP:80 で、GET /public のみ許可する
        env: prod
    toPorts:
    - ports:
      - port: "80"
        protocol: TCP
      rules:
        http:
        - method: "GET"
          path: "/public"

GET / で設定してみる。

cat <<EOF | kubectl apply -f -
apiVersion: "cilium.io/v2"
kind: CiliumNetworkPolicy
metadata:
  name: "rule1"
  namespace: dev
spec:
  endpointSelector:
    matchLabels:
      type: source
      io.kubernetes.pod.namespace: dev
  ingress:
  - fromEndpoints:
    - matchLabels: 
        type: dest
        io.kubernetes.pod.namespace: stg
    toPorts:
    - ports:
      - port: "80"
        protocol: TCP
      rules:
        http:
        - method: "GET"
          path: "/"
EOF

最後に L7 で認証を requiredする方法は?

マニュアルに明記されている。

authentication:
    mode: "required"

L7 設定に authentication 設定を追加してみる。

cat <<EOF | kubectl apply -f -
apiVersion: "cilium.io/v2"
kind: CiliumNetworkPolicy
metadata:
  name: "rule1"
  namespace: dev
spec:
  endpointSelector:
    matchLabels:
      type: source
      io.kubernetes.pod.namespace: dev
  ingress:
  - fromEndpoints:
    - matchLabels: 
        type: dest
        io.kubernetes.pod.namespace: stg
    toPorts:
    - ports:
      - port: "80"
        protocol: TCP
      rules:
        http:
        - method: "GET"
          path: "/"
    authentication:
      mode: "required"
EOF

# 上記 yaml で設定可能

controlplane $ k describe -n dev cnp rule1 
Name:         rule1
Namespace:    dev
Labels:       <none>
Annotations:  <none>
API Version:  cilium.io/v2
Kind:         CiliumNetworkPolicy
Metadata:
  Creation Timestamp:  2024-12-10T10:23:43Z
  Generation:          1
  Resource Version:    6643
  UID:                 b3635ede-e4c4-4bab-8813-3fafe574c2f0
Spec:
  Endpoint Selector:
    Match Labels:
      io.kubernetes.pod.namespace:  dev
      Type:                         source
  Ingress:
    Authentication:
      Mode:  required
    From Endpoints:
      Match Labels:
        io.kubernetes.pod.namespace:  stg
        Type:                         dest
    To Ports:
      Ports:
        Port:      80
        Protocol:  TCP
      Rules:
        Http:
          Method:  GET
          Path:    /
Status:
  Conditions:
    Last Transition Time:  2024-12-10T10:23:43Z
    Message:               Policy validation succeeded
    Status:                True
    Type:                  Valid
Events:                    <none>
# describe結果

あとがき

Networkpolicyは別の記事に書きます。。。

ソース

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?