From 37b75bdcb64aafa3b3de49630c65ae38a22b3074 Mon Sep 17 00:00:00 2001 From: Hana <115437281+Hana-Hasa@users.noreply.github.com> Date: Fri, 13 Nov 2026 15:13:19 +0700 Subject: [PATCH] =?UTF-8?q?[docs]=20[VKS]=20Security=20Group=20=E2=80=94?= =?UTF-8?q?=20rewrite=20+=20trang=20con=20Gi=E1=BB=9Bi=20h=E1=BA=A1n=20out?= =?UTF-8?q?bound=20cho=20worker=20node,=20annotation=20enable-default-egre?= =?UTF-8?q?ss=20=E2=80=94=20VI=20+=20EN?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Code --- English/SUMMARY.md | 1 + English/overview/product-updates-all/2026.md | 8 + English/vks/announcements/release-notes.md | 13 ++ English/vks/security-group.md | 166 ++++++++++++----- ...limit-outbound-traffic-for-worker-nodes.md | 169 ++++++++++++++++++ Vietnamese/SUMMARY.md | 1 + .../thong-bao-va-cap-nhat/2026.md | 8 + Vietnamese/vks/announcements/release-notes.md | 13 ++ Vietnamese/vks/security-group.md | 145 ++++++++++++--- .../gioi-han-outbound-cho-worker-node.md | 169 ++++++++++++++++++ 10 files changed, 628 insertions(+), 65 deletions(-) create mode 100644 English/vks/security-group/limit-outbound-traffic-for-worker-nodes.md create mode 100644 Vietnamese/vks/security-group/gioi-han-outbound-cho-worker-node.md diff --git a/English/SUMMARY.md b/English/SUMMARY.md index c2bff7bc6..0a8c7122d 100644 --- a/English/SUMMARY.md +++ b/English/SUMMARY.md @@ -717,6 +717,7 @@ * [CSI Quick Start](vks/storage/working-with-csi/csi-quick-start.md) * [CSI Limitation](vks/storage/working-with-csi/gioi-han-va-han-che-csi.md) * [Security Group](vks/security-group.md) + * [Limit outbound traffic for VKS worker nodes](vks/security-group/limit-outbound-traffic-for-worker-nodes.md) * [Upgrade Kubernetes Version](vks/upgrade-kubernetes-version/README.md) * [Manually Upgrade](vks/upgrade-kubernetes-version/manually-upgrade.md) * [Automatically Upgrade](vks/upgrade-kubernetes-version/automatically-upgrade.md) diff --git a/English/overview/product-updates-all/2026.md b/English/overview/product-updates-all/2026.md index 9e09c2ed9..048b08fe3 100644 --- a/English/overview/product-updates-all/2026.md +++ b/English/overview/product-updates-all/2026.md @@ -239,6 +239,14 @@ For more details about the updated renewal mechanism and policy, please refer [h {% tab title="New features" %} **Nov 2026** +**VKS — Limit worker node outbound traffic & disable default outbound on the Load Balancer SG** + +VKS adds a guide for limiting worker node outbound traffic, plus an annotation to disable the 2 default outbound rules on the Security Group created by the GreenNode LoadBalancer Controller: + +* **Limit outbound traffic for worker nodes:** replace the default allow-all outbound rules with the minimum rule set that keeps the cluster stable (node join, image pull, volume and load balancer creation) — meeting security and compliance requirements. Applies to **private clusters**. +* **The annotation `vks.vngcloud.vn/enable-default-egress`** (GreenNode LoadBalancer Controller **0.5.0+**): set it to `"false"` on an NLB Service / ALB Ingress to remove the 2 outbound allow-all rules from the corresponding SG without downtime; defaults to `"true"`, keeping current behavior. +* Learn more at [Security Group](../../vks/security-group.md) and [Limit outbound traffic for VKS worker nodes](../../vks/security-group/limit-outbound-traffic-for-worker-nodes.md). + **VKS — Configure vLB listener ACLs via annotations** Starting with version **0.4.2** of GreenNode LoadBalancer Controller, you can configure the ACL of a Load Balancer listener directly in your manifest (Service for NLB, Ingress for ALB) — no vLB Portal needed: diff --git a/English/vks/announcements/release-notes.md b/English/vks/announcements/release-notes.md index e2db0a672..ff6017046 100644 --- a/English/vks/announcements/release-notes.md +++ b/English/vks/announcements/release-notes.md @@ -1,5 +1,18 @@ # Release notes +## Nov 13, 2026 + +VKS (VNG Kubernetes Engine) has just released a new update with the following improvements: + +**New features:** + +* **Limit outbound traffic for worker nodes:** A new guide shows how to replace the default allow-all outbound rules on worker nodes with the minimum rule set that keeps the cluster stable (node join, image pull, volume and load balancer creation) — meeting security and compliance requirements for outbound traffic control. + * Applies to **private clusters** (Cilium overlay CNI recommended); Calico and Cilium native routing work with adjusted inter-node ports. + * See [Limit outbound traffic for VKS worker nodes](../security-group/limit-outbound-traffic-for-worker-nodes.md) for details. +* **Disable default outbound on the Load Balancer Security Group via annotation:** Starting with version **0.5.0**, GreenNode LoadBalancer Controller supports the annotation **`vks.vngcloud.vn/enable-default-egress`** on NLB Services and ALB Ingresses. + * Set it to `"false"` to remove the 2 outbound allow-all rules (`0.0.0.0/0`, `::/0`) from the controller-created SG for that Service/Ingress without downtime; removing the annotation recreates them. Defaults to `"true"` — existing Services/Ingresses keep their current behavior. + * Has no effect when the Service/Ingress uses your own Security Group via the annotation `vks.vngcloud.vn/security-groups`. + ## Nov 11, 2026 VKS (VNG Kubernetes Engine) has just released a new update with the following improvements: diff --git a/English/vks/security-group.md b/English/vks/security-group.md index 33f1274e4..9bbb2a9b2 100644 --- a/English/vks/security-group.md +++ b/English/vks/security-group.md @@ -1,66 +1,146 @@ # Security Group -Security Group acts as a firewall to help you control traffic going in and out of the server (VM). On the VKS system, to ensure the cluster operates safely and effectively, default Security Groups are set up to allow necessary access for the cluster's internal operations. Automatically creating a Security Group simplifies the cluster deployment process and ensures that the cluster is protected from the start. Specifically, when you initialize a Cluser, we will automatically create several Security Groups with the following parameters: +A Security Group (SG) acts as a firewall that controls traffic going in and out of a server (VM). When you create a cluster and expose applications through a load balancer, VKS automatically creates and attaches certain SGs to worker nodes so the cluster can operate. This page describes those SGs, the rules inside them, and what VKS automatically restores if you make changes. -#### The default security group is automatically created for all Clusters +A worker node typically has the following SGs: -For each Cluster created in the VKS system, we will automatically create a Security Group. This security group will include: +| SG | Created by | Name format | Quantity | +|---|---|---|---| +| Cluster node SG | VKS, when the cluster is created | `vks-user--k8s--` | 1 SG per cluster | +| Load balancer SG | GreenNode LoadBalancer Controller, when a `LoadBalancer` Service or Ingress is created | `vks----` | 1 SG per `LoadBalancer` Service / Ingress | +| SG attached by you | You | Any name you choose | Up to you | -* Inbound: +{% hint style="info" %} +**Notes:** + +* Traffic is allowed if **any** SG attached to the VM allows it. +* SGs are stateful: return traffic of an allowed connection is automatically allowed, without a rule in the reverse direction. +* Every newly created SG comes with 2 outbound allow-all rules: `any → 0.0.0.0/0` (IPv4) and `any → ::/0` (IPv6). +* A VM can only have a limited number of SGs attached, according to the project quota. Each `LoadBalancer` Service / Ingress attaches 1 more SG to the node; if the quota is reached, the controller cannot attach new SGs. Share an SG across Services via the annotation `vks.vngcloud.vn/security-groups` to avoid exceeding the quota (see below). +{% endhint %} -| Protocol | Ether type | Port range | Source | Meaning | -| -------- | ---------- | ----------- | ---------------------------------------------- | ------------------------------------------------------ | -| TCP | IPv4 | 30000-32767 | CIDR of the VPC you use for the Cluster. | Security group rule used for TCP Node Port Services | -| UDP | IPv4 | 30000-32767 | CIDR of the VPC you use for the Cluster. | Security group rule used for UDP Node Port Services | -| TCP | IPv4 | 10250 | External IP of Load Balancer used for Cluster. | Security group rule used for Kubelet API control-plane | -| TCP | IPv4 | 10250 | CIDR of the VPC you use for the Cluster. | Security group rule used for Kubelet API control-plane | -| TCP | IPv4 | 179 | CIDR of the VPC you use for the Cluster. | Security group rule used for Kubelet API control-plane | -| 4 | IPv4 | 1-65535 | CIDR of the VPC you use for the Cluster. | Security group rule used for Calico IP-in-IP | -| TCP | IPv4 | 5473 | CIDR of the VPC you use for the Cluster. | Security group rule used for Calico Typha | +## Cluster node SG -* Outbound +Each cluster has one node SG, created together with the cluster and attached to all worker nodes of every node group, including nodes created later. The SG description is: `Default worker security group for VKS cluster . Please DO NOT DELETE it.` -| Protocol | Ether type | Port range | Destination | Meaning | -| -------- | ---------- | ---------- | ----------- | ----------------------------------- | -| ANY | IPv4 | 0-65535 | 0.0.0.0/0 | Default rule of all Security groups | -| ANY | IPv6 | 0-65535 | ::/0 | Default rule of all Security groups | +In the tables below, **``** is the CIDR of the subnet used by the node group. If the node groups use multiple subnets, each rule is created repeatedly for each subnet CIDR. -#### Security group is automatically created by VNGCLOUD LoadBalancer Controller +### Inbound — applied to all CNIs -When you use GreenNode LoadBalancer Controller to integrate Network Load Balancer with Cluster on VKS system, we will automatically create a Security Group. This security group will include: +| Protocol | Ether type | Port range | Source | Meaning | +|---|---|---|---|---| +| TCP | IPv4 | 30000-32767 | `` | NodePort Service (TCP) | +| UDP | IPv4 | 30000-32767 | `` | NodePort Service (UDP) | +| TCP | IPv4 | 10250 | `` | Kubelet API | +| TCP | IPv4 | 10250 | `/32` | Kubelet API from the control plane. Only present when the cluster's control plane endpoint is an IP address | -* Inbound: +### Inbound — additional rules per CNI -| Protocol | Ether type | Port range | Source | -| ---------------- | ---------- | --------------- | -------------------------------------------------- | -| TCP, UDP or ICMP | IPv4 | Port of Service | Subnet Mask of the Subnet you use for the Cluster. | +**Calico Overlay** -* Outbound: +| Protocol | Ether type | Port range | Source | Meaning | +|---|---|---|---|---| +| TCP | IPv4 | 179 | `` | Calico BGP | +| 4 (IP-in-IP) | IPv4 | 1-65535 | `` | Calico IP-in-IP | +| TCP | IPv4 | 5473 | `` | Calico Typha | -| Protocol | Ether type | Port range | Destination | Meaning | -| -------- | ---------- | ---------- | ----------- | ----------------------------------- | -| ANY | IPv4 | 0-65535 | 0.0.0.0/0 | Default rule of all Security groups | -| ANY | IPv6 | 0-65535 | ::/0 | Default rule of all Security groups | +**Cilium Overlay** -#### Security group is automatically created by VNGCLOUD LoadBalancer Controller +| Protocol | Ether type | Port range | Source | Meaning | +|---|---|---|---|---| +| UDP | IPv4 | 8472 | `` | Cilium VXLAN overlay | +| TCP | IPv4 | 4240 | `` | Cilium health check (TCP) | +| ICMP | IPv4 | 1-255 | `` | Cilium health check (ICMP) | -When you use GreenNode LoadBalancer Controller to integrate Application Load Balancer with Cluster on VKS system, we will automatically create a Security Group. This security group will include: +**Cilium VPC Native Routing** -* Inbound: +| Protocol | Ether type | Port range | Source | Meaning | +|---|---|---|---|---| +| UDP | IPv4 | 8472 | `` | Cilium VXLAN | +| TCP | IPv4 | 4240 | `` | Cilium health check (TCP) | +| ICMP | IPv4 | 1-255 | `` | Cilium health check (ICMP) | +| TCP | IPv4 | 53 | `` | DNS (TCP) | +| UDP | IPv4 | 53 | `` | DNS (UDP) | -| Protocol | Ether type | Port range | Source | -| -------- | ---------- | --------------- | -------------------------------------------------- | -| TCP | IPv4 | Port of Service | Subnet Mask of the Subnet you use for the Cluster. | +### Outbound -* Outbound: +| Protocol | Ether type | Port range | Destination | Meaning | +|---|---|---|---|---| +| ANY | IPv4 | 0-65535 | 0.0.0.0/0 | Default rule of every SG | +| ANY | IPv6 | 0-65535 | ::/0 | Default rule of every SG | -| Protocol | Ether type | Port range | Destination | Meaning | -| -------- | ---------- | ---------- | ----------- | ----------------------------------- | -| ANY | IPv4 | 0-65535 | 0.0.0.0/0 | Default rule of all Security groups | -| ANY | IPv6 | 0-65535 | ::/0 | Default rule of all Security groups | +### What VKS automatically restores -{% hint style="info" %} -**Attention:** +VKS periodically checks the node SG: -* Default Security Groups are set up to meet the basic security needs of the cluster. If you edit or delete the Security Groups created for the cluster, it may result in connectivity and access issues between nodes in the cluster or the cluster may not function correctly or may not even start. To ensure the stability and security of the cluster, the system will automatically reset Security Groups to default settings after every fixed period of time. +* **Inbound rules in the tables above deleted or modified:** VKS recreates the missing rules. +* **Rules you added yourself** (inbound or outbound): VKS leaves them untouched. +* **Default outbound rules:** VKS does not manage them. If you delete them, VKS will not recreate them. See [Limit outbound traffic for VKS worker nodes](security-group/limit-outbound-traffic-for-worker-nodes.md) before deleting. +* **The entire node SG deleted:** VKS creates a new node SG (with the 2 default outbound allow-all rules) and attaches it to the nodes. Any rules you added to the old SG, including a restricted outbound rule set, are lost and must be reconfigured on the new SG. + +{% hint style="warning" %} +**Do not delete the cluster node SG.** The node SG is deleted together with the cluster. Deleting it manually causes the cluster to lose connectivity between nodes until VKS creates a new SG, and your custom configuration on the old SG is lost. {% endhint %} + +## Load balancer SG + +When you create a Service `type: LoadBalancer` (Network Load Balancer) or an Ingress (Application Load Balancer), the GreenNode LoadBalancer Controller creates a dedicated SG for that Service/Ingress, with the description `Automatically created using VNGCLOUD LoadBalancer Controller`. The SG is attached to all worker nodes (or only the nodes matching the annotation `vks.vngcloud.vn/target-node-labels`), including nodes created later. + +In the tables below, **``** is the CIDR of the subnet the load balancer uses to connect to the nodes (backend subnet). + +### Inbound — Service `LoadBalancer` + +| Case | Protocol | Port | Source | Meaning | +|---|---|---|---|---| +| Default (target type `instance`) | Follows the protocol of each Service port (TCP/UDP) | NodePort of each port | `` | Load balancer accesses the NodePort | +| Target type `ip` | Follows the protocol of each Service port (TCP/UDP) | `targetPort` of the pod | `` | Load balancer accesses the pod directly | +| Cluster uses Cilium VPC Native Routing | Follows the protocol of each Service port (TCP/UDP) | `targetPort` of the pod | Subnet CIDR of every node in the cluster | Nodes forward traffic to pods on other nodes | +| With annotation `vks.vngcloud.vn/healthcheck-port` | Follows the protocol of the Service port | Declared health check port | `` | Custom health check port | +| Service has a UDP port | ICMP | 1-255 | Same source as the UDP rule | Health check for the UDP port | + +### Inbound — Ingress + +Same as the Service above, applied to each backend Service of the Ingress (default backend and every path), with the protocol always being TCP. + +### Outbound + +| Protocol | Ether type | Port range | Destination | Meaning | +|---|---|---|---|---| +| ANY | IPv4 | 0-65535 | 0.0.0.0/0 | Default outbound | +| ANY | IPv6 | 0-65535 | ::/0 | Default outbound | + +These 2 outbound rules are disabled with the annotation `vks.vngcloud.vn/enable-default-egress: "false"` on the Service/Ingress (requires GreenNode LoadBalancer Controller version `0.5.0` or later). Details at [Limit outbound traffic for VKS worker nodes](security-group/limit-outbound-traffic-for-worker-nodes.md). + +### What VKS automatically restores + +The controller manages **all** rules (both inbound and outbound) of this SG: + +* Rules modified or deleted manually are restored at the next periodic sync. Rules you add to this SG yourself will be deleted. +* When you modify the Service/Ingress (ports, annotations…), the rules are updated accordingly. +* When the Service/Ingress is deleted, the SG is detached from the nodes and deleted. + +Therefore, **do not modify rules directly on the portal** for this SG; always configure via annotations. + +### Use your own SG instead of the auto-created one + +Add the annotation `vks.vngcloud.vn/security-groups: ","` to the Service/Ingress: + +* The controller does not create a dedicated SG for that Service/Ingress; any previously auto-created SG is detached from the nodes and deleted. +* The SGs you specify are attached to the worker nodes (including new nodes) — **not** to the load balancer. +* The controller **does not touch** the rules of these SGs: you add the inbound rules for the Service ports yourself (per the table above) and manage outbound yourself. The annotation `enable-default-egress` has no effect in this case. +* You can share one SG across multiple Services/Ingresses to reduce the number of SGs attached to each node. + +{% hint style="info" %} +The annotation `vks.vngcloud.vn/inbound-cidrs` (restricting client IPs that can access the load balancer) configures the ACL on the load balancer's listeners; it does not change SG rules. +{% endhint %} + +## Frequently asked questions + +**I want to block worker node outbound traffic to the internet?** +See [Limit outbound traffic for VKS worker nodes](security-group/limit-outbound-traffic-for-worker-nodes.md). You must handle outbound on **every** SG attached to the node, not just the cluster node SG. + +**I want to add an inbound rule for my application (e.g. open a port for another system in the VPC to access the node)?** +Add the rule to the cluster node SG or to a separate SG that you create and attach to the node yourself. Do not add it to the load balancer SG, because the controller will delete that rule. + +**Do newly created nodes automatically get all the SGs?** +Yes. The cluster node SG and the load balancer SG are automatically attached to new nodes. SGs you attached to the VM manually are **not** automatically attached to new nodes; use the annotation `vks.vngcloud.vn/security-groups` if you need your SG to follow the nodes. diff --git a/English/vks/security-group/limit-outbound-traffic-for-worker-nodes.md b/English/vks/security-group/limit-outbound-traffic-for-worker-nodes.md new file mode 100644 index 000000000..f8211d239 --- /dev/null +++ b/English/vks/security-group/limit-outbound-traffic-for-worker-nodes.md @@ -0,0 +1,169 @@ +# Limit outbound traffic for VKS worker nodes + +By default, worker nodes of a VKS cluster are allowed outbound access to every destination. This guide shows how to configure an outbound rule set that is **the minimum for a VKS cluster to operate stably**. Destinations that your applications access are out of scope of this rule set; you must add them yourself (see the note in Step 2). + +- **Scope:** **private clusters** using the Cilium overlay CNI. With Calico or Cilium native routing, the steps still apply; only the inter-node ports in Step 2 differ (how to determine them is described there). +- **Not applicable to public clusters:** nodes access VNG Cloud services via public domains whose IP addresses can change at any time, so they cannot be filtered with Security Groups. +- **Only need to restrict pod egress:** use a `CiliumNetworkPolicy` egress. This option supports domain (FQDN) filtering and does not affect system components. +- **Responsibility:** you are responsible for managing and maintaining the outbound rule set. Missing rules can prevent new nodes from joining the cluster, pulling images, or creating volumes or load balancers. + +## What you need to know + +- A node's outbound traffic is allowed if **any** Security Group (SG) attached to the VM allows it. Therefore you must remove the outbound allow-all rules on **all** SGs attached to the node, not just the cluster SG. +- SGs are stateful: you only need outbound rules; return traffic is automatically allowed. +- Every newly created SG comes with 2 default outbound allow-all rules: `any → 0.0.0.0/0` and `any → ::/0`. + +SGs typically attached to a VKS node: + +| SG | Name format | Action required | +| --- | --- | --- | +| Cluster node SG | `vks-user--k8s--…` | Add allow rules, delete the 2 default rules (Steps 2–3) | +| Load balancer SG | `vks----…` | Disable outbound via annotation (next section) | +| SG attached by you | Any name you choose | Delete the 2 default rules | + +## Disable outbound on the load balancer SG + +The GreenNode LoadBalancer Controller creates one SG per `LoadBalancer` Service and Ingress, then attaches this SG to the nodes. By default, this SG allows all outbound traffic; if you delete the rules manually, the controller recreates them. To disable them, add the following annotation to **all** `LoadBalancer` Services and Ingresses: + +```yaml +metadata: + annotations: + vks.vngcloud.vn/enable-default-egress: "false" +``` + +The controller removes the 2 outbound rules from the corresponding SG without causing downtime for the load balancer. When you remove the annotation, the 2 rules are recreated. + +> **Do not delete outbound rules directly on the portal** for SGs managed by the controller: the controller will recreate these rules at the next periodic sync. Always use the annotation. + +The annotation requires GreenNode LoadBalancer Controller version `0.5.0` or later; if your cluster runs an older version, upgrade first. Check the current version: + +```bash +kubectl -n kube-system get deploy -l app.kubernetes.io/name=vngcloud-load-balancer-controller \ + -o jsonpath='{.items[0].spec.template.spec.containers[0].image}'; echo +``` + +**Apply to every Service/Ingress, including resources created later.** A single `LoadBalancer` Service or Ingress missing the annotation reopens outbound for the entire node. List resources missing the annotation (empty output means all are covered): + +```bash +kubectl get svc -A -o jsonpath='{range .items[?(@.spec.type=="LoadBalancer")]}{.metadata.namespace}/{.metadata.name} {.metadata.annotations.vks\.vngcloud\.vn/enable-default-egress}{"\n"}{end}' | awk '$2!="false"' +kubectl get ingress -A -o jsonpath='{range .items[*]}{.metadata.namespace}/{.metadata.name} {.spec.ingressClassName}{.metadata.annotations.kubernetes\.io/ingress\.class} {.metadata.annotations.vks\.vngcloud\.vn/enable-default-egress}{"\n"}{end}' | awk '$2=="vngcloud" && $3!="false"' +``` + +## Step 1: Collect cluster parameters + +IP addresses differ between clusters, so you need to collect parameters for each cluster individually. Create a debug pod on a node (requires kubectl 1.28 or later; the command uses the Cilium image already present on the node, because private clusters usually cannot reach Docker Hub): + +```bash +NODE=$(kubectl get nodes -o jsonpath='{.items[0].metadata.name}') +IMG=$(kubectl -n kube-system get ds cilium -o jsonpath='{.spec.template.spec.containers[0].image}') +kubectl debug node/$NODE -it --profile=sysadmin --image=$IMG -- chroot /host bash -c ' + echo "## control plane"; grep "server:" /etc/kubernetes/kubelet.conf + echo "## endpoints"; for h in iamapis.vngcloud.vn hcm-3.api.vngcloud.vn hcm03.vstorage.vngcloud.vn vcr.vngcloud.vn; do + getent ahosts $h | cut -d" " -f1 | sort -u | sed "s/^/$h /"; done + echo "## dns"; resolvectl status | grep -E "DNS Servers|Current DNS" + echo "## ntp"; timedatectl show-timesync -p ServerAddress -p SystemNTPServers + echo "## dhcp"; networkctl status eth0 | grep "DHCP4 via"' +kubectl get pods -o name | grep node-debugger | xargs kubectl delete +``` + +Record the following values: + +| Parameter | Example | Source | +| --- | --- | --- | +| VPC CIDR | `10.0.0.0/16` | VPC portal (the CIDR of the VPC, not of the subnet) | +| Control plane IP | `10.0.1.3` | `## control plane` section. If it is a hostname, run `getent ahosts ` on the node and collect all IPs | +| Private endpoint IPs | `10.0.1.6` … `10.0.1.9` | `## endpoints` section: IAM (`iamapis…`), vServer API (`…api…`), vStorage (`…vstorage…`), vCR (`vcr…`). A multi-AZ cluster has one IP per zone — collect all of them. The domains in the command are for the HCM region; for other regions, see the Private Service Endpoint page on the portal | +| DNS resolver | `8.8.8.8` | `## dns` section, collect all IPs | +| NTP server | Internal NTP server IP | `## ntp` section. If it is a public pool (e.g. `ntp.ubuntu.com`), the IP changes constantly: switch to an internal NTP server or allow `UDP 123 → 0.0.0.0/0` | +| DHCP server | `10.0.1.2` | `## dhcp` section | + +## Step 2: Create the outbound rule set + +Add the rules below to the **node SG**: on the vServer portal, go to **Security Groups**, select the SG named `vks-user--k8s--…`, open the **Outbound** rule list and add rules. Take the values in `< >` from Step 1; each IP corresponds to one rule in `/32` form. The "Type" column is the rule type to select on the portal. Note: the **DNS** type on the portal only opens TCP, so you also need a **Custom UDP** rule for DNS. + +**Option 1 (recommended): allow all traffic within the VPC, block traffic outside the VPC.** + +| # | Type | Port | Destination | Purpose | +| --- | --- | --- | --- | --- | +| 1 | All Traffic | – | `` | Control plane, private endpoints, DHCP, inter-node traffic | +| 2 | HTTP | 80 | `169.254.169.254/32` | Metadata service, used during node bootstrap and when the CSI/LB controllers start | +| 3 | DNS **and** Custom UDP | 53 | `/32` | DNS resolution | +| 4 | Custom UDP | 123 | `/32` | Time sync | + +Verify that the control plane IP, the 4 private endpoint IPs, and the DHCP server are all within ``. Any IP outside this range needs its own rule per the Option 2 table. If the DNS resolver and NTP server are inside the VPC, rules 3 and 4 are not needed. + +
+Option 2: open only the necessary ports (replaces rule 1) + +| Type | Port | Destination | Purpose | +| --- | --- | --- | --- | +| Custom TCP | 6443 | `/32` | Kubernetes API server | +| Custom TCP | 8132 | `/32` | `kubectl logs/exec`, admission webhook | +| HTTPS | 443 | `/32` | Authentication for the CSI and LB controllers | +| HTTPS | 443 | `/32` | Attach volumes, create load balancers | +| HTTPS | 443 | `/32` | Pull system images | +| HTTPS | 443 | `/32` | vStorage | +| Custom UDP | 67 | `/32` | DHCP lease renewal. Without this rule, the node still gets an IP at boot but cannot renew the lease periodically | +| Custom UDP | 8472 | `` | VXLAN tunnel between nodes (pod-to-pod traffic) | +| Custom TCP | 4240 | `` | Cilium health check | +| All ICMP | – | `` | Health check, Path MTU Discovery | +| Custom TCP | 10250 | `` | Kubelet API between nodes | +| Custom TCP | 4244 | `` | Hubble | + +The last four rules with destination `` apply to Cilium overlay. For other CNIs, copy the inbound rules VKS created on the node SG to the outbound direction (same protocol, same port, destination ``). + +
+ +> **Note on application destinations.** The rule set above only covers the needs of the VKS cluster itself. After you delete the default outbound rules, every connection from your applications to a destination **outside the VPC** (with Option 2, also destinations inside the VPC) will be blocked unless it matches a rule — for example: databases or APIs outside the VPC, private or public image registries (Docker Hub, ghcr.io…), Git, logging/monitoring backends, SaaS services. Review and add rules for these destinations before applying. +> +> Destinations served by CDNs (Docker Hub, ghcr.io, quay.io and most SaaS services) change IPs constantly, so IP-based rules will stop working after a short time. We recommend mirroring images to vCR, and accessing SaaS services through a proxy or `CiliumNetworkPolicy` `toFQDNs`. + +## Step 3: Apply + +Principle: add the allow rules first, delete the allow-all rules last. Rehearse on a dev/staging cluster with the same configuration before applying to production. + +1. Back up the current configuration: the SG list of each node VM and all rules of those SGs. +2. Add all rules from Step 2, plus the rules for your application destinations, to the node SG. Do not delete any rules yet. +3. Add the annotation `enable-default-egress: "false"` to all `LoadBalancer` Services and Ingresses (see "Disable outbound on the load balancer SG"). This step must come **after** step 2: if the node SG is still missing rules and the cluster is running on the load balancer SG's outbound, disabling it causes downtime immediately. +4. During a maintenance window (off-peak hours), delete the 2 default outbound rules (`::/0` first, then `0.0.0.0/0`) on the node SG and any SGs you attached yourself. +5. Verify immediately per Step 4. If anything goes wrong, roll back first, then investigate. + +Existing connections may keep working; only **new** connections are blocked. Monitor for at least one business cycle. A newly created or recreated cluster gets a new node SG — start again from Step 1. + +## Step 4: Verify + +- [ ] **Confirm outbound is blocked:** a connection to a destination not in the rules must time out: `kubectl run egresstest --rm -it --restart=Never --image= -- curl -m 5 -sS https://1.1.1.1`. If the VPC has no internet route, this test always times out and proves nothing; instead test against a destination inside the VPC that has no allow rule. +- [ ] All nodes are `Ready`; `kubectl logs` and `kubectl exec` work normally. +- [ ] DNS resolution in pods works for both the cluster's internal domains and the external domains your applications use. +- [ ] New images can be pulled (test with `imagePullPolicy: Always`). +- [ ] Restart the CSI and LB controllers and the pods return to `Running`: `kubectl -n kube-system get deploy,ds -o name | grep -E 'csi|load-balancer' | xargs -n1 kubectl -n kube-system rollout restart` +- [ ] A PVC can be created and mounted to a pod. +- [ ] An annotated `LoadBalancer` Service can be created and receives an external address; repeat the first test: it must still time out. +- [ ] DHCP lease renewal works: in the debug pod from Step 1, run `networkctl renew eth0`; after a few seconds, `ip -4 addr show eth0` shows `valid_lft` back near the full lease time (usually 86400s). +- [ ] Scale the node group up by 1 node: the new node becomes `Ready` within the normal time. Then scale back down. +- [ ] Applications work correctly: database connections, API calls, log and metric shipping, scheduled jobs. + +## Rollback + +Add the following rule back to the node SG to return the cluster to its original state, without restarting nodes or pods: + +| Type | Port | Destination | +| --- | --- | --- | +| All Traffic | – | `0.0.0.0/0` | + +Pods that failed while the rule was missing will retry on their own. Nodes created while the rule was missing (e.g. during scaling) do not recover after the rollback rule is added; replace those nodes. Once you have identified and added the missing rules, delete the rollback rule. + +## Troubleshooting + +| Symptom | Common cause | +| --- | --- | +| New node never becomes `Ready`, keeps being replaced | Missing rule to the metadata service `169.254.169.254`, control plane (6443), vCR or DNS | +| CSI or LB controller in `CrashLoopBackOff` | Missing rule to the metadata service, IAM or vServer API | +| Pods on different nodes cannot reach each other, node `NotReady` | Missing inter-node rules (UDP 8472, TCP 4240, ICMP) | +| `kubectl logs/exec` times out | Missing TCP 8132 rule to the control plane | +| `ImagePullBackOff` | Missing rule to vCR (system images) or the registry holding your application images | +| PVC stuck in `Pending`, `LoadBalancer` Service gets no external address | Missing rule to IAM or the vServer API | +| TLS certificate "not yet valid"/"expired" errors after a few days | Missing rule to the NTP server | +| `networkctl renew eth0` on the node cannot renew the lease | Missing DHCP rule (UDP 67) | +| Rules deleted but the node can still reach the internet | Another SG still allows outbound — usually the SG of a Service/Ingress missing the annotation `enable-default-egress: "false"` | +| Application cannot reach a database, API, registry… outside the VPC | Missing rule for the application's destination (see the note in Step 2) | diff --git a/Vietnamese/SUMMARY.md b/Vietnamese/SUMMARY.md index 58996d571..b8c64c392 100644 --- a/Vietnamese/SUMMARY.md +++ b/Vietnamese/SUMMARY.md @@ -800,6 +800,7 @@ * [Integrate with Container Storage Interface (CSI)](vks/storage/working-with-csi/integrate-with-container-storage-interface-csi.md) * [Giới hạn và hạn chế CSI](vks/storage/working-with-csi/gioi-han-va-han-che-csi.md) * [Security Group](vks/security-group.md) + * [Giới hạn outbound cho worker node](vks/security-group/gioi-han-outbound-cho-worker-node.md) * [Upgrade Kubernetes Version](vks/upgrade-kubernetes-version/README.md) * [Manually Upgrade](vks/upgrade-kubernetes-version/manually-upgrade.md) * [Automatically Upgrade](vks/upgrade-kubernetes-version/automatically-upgrade.md) diff --git a/Vietnamese/gioi-thieu-chung/thong-bao-va-cap-nhat/2026.md b/Vietnamese/gioi-thieu-chung/thong-bao-va-cap-nhat/2026.md index 342e6236f..054071b92 100644 --- a/Vietnamese/gioi-thieu-chung/thong-bao-va-cap-nhat/2026.md +++ b/Vietnamese/gioi-thieu-chung/thong-bao-va-cap-nhat/2026.md @@ -234,6 +234,14 @@ Chính sách gia hạn tài nguyên này áp dụng từ ngày 8/1/2026 và áp {% tab title="Tính năng mới" %} **Tháng 11, 2026** +**VKS – Giới hạn outbound cho worker node & tắt outbound mặc định trên SG của Load Balancer** + +VKS bổ sung hướng dẫn giới hạn outbound traffic cho worker node, cùng annotation tắt 2 rule outbound mặc định trên Security Group do GreenNode LoadBalancer Controller tạo: + +* **Giới hạn outbound cho worker node:** thay rule outbound allow-all mặc định bằng bộ rule tối thiểu để cluster vẫn hoạt động ổn định (join node, pull image, tạo volume, load balancer) — đáp ứng yêu cầu bảo mật và compliance. Áp dụng cho **private cluster**. +* **Annotation `vks.vngcloud.vn/enable-default-egress`** (GreenNode LoadBalancer Controller từ phiên bản **0.5.0**): đặt `"false"` trên Service NLB / Ingress ALB để gỡ 2 rule outbound allow-all khỏi SG tương ứng mà không gây downtime; mặc định `"true"` giữ hành vi hiện tại. +* Tìm hiểu thêm tại [Security Group](../../vks/security-group.md) và [Giới hạn outbound cho worker node](../../vks/security-group/gioi-han-outbound-cho-worker-node.md). + **VKS – Cấu hình ACL listener vLB qua annotation** GreenNode LoadBalancer Controller (từ phiên bản **0.4.2**) cho phép cấu hình ACL cho listener của Load Balancer ngay trên manifest (Service NLB, Ingress ALB), không cần vào vLB Portal: diff --git a/Vietnamese/vks/announcements/release-notes.md b/Vietnamese/vks/announcements/release-notes.md index 524795b83..a5cf3d7e9 100644 --- a/Vietnamese/vks/announcements/release-notes.md +++ b/Vietnamese/vks/announcements/release-notes.md @@ -1,5 +1,18 @@ # Release notes +## Nov 13, 2026 + +VKS (VNG Kubernetes Engine) vừa ra mắt bản cập nhật mới với các cải tiến sau: + +**Tính năng mới:** + +* **Giới hạn outbound cho worker node:** Hướng dẫn mới giúp bạn thay rule outbound allow-all mặc định trên worker node bằng bộ rule tối thiểu để cluster vẫn hoạt động ổn định (join node, pull image, tạo volume, load balancer), đáp ứng yêu cầu bảo mật và compliance về kiểm soát traffic ra ngoài. + * Áp dụng cho **private cluster** (khuyến nghị CNI Cilium overlay); Calico và Cilium native routing áp dụng được với điều chỉnh port giữa các node. + * Hướng dẫn chi tiết tại [Giới hạn outbound cho worker node](../security-group/gioi-han-outbound-cho-worker-node.md). +* **Tắt outbound mặc định trên Security Group của Load Balancer qua annotation:** GreenNode LoadBalancer Controller (từ phiên bản **0.5.0**) hỗ trợ annotation **`vks.vngcloud.vn/enable-default-egress`** trên Service NLB và Ingress ALB. + * Đặt `"false"` để gỡ 2 rule outbound allow-all (`0.0.0.0/0`, `::/0`) khỏi SG do controller tạo cho Service/Ingress mà không gây downtime; gỡ annotation thì 2 rule được tạo lại. Mặc định `"true"` — Service/Ingress hiện có không thay đổi hành vi. + * Không có tác dụng khi Service/Ingress dùng Security Group riêng qua annotation `vks.vngcloud.vn/security-groups`. + ## Nov 11, 2026 VKS (VNG Kubernetes Engine) vừa ra mắt bản cập nhật mới với các cải tiến sau: diff --git a/Vietnamese/vks/security-group.md b/Vietnamese/vks/security-group.md index b4c056954..cc1f97ed8 100644 --- a/Vietnamese/vks/security-group.md +++ b/Vietnamese/vks/security-group.md @@ -1,45 +1,146 @@ # Security Group -Security Group đóng vai trò như một firewall giúp bạn kiểm soát lưu lượng truy cập ra vào máy chủ (VM). Trên hệ thống VKS, để đảm bảo cluster hoạt động an toàn và hiệu quả, các Security Group mặc định được thiết lập để cho phép các truy cập cần thiết cho hoạt động nội bộ của cluster. Việc tự động tạo Security Group giúp đơn giản hóa quá trình triển khai cluster và đảm bảo rằng cluster được bảo vệ ngay từ đầu. Cụ thể, khi bạn thực hiện khởi tạo một Cluser, chúng tôi sẽ tự động khởi tạo một vài Security Group với các thông số như sau: +Security Group (SG) đóng vai trò firewall, kiểm soát traffic vào và ra máy chủ (VM). Khi bạn tạo cluster và expose ứng dụng qua load balancer, VKS tự động tạo và gắn một số SG lên worker node để cluster hoạt động. Trang này mô tả các SG đó, các rule bên trong, và những gì VKS tự động khôi phục nếu bạn thay đổi. -### Security group mặc định được tạo tự động cho tất cả Cluster +Trên một worker node thường có các SG sau: -Mỗi Cluster được tạo ra trong hệ thống VKS, chúng tôi sẽ tự động tạo một Security Group. Security group này sẽ bao gồm: +| SG | Ai tạo | Định dạng tên | Số lượng | +|---|---|---|---| +| Node SG của cluster | VKS, khi tạo cluster | `vks-user--k8s--` | 1 SG cho mỗi cluster | +| SG của load balancer | GreenNode LoadBalancer Controller, khi tạo Service `LoadBalancer` hoặc Ingress | `vks----` | 1 SG cho mỗi Service `LoadBalancer` / Ingress | +| SG do bạn tự gắn | Bạn | Theo tên bạn đặt | Tuỳ bạn | -* Inbound: +{% hint style="info" %} +**Lưu ý:** + +* Traffic được cho phép nếu **bất kỳ** SG nào gắn trên VM cho phép. +* SG hoạt động theo cơ chế stateful: return traffic của một connection đã được cho phép sẽ tự động được cho phép, không cần rule chiều ngược lại. +* Mỗi SG khi tạo mới đều có sẵn 2 rule outbound allow-all: `any → 0.0.0.0/0` (IPv4) và `any → ::/0` (IPv6). +* Mỗi VM chỉ gắn được một số lượng SG giới hạn theo quota của project. Mỗi Service `LoadBalancer` / Ingress gắn thêm 1 SG lên node; nếu chạm quota, controller không gắn được SG mới. Dùng chung SG qua annotation `vks.vngcloud.vn/security-groups` để tránh vượt quota (xem bên dưới). +{% endhint %} -
ProtocolEther typePort rangeSourceÝ nghĩa
TCPIPv430000-32767CIDR của VPC mà bạn sử dụng cho Cluster.Security group rule sử dụng cho TCP Node Port Services
UDPIPv430000-32767CIDR của VPC mà bạn sử dụng cho Cluster.Security group rule sử dụng cho UDP Node Port Services
TCPIPv410250External IP của Load Balancer sử dụng cho Cluster.Security group rule sử dụng cho Kubelet API control-plane
TCPIPv410250CIDR của VPC mà bạn sử dụng cho Cluster.Security group rule sử dụng cho Kubelet API control-plane
TCPIPv4179CIDR của VPC mà bạn sử dụng cho Cluster.Security group rule sử dụng cho Kubelet API control-plane
4IPv41-65535CIDR của VPC mà bạn sử dụng cho Cluster.Security group rule sử dụng cho Calico IP-in-IP
TCPIPv45473CIDR của VPC mà bạn sử dụng cho Cluster.Security group rule sử dụng cho Calico Typha
+## Node SG của cluster -* Outbound +Mỗi cluster có một node SG, được tạo cùng cluster và gắn lên tất cả worker node của mọi node group, kể cả node tạo sau này. Mô tả của SG: `Default worker security group for VKS cluster . Please DO NOT DELETE it.` -
ProtocolEther typePort rangeDestinationÝ nghĩa
ANYIPv40-655350.0.0.0/0Rule mặc định của tất cả Security group
ANYIPv60-65535::/0Rule mặc định của tất cả Security group
+Trong các bảng dưới, **``** là CIDR của subnet mà node group sử dụng. Nếu các node group dùng nhiều subnet khác nhau, mỗi rule được tạo lặp lại cho từng subnet CIDR. -### Security group được tạo tự động bởi VNGCLOUD LoadBalancer Controller +### Inbound — áp dụng cho mọi CNI -Khi bạn sử dụng GreenNode LoadBalancer Controller để tích hợp Network Load Balancer với Cluster trên hệ thống VKS, chúng tôi sẽ tự động tạo một Security Group. Security group này sẽ bao gồm: +| Protocol | Ether type | Port range | Source | Ý nghĩa | +|---|---|---|---|---| +| TCP | IPv4 | 30000-32767 | `` | NodePort Service (TCP) | +| UDP | IPv4 | 30000-32767 | `` | NodePort Service (UDP) | +| TCP | IPv4 | 10250 | `` | Kubelet API | +| TCP | IPv4 | 10250 | `/32` | Kubelet API từ control plane. Chỉ có khi endpoint control plane của cluster là địa chỉ IP | -* Inbound: +### Inbound — bổ sung theo CNI -
ProtocolEther typePort rangeSource
TCP, UDP hoặc ICMPIPv4Port của ServiceSubnet Mask của Subnet mà bạn sử dụng cho Cluster.
+**Calico Overlay** -* Outbound: +| Protocol | Ether type | Port range | Source | Ý nghĩa | +|---|---|---|---|---| +| TCP | IPv4 | 179 | `` | Calico BGP | +| 4 (IP-in-IP) | IPv4 | 1-65535 | `` | Calico IP-in-IP | +| TCP | IPv4 | 5473 | `` | Calico Typha | -
ProtocolEther typePort rangeDestinationÝ nghĩa
ANYIPv40-655350.0.0.0/0Rule mặc định của tất cả Security group
ANYIPv60-65535::/0Rule mặc định của tất cả Security group
+**Cilium Overlay** -### Security group được tạo tự động bởi VNGCLOUD Ingress Controller +| Protocol | Ether type | Port range | Source | Ý nghĩa | +|---|---|---|---|---| +| UDP | IPv4 | 8472 | `` | Cilium VXLAN overlay | +| TCP | IPv4 | 4240 | `` | Cilium health check (TCP) | +| ICMP | IPv4 | 1-255 | `` | Cilium health check (ICMP) | -Khi bạn sử dụng GreenNode Ingress Controller để tích hợp Application Load Balancer với Cluster trên hệ thống VKS, chúng tôi sẽ tự động tạo một Security Group. Security group này sẽ bao gồm: +**Cilium VPC Native Routing** -* Inbound: +| Protocol | Ether type | Port range | Source | Ý nghĩa | +|---|---|---|---|---| +| UDP | IPv4 | 8472 | `` | Cilium VXLAN | +| TCP | IPv4 | 4240 | `` | Cilium health check (TCP) | +| ICMP | IPv4 | 1-255 | `` | Cilium health check (ICMP) | +| TCP | IPv4 | 53 | `` | DNS (TCP) | +| UDP | IPv4 | 53 | `` | DNS (UDP) | -
ProtocolEther typePort rangeSource
TCPIPv4Port của ServiceSubnet Mask của Subnet mà bạn sử dụng cho Cluster.
+### Outbound -* Outbound: +| Protocol | Ether type | Port range | Destination | Ý nghĩa | +|---|---|---|---|---| +| ANY | IPv4 | 0-65535 | 0.0.0.0/0 | Rule mặc định của mọi SG | +| ANY | IPv6 | 0-65535 | ::/0 | Rule mặc định của mọi SG | -
ProtocolEther typePort rangeDestinationÝ nghĩa
ANYIPv40-655350.0.0.0/0Rule mặc định của tất cả Security group
ANYIPv60-65535::/0Rule mặc định của tất cả Security group
+### VKS tự động khôi phục những gì -{% hint style="info" %} -**Chú ý:** +VKS kiểm tra node SG định kỳ: -* Các Security Group mặc định được thiết lập để đáp ứng các nhu cầu bảo mật cơ bản của cluster. Nếu bạn sửa hoặc xóa các Security Group được tạo sẵn cho cluster, có thể dẫn đến các vấn đề về kết nối và truy cập giữa các node trong cluster hoặc cluster có thể không hoạt động chính xác hoặc thậm chí không thể khởi động được. Để đảm bảo tính ổn định và bảo mật của cluster, hệ thống sẽ tự động reset các Security Group về cài đặt mặc định sau mỗi khoảng thời gian cố định. +* **Inbound rule ở các bảng trên bị xoá hoặc sửa:** VKS tạo lại rule còn thiếu. +* **Rule bạn tự thêm** (inbound hoặc outbound): VKS giữ nguyên, không xoá. +* **Outbound rule mặc định:** VKS không quản lý. Nếu bạn xoá, VKS không tạo lại. Xem [Giới hạn outbound cho worker node](security-group/gioi-han-outbound-cho-worker-node.md) trước khi xoá. +* **Cả node SG bị xoá:** VKS tạo một node SG mới (kèm 2 outbound rule allow-all mặc định) và gắn lên các node. Mọi rule bạn tự thêm vào SG cũ, kể cả bộ outbound rule đã giới hạn, sẽ mất và cần cấu hình lại trên SG mới. + +{% hint style="warning" %} +**Không xoá node SG của cluster.** Node SG được xoá cùng cluster. Xoá thủ công khiến cluster mất kết nối giữa các node cho tới khi VKS tạo SG mới, và cấu hình riêng của bạn trên SG cũ bị mất. {% endhint %} + +## SG của load balancer + +Khi bạn tạo Service `type: LoadBalancer` (Network Load Balancer) hoặc Ingress (Application Load Balancer), GreenNode LoadBalancer Controller tạo một SG riêng cho Service/Ingress đó, với mô tả `Automatically created using VNGCLOUD LoadBalancer Controller`. SG được gắn lên tất cả worker node (hoặc chỉ các node khớp annotation `vks.vngcloud.vn/target-node-labels`), kể cả node tạo sau này. + +Trong các bảng dưới, **``** là CIDR của subnet mà load balancer dùng để kết nối tới node (backend subnet). + +### Inbound — Service `LoadBalancer` + +| Trường hợp | Protocol | Port | Source | Ý nghĩa | +|---|---|---|---|---| +| Mặc định (target type `instance`) | Theo protocol của port Service (TCP/UDP) | NodePort của từng port | `` | Load balancer truy cập NodePort | +| Target type `ip` | Theo protocol của port Service (TCP/UDP) | `targetPort` của pod | `` | Load balancer truy cập trực tiếp pod | +| Cluster dùng Cilium VPC Native Routing | Theo protocol của port Service (TCP/UDP) | `targetPort` của pod | Subnet CIDR của mọi node trong cluster | Node chuyển tiếp traffic tới pod ở node khác | +| Có annotation `vks.vngcloud.vn/healthcheck-port` | Theo protocol của port Service | Port health check đã khai báo | `` | Health check port tuỳ chỉnh | +| Service có port UDP | ICMP | 1-255 | Cùng source với rule UDP | Health check cho port UDP | + +### Inbound — Ingress + +Giống Service ở trên, áp dụng cho từng Service backend của Ingress (default backend và mọi path), với protocol luôn là TCP. + +### Outbound + +| Protocol | Ether type | Port range | Destination | Ý nghĩa | +|---|---|---|---|---| +| ANY | IPv4 | 0-65535 | 0.0.0.0/0 | Outbound mặc định | +| ANY | IPv6 | 0-65535 | ::/0 | Outbound mặc định | + +Hai rule outbound này được tắt bằng annotation `vks.vngcloud.vn/enable-default-egress: "false"` trên Service/Ingress (yêu cầu GreenNode LoadBalancer Controller phiên bản `0.5.0` trở lên). Chi tiết tại [Giới hạn outbound cho worker node](security-group/gioi-han-outbound-cho-worker-node.md). + +### VKS tự động khôi phục những gì + +Controller quản lý **toàn bộ** rule (cả inbound và outbound) của SG này: + +* Rule bị sửa hoặc xoá thủ công được khôi phục ở lần đồng bộ định kỳ kế tiếp. Rule bạn tự thêm vào SG này sẽ bị xoá. +* Khi bạn sửa Service/Ingress (port, annotation…), rule được cập nhật theo. +* Khi xoá Service/Ingress, SG được gỡ khỏi các node và bị xoá. + +Vì vậy, **không sửa rule trực tiếp trên portal** cho SG này; luôn cấu hình qua annotation. + +### Dùng SG của bạn thay cho SG tự động + +Thêm annotation `vks.vngcloud.vn/security-groups: ","` vào Service/Ingress: + +* Controller không tạo SG riêng cho Service/Ingress đó; SG tự động đã có trước đó được gỡ khỏi node và xoá. +* Các SG bạn chỉ định được gắn lên các worker node (kể cả node mới) — **không** gắn lên load balancer. +* Controller **không đụng** tới rule của các SG này: bạn tự thêm rule inbound cho port Service (theo bảng trên) và tự quản lý outbound. Annotation `enable-default-egress` không có tác dụng trong trường hợp này. +* Có thể dùng chung một SG cho nhiều Service/Ingress để giảm số SG gắn trên mỗi node. + +{% hint style="info" %} +Annotation `vks.vngcloud.vn/inbound-cidrs` (giới hạn IP client được truy cập load balancer) cấu hình ACL trên listener của load balancer, không thay đổi rule của SG. +{% endhint %} + +## Câu hỏi thường gặp + +**Tôi muốn chặn outbound của worker node ra internet?** +Xem [Giới hạn outbound cho worker node](security-group/gioi-han-outbound-cho-worker-node.md). Cần xử lý outbound trên **mọi** SG gắn trên node, không chỉ node SG. + +**Tôi muốn thêm inbound rule cho ứng dụng (ví dụ mở port cho hệ thống khác trong VPC truy cập node)?** +Thêm rule vào node SG của cluster hoặc vào một SG riêng do bạn tạo và tự gắn lên node. Không thêm vào SG của load balancer vì controller sẽ xoá rule đó. + +**Node mới tạo có tự động có đủ SG không?** +Có. Node SG của cluster và SG của load balancer được gắn tự động lên node mới. SG do bạn tự gắn thủ công lên VM **không** tự gắn lên node mới; dùng annotation `vks.vngcloud.vn/security-groups` nếu cần SG của bạn theo node. diff --git a/Vietnamese/vks/security-group/gioi-han-outbound-cho-worker-node.md b/Vietnamese/vks/security-group/gioi-han-outbound-cho-worker-node.md new file mode 100644 index 000000000..287a36ce5 --- /dev/null +++ b/Vietnamese/vks/security-group/gioi-han-outbound-cho-worker-node.md @@ -0,0 +1,169 @@ +# Giới hạn outbound cho worker node VKS + +Theo mặc định, worker node của cluster VKS được phép truy cập outbound tới mọi destination. Tài liệu này hướng dẫn cấu hình bộ outbound rule **tối thiểu để cluster VKS hoạt động ổn định**. Các destination mà ứng dụng của bạn truy cập không thuộc phạm vi bộ rule này; bạn cần tự bổ sung (xem lưu ý tại Bước 2). + +- **Phạm vi áp dụng:** **private cluster** sử dụng CNI Cilium overlay. Với Calico hoặc Cilium native routing, các bước vẫn áp dụng được; chỉ khác các port giữa các node ở Bước 2 (cách xác định được nêu tại đó). +- **Không áp dụng cho public cluster:** node truy cập dịch vụ VNG Cloud qua public domain, IP address có thể thay đổi bất kỳ lúc nào nên không thể lọc bằng Security Group. +- **Chỉ cần giới hạn egress của pod:** sử dụng `CiliumNetworkPolicy` egress. Phương án này hỗ trợ lọc theo domain (FQDN) và không ảnh hưởng tới các system component. +- **Trách nhiệm:** bạn chịu trách nhiệm quản lý và duy trì bộ outbound rule. Thiếu rule có thể khiến node mới không join được cluster, không pull được image, không tạo được volume hoặc load balancer. + +## Kiến thức cần nắm + +- Outbound traffic của node được cho phép nếu **bất kỳ** Security Group (SG) nào gắn trên VM cho phép. Do đó cần loại bỏ rule outbound allow-all trên **tất cả** SG gắn trên node, không chỉ SG của cluster. +- SG hoạt động theo cơ chế stateful: chỉ cần khai báo rule theo chiều outbound, return traffic được tự động cho phép. +- Mỗi SG khi tạo mới đều có sẵn 2 default rule outbound allow-all: `any → 0.0.0.0/0` và `any → ::/0`. + +Các SG thường gắn trên node VKS: + +| SG | Định dạng tên | Thao tác cần thực hiện | +| --- | --- | --- | +| Node SG của cluster | `vks-user--k8s--…` | Thêm allow rule, xoá 2 default rule (Bước 2–3) | +| SG của load balancer | `vks----…` | Tắt outbound bằng annotation (mục tiếp theo) | +| SG do bạn tự gắn | Theo tên bạn đặt | Xoá 2 default rule | + +## Tắt outbound trên SG của load balancer + +GreenNode LoadBalancer Controller tạo một SG cho mỗi Service `LoadBalancer` và Ingress, sau đó attach SG này lên node. Theo mặc định, SG này allow-all outbound; nếu xoá thủ công, controller sẽ tạo lại. Để tắt, thêm annotation sau vào **tất cả** Service `LoadBalancer` và Ingress: + +```yaml +metadata: + annotations: + vks.vngcloud.vn/enable-default-egress: "false" +``` + +Controller sẽ gỡ 2 outbound rule khỏi SG tương ứng mà không gây downtime cho load balancer. Khi gỡ annotation, 2 rule này được tạo lại. + +> **Không xoá outbound rule trực tiếp trên portal** đối với SG do controller quản lý: controller sẽ tạo lại các rule này ở lần đồng bộ định kỳ kế tiếp. Luôn dùng annotation. + +Annotation yêu cầu GreenNode LoadBalancer Controller phiên bản `0.5.0` trở lên; nếu cluster đang chạy phiên bản cũ hơn, cần upgrade trước. Kiểm tra phiên bản hiện tại: + +```bash +kubectl -n kube-system get deploy -l app.kubernetes.io/name=vngcloud-load-balancer-controller \ + -o jsonpath='{.items[0].spec.template.spec.containers[0].image}'; echo +``` + +**Áp dụng cho mọi Service/Ingress, kể cả các resource tạo mới sau này.** Chỉ cần một Service `LoadBalancer` hoặc Ingress thiếu annotation, outbound của toàn bộ node sẽ được mở lại. Liệt kê các resource còn thiếu annotation (output rỗng nghĩa là đã đầy đủ): + +```bash +kubectl get svc -A -o jsonpath='{range .items[?(@.spec.type=="LoadBalancer")]}{.metadata.namespace}/{.metadata.name} {.metadata.annotations.vks\.vngcloud\.vn/enable-default-egress}{"\n"}{end}' | awk '$2!="false"' +kubectl get ingress -A -o jsonpath='{range .items[*]}{.metadata.namespace}/{.metadata.name} {.spec.ingressClassName}{.metadata.annotations.kubernetes\.io/ingress\.class} {.metadata.annotations.vks\.vngcloud\.vn/enable-default-egress}{"\n"}{end}' | awk '$2=="vngcloud" && $3!="false"' +``` + +## Bước 1: Thu thập thông số cluster + +IP address khác nhau giữa các cluster, vì vậy cần thu thập thông số riêng cho từng cluster. Tạo một debug pod trên node (yêu cầu kubectl 1.28 trở lên; lệnh sử dụng image Cilium có sẵn trên node do private cluster thường không truy cập được Docker Hub): + +```bash +NODE=$(kubectl get nodes -o jsonpath='{.items[0].metadata.name}') +IMG=$(kubectl -n kube-system get ds cilium -o jsonpath='{.spec.template.spec.containers[0].image}') +kubectl debug node/$NODE -it --profile=sysadmin --image=$IMG -- chroot /host bash -c ' + echo "## control plane"; grep "server:" /etc/kubernetes/kubelet.conf + echo "## endpoints"; for h in iamapis.vngcloud.vn hcm-3.api.vngcloud.vn hcm03.vstorage.vngcloud.vn vcr.vngcloud.vn; do + getent ahosts $h | cut -d" " -f1 | sort -u | sed "s/^/$h /"; done + echo "## dns"; resolvectl status | grep -E "DNS Servers|Current DNS" + echo "## ntp"; timedatectl show-timesync -p ServerAddress -p SystemNTPServers + echo "## dhcp"; networkctl status eth0 | grep "DHCP4 via"' +kubectl get pods -o name | grep node-debugger | xargs kubectl delete +``` + +Ghi nhận các giá trị sau: + +| Thông số | Ví dụ | Nguồn | +| --- | --- | --- | +| VPC CIDR | `10.0.0.0/16` | Portal VPC (CIDR của VPC, không phải của subnet) | +| Control plane IP | `10.0.1.3` | Mục `## control plane`. Nếu là hostname, chạy `getent ahosts ` trên node và lấy toàn bộ IP | +| Private endpoint IP | `10.0.1.6` … `10.0.1.9` | Mục `## endpoints`: IAM (`iamapis…`), vServer API (`…api…`), vStorage (`…vstorage…`), vCR (`vcr…`). Cluster multi-AZ có một IP cho mỗi zone, cần lấy toàn bộ. Domain trong lệnh là của region HCM; region khác xem trang Private Service Endpoint trên portal | +| DNS resolver | `8.8.8.8` | Mục `## dns`, lấy toàn bộ IP | +| NTP server | IP NTP server nội bộ | Mục `## ntp`. Nếu là public pool (ví dụ `ntp.ubuntu.com`), IP thay đổi liên tục: chuyển sang NTP server nội bộ hoặc mở `UDP 123 → 0.0.0.0/0` | +| DHCP server | `10.0.1.2` | Mục `## dhcp` | + +## Bước 2: Tạo bộ outbound rule + +Thêm các rule dưới đây vào **node SG**: trên portal vServer, vào **Security Groups**, chọn SG có tên dạng `vks-user--k8s--…`, mở danh sách rule **Outbound** và thêm rule. Giá trị trong `< >` lấy từ Bước 1, mỗi IP tương ứng một rule dạng `/32`. Cột "Type" là rule type cần chọn trên portal. Lưu ý: type **DNS** trên portal chỉ mở TCP, vì vậy cần thêm một rule **Custom UDP** cho DNS. + +**Phương án 1 (khuyến nghị): allow toàn bộ traffic trong VPC, chặn traffic ra ngoài VPC.** + +| # | Type | Port | Destination | Mục đích | +| --- | --- | --- | --- | --- | +| 1 | All Traffic | – | `` | Control plane, private endpoint, DHCP, traffic giữa các node | +| 2 | HTTP | 80 | `169.254.169.254/32` | Metadata service, dùng khi node bootstrap và khi CSI/LB controller khởi động | +| 3 | DNS **và** Custom UDP | 53 | `/32` | DNS resolution | +| 4 | Custom UDP | 123 | `/32` | Time sync | + +Xác nhận control plane IP, 4 private endpoint IP và DHCP server đều thuộc ``. IP nào nằm ngoài range này cần thêm rule riêng theo bảng của Phương án 2. Nếu DNS resolver và NTP server thuộc VPC thì không cần rule 3 và 4. + +
+Phương án 2: chỉ mở các port cần thiết (thay cho rule 1) + +| Type | Port | Destination | Mục đích | +| --- | --- | --- | --- | +| Custom TCP | 6443 | `/32` | Kubernetes API server | +| Custom TCP | 8132 | `/32` | `kubectl logs/exec`, admission webhook | +| HTTPS | 443 | `/32` | Authentication cho CSI và LB controller | +| HTTPS | 443 | `/32` | Attach volume, tạo load balancer | +| HTTPS | 443 | `/32` | Pull system image | +| HTTPS | 443 | `/32` | vStorage | +| Custom UDP | 67 | `/32` | DHCP lease renewal. Thiếu rule này, node vẫn nhận IP khi khởi động nhưng không renew lease định kỳ được | +| Custom UDP | 8472 | `` | VXLAN tunnel giữa các node (pod-to-pod traffic) | +| Custom TCP | 4240 | `` | Cilium health check | +| All ICMP | – | `` | Health check, Path MTU Discovery | +| Custom TCP | 10250 | `` | Kubelet API giữa các node | +| Custom TCP | 4244 | `` | Hubble | + +Bốn rule cuối với destination `` áp dụng cho Cilium overlay. Với CNI khác, sao chép các inbound rule mà VKS đã tạo trên node SG sang chiều outbound (cùng protocol, cùng port, destination ``). + +
+ +> **Lưu ý về destination của ứng dụng.** Bộ rule trên chỉ đáp ứng nhu cầu của cluster VKS. Sau khi xoá default outbound rule, mọi connection từ ứng dụng tới destination **ngoài VPC** (với Phương án 2 là cả destination trong VPC) sẽ bị chặn nếu không có rule tương ứng, ví dụ: database hoặc API ngoài VPC, image registry private hoặc public (Docker Hub, ghcr.io…), Git, logging/monitoring backend, dịch vụ SaaS. Hãy rà soát và bổ sung rule cho các destination này trước khi apply. +> +> Các destination sử dụng CDN (Docker Hub, ghcr.io, quay.io và phần lớn dịch vụ SaaS) thay đổi IP liên tục, nên rule theo IP sẽ mất hiệu lực sau một thời gian ngắn. Khuyến nghị mirror image về vCR, và truy cập dịch vụ SaaS qua proxy hoặc `CiliumNetworkPolicy` `toFQDNs`. + +## Bước 3: Apply + +Nguyên tắc: thêm allow rule trước, xoá rule allow-all sau cùng. Thực hiện trên cluster dev/staging có cùng cấu hình trước khi apply cho production. + +1. Backup cấu hình hiện tại: danh sách SG trên từng VM node và toàn bộ rule của các SG đó. +2. Thêm toàn bộ rule ở Bước 2, cùng các rule cho destination của ứng dụng, vào node SG. Chưa xoá rule nào. +3. Thêm annotation `enable-default-egress: "false"` vào tất cả Service `LoadBalancer` và Ingress (xem mục "Tắt outbound trên SG của load balancer"). Bước này phải thực hiện **sau** bước 2: nếu node SG còn thiếu rule và cluster đang hoạt động nhờ outbound của SG load balancer, việc tắt outbound này sẽ gây downtime ngay lập tức. +4. Trong maintenance window (khung giờ thấp điểm), xoá 2 default outbound rule (`::/0` trước, `0.0.0.0/0` sau) trên node SG và các SG bạn tự gắn. +5. Verify ngay theo Bước 4. Nếu phát sinh lỗi, rollback trước rồi mới điều tra nguyên nhân. + +Các connection đang mở có thể tiếp tục hoạt động; chỉ các connection **mới** bị chặn. Cần monitor ít nhất một chu kỳ nghiệp vụ. Cluster tạo mới hoặc tạo lại sẽ có node SG mới, cần thực hiện lại từ Bước 1. + +## Bước 4: Verify + +- [ ] **Xác nhận outbound đã bị chặn:** connection tới một destination không có trong rule phải bị timeout: `kubectl run egresstest --rm -it --restart=Never --image= -- curl -m 5 -sS https://1.1.1.1`. Nếu VPC không có route ra internet, phép thử này luôn timeout và không có ý nghĩa; khi đó hãy thử với một destination trong VPC chưa được mở rule. +- [ ] Tất cả node ở trạng thái `Ready`; `kubectl logs`, `kubectl exec` hoạt động bình thường. +- [ ] DNS resolution trong pod hoạt động với cả internal domain của cluster và external domain mà ứng dụng sử dụng. +- [ ] Pull được image mới (deploy thử với `imagePullPolicy: Always`). +- [ ] Restart CSI và LB controller, các pod chuyển sang `Running`: `kubectl -n kube-system get deploy,ds -o name | grep -E 'csi|load-balancer' | xargs -n1 kubectl -n kube-system rollout restart` +- [ ] Tạo được PVC và mount vào pod. +- [ ] Tạo được Service `LoadBalancer` có annotation và nhận được external address; thực hiện lại phép thử ở mục đầu tiên: kết quả vẫn timeout. +- [ ] DHCP lease renewal thành công: trong debug pod ở Bước 1, chạy `networkctl renew eth0`; sau vài giây, `ip -4 addr show eth0` hiển thị `valid_lft` trở về gần lease time đầy đủ (thường là 86400s). +- [ ] Scale node group thêm 1 node: node mới chuyển sang `Ready` trong thời gian bình thường. Sau đó scale về như cũ. +- [ ] Ứng dụng hoạt động đúng nghiệp vụ: database connection, API call, đẩy log và metric, scheduled job. + +## Rollback + +Thêm lại rule sau vào node SG để đưa cluster về trạng thái ban đầu, không cần restart node hay pod: + +| Type | Port | Destination | +| --- | --- | --- | +| All Traffic | – | `0.0.0.0/0` | + +Pod gặp lỗi trong thời gian thiếu rule sẽ tự retry. Node được tạo trong thời gian thiếu rule (ví dụ khi scale) không tự phục hồi sau khi thêm rule rollback; cần thay thế node đó. Sau khi xác định và bổ sung rule còn thiếu, xoá rule rollback. + +## Troubleshooting + +| Symptom | Nguyên nhân thường gặp | +| --- | --- | +| Node mới không chuyển sang `Ready`, liên tục bị thay thế | Thiếu rule tới metadata service `169.254.169.254`, control plane (6443), vCR hoặc DNS | +| CSI hoặc LB controller ở trạng thái `CrashLoopBackOff` | Thiếu rule tới metadata service, IAM hoặc vServer API | +| Pod trên các node khác nhau không kết nối được với nhau, node `NotReady` | Thiếu rule giữa các node (UDP 8472, TCP 4240, ICMP) | +| `kubectl logs/exec` bị timeout | Thiếu rule TCP 8132 tới control plane | +| `ImagePullBackOff` | Thiếu rule tới vCR (system image) hoặc registry chứa image của ứng dụng | +| PVC ở trạng thái `Pending`, Service `LoadBalancer` không nhận được external address | Thiếu rule tới IAM hoặc vServer API | +| Lỗi TLS certificate "not yet valid"/"expired" sau vài ngày | Thiếu rule tới NTP server | +| `networkctl renew eth0` trên node không renew được lease | Thiếu rule DHCP (UDP 67) | +| Đã xoá rule nhưng node vẫn truy cập được internet | Còn SG khác allow outbound, thường là SG của Service/Ingress thiếu annotation `enable-default-egress: "false"` | +| Ứng dụng không kết nối được tới database, API, registry… ngoài VPC | Thiếu rule cho destination của ứng dụng (xem lưu ý tại Bước 2) |