Enable Vpc Flow Logs And Intranode Visibility
More Info:
Enable Vpc Flow Logs And Intranode Visibility To See Pod-Level Traffic, Even For Traffic Within A Worker Node.
Risk Level
Low
Address
Security
Compliance Standards
- CIS GKE
Triage and Remediation
- Remediation
Remediation
Manual Steps
-
Identify the cluster’s VPC network and subnetwork (any machine with gcloud access)
gcloud container clusters describe CLUSTER_NAME \--location LOCATION \--project PROJECT_ID \--format="json(network,subnetwork,networkConfig.enableIntraNodeVisibility)"Note the values of
network,subnetwork, andnetworkConfig.enableIntraNodeVisibility. -
Review whether intranode visibility is already enabled (any machine with gcloud access)
From the previous command’s output, checknetworkConfig.enableIntraNodeVisibility:true→ intranode visibility is enabled.falseornull→ intranode visibility is not enabled; plan if enabling it is acceptable (extra logging, potential cost, and privacy considerations).
-
Check current VPC Flow Logs configuration on the cluster subnet (any machine with gcloud access)
# If subnetwork is a full URL, extract the name and region; otherwise use directly.gcloud compute networks subnets describe SUBNET_NAME \--region SUBNET_REGION \--project PROJECT_ID \--format="json(name,region,enableFlowLogs,logConfig)"Review
enableFlowLogsandlogConfigto understand current logging status and granularity. -
Decide on enabling VPC Flow Logs and intranode visibility
With your security/networking team, determine:- Whether pod‑level and intra‑node traffic visibility is required for your threat model and compliance.
- Acceptable log volume, retention, and access controls in Cloud Logging. If both are required and acceptable, proceed to enable them.
-
Enable VPC Flow Logs on the subnet and intranode visibility on the cluster (any machine with gcloud access)
a. Enable VPC Flow Logs on the subnet:gcloud compute networks subnets update SUBNET_NAME \--region SUBNET_REGION \--project PROJECT_ID \--enable-flow-logsb. Enable intranode visibility on the cluster (this may be a mutating operation on the cluster config):
gcloud container clusters update CLUSTER_NAME \--location LOCATION \--project PROJECT_ID \--enable-intra-node-visibility -
Verify that the configuration change is effective (any machine with gcloud access)
a. Re-run the cluster describe command to confirm intranode visibility:gcloud container clusters describe CLUSTER_NAME \--location LOCATION \--project PROJECT_ID \--format json | jq '.networkConfig.enableIntraNodeVisibility'Ensure the output is
true.
b. Re-run the subnet describe command to confirm flow logs:gcloud compute networks subnets describe SUBNET_NAME \--region SUBNET_REGION \--project PROJECT_ID \--format="json(enableFlowLogs)"Ensure
enableFlowLogsistrue.
Using kubectl
kubectl cannot enable VPC Flow Logs or Intranode Visibility because they are configured on the GCP VPC subnet and GKE cluster network settings via the cloud provider (gcloud/Console/IaC), not via Kubernetes API objects. To remediate this finding, follow the guidance in the Manual Steps section using gcloud or your infrastructure-as-code tooling.
Automation
#!/usr/bin/env bash
#
# Purpose:
# Report VPC Flow Logs and Intra-node visibility status for all GKE clusters
# in a project (and optionally across all projects), so you can review where
# CIS GKE 5.6.1 is not met.
#
# Requirements:
# - Run on any machine with:
# - gcloud CLI configured and authenticated
# - jq installed
# - This script does NOT make changes; it only reports state.
#
# Usage examples:
# PROJECT_ID="my-project" ./check_gke_vpc_flowlogs_intranode.sh
# ALL_PROJECTS=true ./check_gke_vpc_flowlogs_intranode.sh
#
# Notes:
# - Intra-node visibility is a CLUSTER setting.
# - VPC Flow Logs are a SUBNET setting (shared across clusters using it).
set -euo pipefail
ALL_PROJECTS="${ALL_PROJECTS:-false}"
PROJECT_ID="${PROJECT_ID:-}"
if [[ "${ALL_PROJECTS}" != "true" && -z "${PROJECT_ID}" ]]; then
echo "ERROR: Set PROJECT_ID=<project-id> or ALL_PROJECTS=true" >&2
exit 1
fi
# Resolve project list
if [[ "${ALL_PROJECTS}" == "true" ]]; then
mapfile -t PROJECTS < <(gcloud projects list --format="value(projectId)")
else
PROJECTS=("${PROJECT_ID}")
fi
echo "project,location,cluster,network,subnetwork,intra_node_visibility,vpc_flow_logs_enabled"
for P in "${PROJECTS[@]}"; do
# List all GKE clusters in this project (all regions/zones)
mapfile -t CLUSTERS < <(
gcloud container clusters list \
--project "${P}" \
--format="value(name,location)"
)
if [[ "${#CLUSTERS[@]}" -eq 0 ]]; then
continue
fi
for entry in "${CLUSTERS[@]}"; do
CLUSTER_NAME="$(awk '{print $1}' <<< "${entry}")"
LOCATION="$(awk '{print $2}' <<< "${entry}")"
# Describe cluster once
DESC_JSON="$(gcloud container clusters describe "${CLUSTER_NAME}" \
--location "${LOCATION}" \
--project "${P}" \
--format=json)"
NETWORK="$(jq -r '.network' <<< "${DESC_JSON}")"
SUBNETWORK="$(jq -r '.subnetwork' <<< "${DESC_JSON}")"
INTRA_NODE="$(jq -r '.networkConfig.enableIntraNodeVisibility // false' <<< "${DESC_JSON}")"
# SUBNETWORK may be full URL or short name; handle both
if [[ "${SUBNETWORK}" == https://* ]]; then
# Extract region and subnetwork name from selfLink
SUBNET_REGION="$(awk -F'/' '{for (i=1;i<=NF;i++){if($i=="regions"){print $(i+1);exit}}}' <<< "${SUBNETWORK}")"
SUBNET_NAME="$(awk -F'/' '{print $NF}' <<< "${SUBNETWORK}")"
else
# Need region from cluster location; if zonal, convert to region
if [[ "${LOCATION}" =~ ^[a-z]+-[a-z]+[0-9]-[a-z]$ ]]; then
SUBNET_REGION="${LOCATION%-?}"
else
SUBNET_REGION="${LOCATION}"
fi
SUBNET_NAME="${SUBNETWORK}"
fi
# Query subnet for flow logs
FLOW_LOGS="unknown"
if [[ -n "${SUBNET_NAME}" && -n "${SUBNET_REGION}" ]]; then
# If subnet is shared VPC in another project, this may fail; handle gracefully
if SUBNET_JSON="$(gcloud compute networks subnets describe "${SUBNET_NAME}" \
--region "${SUBNET_REGION}" \
--project "${P}" \
--format=json 2>/dev/null)"; then
# For modern API, "enableFlowLogs" or "logConfig.enable"
if jq -e 'has("enableFlowLogs")' >/dev/null 2>&1 <<< "${SUBNET_JSON}"; then
FLOW_LOGS="$(jq -r '.enableFlowLogs // false' <<< "${SUBNET_JSON}")"
elif jq -e '.logConfig.enable' >/dev/null 2>&1 <<< "${SUBNET_JSON}"; then
FLOW_LOGS="$(jq -r '.logConfig.enable // false' <<< "${SUBNET_JSON}")"
else
FLOW_LOGS="false"
fi
else
FLOW_LOGS="unknown-subnet-or-shared-vpc"
fi
fi
echo "${P},${LOCATION},${CLUSTER_NAME},${NETWORK},${SUBNET_NAME},${INTRA_NODE},${FLOW_LOGS}"
done
done
Explanation of output and what indicates a problem:
- Each line is a cluster:
intra_node_visibilityis the value of.networkConfig.enableIntraNodeVisibilityvpc_flow_logs_enabledreflects whether VPC Flow Logs are enabled on the cluster’s subnetwork
For CIS GKE 5.6.1, a cluster is non-compliant / needs review when:
intra_node_visibilityisfalse(ornull), orvpc_flow_logs_enabledisfalseorunknown-subnet-or-shared-vpc
Focus your review on rows where one or both of these columns are not true, and then follow the benchmark remediation manually using gcloud or your IaC to enable:
- Intra-node visibility on the cluster
- VPC Flow Logs on the associated subnetwork