Skip to main content

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

Manual Steps
  1. 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, and networkConfig.enableIntraNodeVisibility.

  2. Review whether intranode visibility is already enabled (any machine with gcloud access)
    From the previous command’s output, check networkConfig.enableIntraNodeVisibility:

    • true → intranode visibility is enabled.
    • false or null → intranode visibility is not enabled; plan if enabling it is acceptable (extra logging, potential cost, and privacy considerations).
  3. 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 enableFlowLogs and logConfig to understand current logging status and granularity.

  4. 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.
  5. 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-logs

    b. 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
  6. 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 enableFlowLogs is true.

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_visibility is the value of .networkConfig.enableIntraNodeVisibility
    • vpc_flow_logs_enabled reflects 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_visibility is false (or null), or
  • vpc_flow_logs_enabled is false or unknown-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

Additional Reading: