EKS の強化された Network Policy を利用して、DNS ベースでのネットワーク制御を行ってみる

EKS の強化された Network Policy を利用して、DNS ベースでのネットワーク制御を行ってみる

2026.01.06

背景

EKS Auto Mode の現時点での制約として Pod の Security Group が使えないという物があります。

EKS Auto Mode does not support:
Security Groups per Pod (SGPP).
https://docs.aws.amazon.com/eks/latest/userguide/auto-networking.html

そのため、AWS リソースとの通信制御が若干行い辛いデメリットがありました。
AWS リソースは IP が変更することを意識する必要があるケースが多いのに対して、通常の Network Policy では IP ブロックを指定しての通信制御しかできないからです。
この際、DNS ベースのフィルタリングを利用できれば AWS リソースとの通信制御もかなり行いやすくなります。

eks.png

先日のアップデートで EKS で利用できる Network Policy が強化され、VPC CNI 単体で DNS ベースでのフィルタリングを行うことが可能になりました。

What's New
https://aws.amazon.com/about-aws/whats-new/2025/12/amazon-eks-enhanced-network-security-policies/

AWS Blog
https://aws.amazon.com/blogs/containers/amazon-eks-introduces-enhanced-network-policy-capabilities/

これまでも Cilium など 3rd パーティのネットワークポリシーエンジンを利用すれば EKS Auto Mode で DNS ベースのフィルタリングを実施することができました。

https://dev.classmethod.jp/articles/eks-auto-mode-restrict-rds-access-by-cilium/

とはいえ、VPC CNI が DNS ベースのフィルタリングに対応してくれるのであれば、セットアップが非常に楽になります。
また、構成がシンプルになって予期せぬ振る舞いも発生し辛くなると想定されます。
ということで、EKS Auto Mode で強化された Network Policy を利用して DNS ベースのフィルタリングを行ってみます。

やってみる

AWS インフラ作成

Auto Mode を有効化した EKS クラスターを Terraform で作成します。
AWS リソースとの疎通確認を行うため、マルチ AZ の RDS クラスターも作成します。

VPC

module "vpc" {
  source  = "terraform-aws-modules/vpc/aws"
  version = "~> 6.0.1"

  name = "eks-vpc"

  cidr = "10.0.0.0/16"

  azs             = ["ap-northeast-1a", "ap-northeast-1c", "ap-northeast-1d"]
  public_subnets  = ["10.0.0.0/24", "10.0.1.0/24", "10.0.2.0/24"]
  private_subnets = ["10.0.100.0/24", "10.0.101.0/24", "10.0.102.0/24"]

  enable_nat_gateway = true
  single_nat_gateway = true

  public_subnet_tags = {
    "kubernetes.io/role/elb" = 1
  }
  private_subnet_tags = {
    "kubernetes.io/role/internal-elb" = 1
  }
}

EKS クラスター

module "eks" {
  source  = "terraform-aws-modules/eks/aws"
  version = "~> 21.0.4"

  name               = "test-cluster"
  kubernetes_version = "1.34"

  endpoint_public_access  = true
  endpoint_private_access = true
  enable_irsa             = false

  vpc_id     = module.vpc.vpc_id
  subnet_ids = module.vpc.private_subnets

  authentication_mode = "API"
  enable_cluster_creator_admin_permissions = true

  compute_config = {
    enabled    = true
    node_pools = ["general-purpose"]
  }
}

RDS クラスター

resource "aws_db_subnet_group" "db_subnet" {
  name = "sample-db-subnet-gp"
  subnet_ids = module.vpc.private_subnets
}

resource "aws_security_group" "rds_sg" {
  name        = "sample-rds-sg"
  description = "sample rds security group"
  vpc_id      = module.vpc.vpc_id
  ingress {
    description = "PostgreSQL"
    from_port   = 5432
    to_port     = 5432
    protocol    = "tcp"
    cidr_blocks = [module.vpc.vpc_cidr_block]
  }
  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }
}

resource "aws_rds_cluster" "aurora_postgres_clsuster" {
  cluster_identifier      = "sample-aurora-postgres-cluster"
  engine                  = "aurora-postgresql"
  engine_version          = "16.4"
  database_name           = "postgres"
  master_username         = "postgres"
  master_password         = "password"
  db_subnet_group_name    = aws_db_subnet_group.db_subnet.name
  vpc_security_group_ids  = [aws_security_group.rds_sg.id]
  skip_final_snapshot     = true
  backup_retention_period = 7
  preferred_backup_window = "07:00-09:00"
  port                    = 5432
  storage_encrypted       = true
}

resource "aws_rds_cluster_instance" "aurora_postgres_instance" {
  count                   = 2
  cluster_identifier      = aws_rds_cluster.aurora_postgres_clsuster.id
  instance_class          = "db.t3.medium"
  engine                  = "aurora-postgresql"
  engine_version          = "16.4"
  publicly_accessible     = false
  db_subnet_group_name    = aws_db_subnet_group.db_subnet.name
  auto_minor_version_upgrade = true
}

Network Policy Controller を有効化

Network Policy Controller を有効化します。

https://github.com/aws/amazon-network-policy-controller-k8s/

コントロールプレーン側に自動でインストールされるコンポーネントですが、Config Map を作成して有効化する必要があります。

apiVersion: v1
kind: ConfigMap
metadata:
  name: amazon-vpc-cni
  namespace: kube-system
data:
  enable-network-policy-controller: "true"

続いて、利用する NodeClass で Network Policy が有効になっていることを確認します(Disabled になっていないことを確認)。
クラスター作成時に作成された default ノードクラスについても、最初から有効化されていました。

% kubectl get nodeclass default -o jsonpath='{.spec.networkPolicy}'
DefaultAllow

NetworkPolicy で通信制御してみる

名前空間を作成します。

% kubectl create ns app
namespace/app created

この状態でコンテナを作成します。

% kubectl run postgres -it --rm --image=postgres:latest -n app /bin/bash

DefaultAllow が効いているので、Aurora PostgreSQL に問題無く接続できます。

root@postgres:/# psql -h sample-aurora-postgres-cluster.cluster-cx4ayeauo8zn.ap-northeast-1.rds.amazonaws.com -U postgres
Password for user postgres:
psql (18.1 (Debian 18.1-1.pgdg13+2), server 16.4)
SSL connection (protocol: TLSv1.3, cipher: TLS_AES_256_GCM_SHA384, compression: off, ALPN: none)
Type "help" for help.

postgres=> \q
root@postgres:/# exit

デフォルトで通信を拒否したいので、kubectl edit nodeclass default でノードクラスの設定を Default Deny に変更しました。

% kubectl get nodeclass default -o jsonpath='{.spec.networkPolicy}'
DefaultDeny%

改めて、コンテナを立てます。

kubectl run postgres -it --rm --image=postgres:latest -n app -- /bin/bash

この状態だと、名前解決もできなくなってます。

root@postgres:/# psql -h sample-aurora-postgres-cluster.cluster-cx4ayeauo8zn.ap-northeast-1.rds.amazonaws.com -U postgres
psql: error: could not translate host name "sample-aurora-postgres-cluster.cluster-cx4ayeauo8zn.ap-northeast-1.rds.amazonaws.com" to address: Temporary failure in name resolution

DNS 通信を通す NetworkPolicy を作成します。

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-dns-network-policy
  namespace: app
spec:
  podSelector: {}
  policyTypes:
    - Egress
  egress:
    - ports:
        - protocol: TCP
          port: 53
    - ports:
        - protocol: UDP
          port: 53

再度、コンテナを立てます。

kubectl run postgres -it --rm --image=postgres:latest -n app -- /bin/bash

名前解決はできますが、疎通できない状態まで来ました。

root@postgres:/# psql -h sample-aurora-postgres-cluster.cluster-cx4ayeauo8zn.ap-northeast-1.rds.amazonaws.com -U postgres
psql: error: connection to server at "sample-aurora-postgres-cluster.cluster-cx4ayeauo8zn.ap-northeast-1.rds.amazonaws.com" (10.0.101.113), port 5432 failed: Connection timed out
        Is the server running on that host and accepting TCP/IP connections?

続いて IP を指定して、Aurora クラスターへの通信を許可する NetworkPolicy を作成します。

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: backend-network-policy
  namespace: app
spec:
  podSelector:
    matchLabels:
      role: backend
  policyTypes:
    - Egress
  egress:
    - to:
        - ipBlock:
            cidr: "10.0.101.113/32"
      ports:
        - protocol: TCP
          port: 5432

これで、上手く通信が通るようになりました。

root@postgres:/# psql -h sample-aurora-postgres-cluster.cluster-cx4ayeauo8zn.ap-northeast-1.rds.amazonaws.com -U postgres
Password for user postgres:
psql (18.1 (Debian 18.1-1.pgdg13+2), server 16.4)
SSL connection (protocol: TLSv1.3, cipher: TLS_AES_256_GCM_SHA384, compression: off, ALPN: none)
Type "help" for help.

postgres=>

リーダー側のエンドポイントを利用すると、IP が違うのでちゃんと拒否されます。

root@postgres:/# psql -h sample-aurora-postgres-cluster.cluster-ro-cx4
ayeauo8zn.ap-northeast-1.rds.amazonaws.com -U postgres
psql: error: connection to server at "sample-aurora-postgres-cluster.cluster-ro-cx4ayeauo8zn.ap-northeast-1.rds.amazonaws.com" (10.0.102.105), port 5432 failed: Connection timed out
        Is the server running on that host and accepting TCP/IP connections?

続いて、NetworkPolicy で domainNames を指定してみます。

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: backend-network-policy
  namespace: app
spec:
  podSelector:
    matchLabels:
      role: backend
  policyTypes:
    - Egress
  egress:
    - to:
        - domainNames:
            - "sample-aurora-postgres-cluster.cluster-cx4ayeauo8zn.ap-northeast-1.rds.amazonaws.com"
      ports:
        - protocol: TCP
          port: 5432

そういった属性は使えないので当然失敗します。

% k apply -f backend-policy.yaml
The request is invalid: patch: Invalid value: "map[metadata:map[annotations:map[kubectl.kubernetes.io/last-applied-configuration:{\"apiVersion\":\"networking.k8s.io/v1\",\"kind\":\"NetworkPolicy\",\"metadata\":{\"annotations\":{},\"name\":\"backend-network-policy\",\"namespace\":\"app\"},\"spec\":{\"egress\":[{\"ports\":[{\"port\":5432,\"protocol\":\"TCP\"}],\"to\":[{\"domainNames\":[\"sample-aurora-postgres-cluster.cluster-cx4ayeauo8zn.ap-northeast-1.rds.amazonaws.com\"]}]}],\"podSelector\":{\"matchLabels\":{\"role\":\"backend\"}},\"policyTypes\":[\"Egress\"]}}\n]] spec:map[egress:[map[ports:[map[port:5432 protocol:TCP]] to:[map[domainNames:[sample-aurora-postgres-cluster.cluster-cx4ayeauo8zn.ap-northeast-1.rds.amazonaws.com]]]]]]]": strict decoding error: unknown field "spec.egress[0].to[0].domainNames"

Application Network Policy で通信制御してみる

ということで Application Network Policy の登場です。
先程の Network Policy を削除して、下記 Application Network Policy を作成します。
apiVersion と kind が異なりますが、その他の書き方は同じです。

apiVersion: networking.k8s.aws/v1alpha1
kind: ApplicationNetworkPolicy
metadata:
  name: backend-network-policy
  namespace: app
spec:
  podSelector:
    matchLabels:
      role: backend
  policyTypes:
    - Egress
  egress:
    - to:
        - domainNames:
            - "sample-aurora-postgres-cluster.cluster-cx4ayeauo8zn.ap-northeast-1.rds.amazonaws.com"
      ports:
        - protocol: TCP
          port: 5432

改めてコンテナを作成します。

kubectl run postgres -it --rm --image=postgres:latest --labels="role=backend" -n app -- /bin/bash

無事、通信も通りました。

root@postgres:/# psql -h sample-aurora-postgres-cluster.cluster-cx4ayeauo8zn.ap-northeast-1.rds.amazonaws.com -U postgres
Password for user postgres:
psql (18.1 (Debian 18.1-1.pgdg13+2), server 16.4)
SSL connection (protocol: TLSv1.3, cipher: TLS_AES_256_GCM_SHA384, compression: off, ALPN: none)
Type "help" for help.

postgres=>

ドメインが異なるリーダーエンドポイントは通信が通らないことも確認できます。

root@postgres:/# psql -h sample-aurora-postgres-cluster.cluster-ro-cx4
ayeauo8zn.ap-northeast-1.rds.amazonaws.com -U postgres
psql: error: connection to server at "sample-aurora-postgres-cluster.cluster-ro-cx4ayeauo8zn.ap-northeast-1.rds.amazonaws.com" (10.0.102.105), port 5432 failed: Connection timed out
        Is the server running on that host and accepting TCP/IP connections?

ここは Application Network Policy でも Network Policy でも一緒ですが、Pod のラベルを変えると対象では無くなり、DefaultDeny によって拒否されると思われます。

kubectl run postgres -it --rm --image=postgres:latest --labels="role=frontend" -n app -- /bin/bash

frontend ラベルがついたコンテナからだと、ちゃんと接続できないことを確認できました。

root@postgres:/# psql -h sample-aurora-postgres-cluster.cluster-cx4ayeauo8zn.ap-northeast-1.rds.amazonaws.com -U postgres
psql: error: connection to server at "sample-aurora-postgres-cluster.cluster-ro-cx4ayeauo8zn.ap-northeast-1.rds.amazonaws.com" (10.0.102.105), port 5432 failed: Connection timed out
        Is the server running on that host and accepting TCP/IP connections?

注意点

ApplicationNetworkPolicy は EKS Auto Mode でのみ利用できます。
EKS Auto Mode を有効化していても、マネージドインスタンス上のワークロードにしか適用されません。

DNS based rules defined using the ApplicationNetworkPolicy are only applicable to workloads running in EKS Auto Mode-launched EC2 instances. If you are running a mixed mode cluster (consisting of both EKS Auto and non EKS Auto worker nodes), your DNS-based rules are only effective in the EKS Auto mode worker nodes (EC2 managed instances).
https://docs.aws.amazon.com/eks/latest/userguide/auto-net-pol.html#_considerations

最後に

EKS Auto Mode で強化された Network Policy を利用して、DNS ベースのフィルタリングを試してみました。
今回は AWS リソースとの接続制御に利用しましたが、外部 SaaS やオンプレミスにあるリソースとの通信制御にも有用です。
是非試してみて下さい!

この記事をシェアする

FacebookHatena blogX

関連記事