1"use strict";(self.webpackChunkcloudanix_dotcom_docs_temp=self.webpackChunkcloudanix_dotcom_docs_temp||[]).push([["122921"],{709380(e,n,a){a.r(n),a.d(n,{metadata:()=>s,default:()=>m,frontMatter:()=>t,contentTitle:()=>o,toc:()=>d,assets:()=>c});var s=JSON.parse('{"id":"aws/audit/awskubernetesmisconfig/rules/aws_mutable_tag_pullpolicy_always","title":"Mutable Image Tags Should Use imagePullPolicy Always","description":"Verifies containers on mutable tags set imagePullPolicy: Always so a node cannot silently run a stale cached image.","source":"@site/docs/aws/audit/awskubernetesmisconfig/rules/aws_mutable_tag_pullpolicy_always.mdx","sourceDirName":"aws/audit/awskubernetesmisconfig/rules","slug":"/aws/audit/awskubernetesmisconfig/rules/aws_mutable_tag_pullpolicy_always","permalink":"/docs/aws/audit/awskubernetesmisconfig/rules/aws_mutable_tag_pullpolicy_always","draft":false,"unlisted":false,"editUrl":"https://github.com/Cloudanix/cloudanix-dotcom-docs/edit/main/docs/aws/audit/awskubernetesmisconfig/rules/aws_mutable_tag_pullpolicy_always.mdx","tags":[],"version":"current","frontMatter":{"title":"Mutable Image Tags Should Use imagePullPolicy Always","sidebar_label":"Mutable Image Tags Should Use imagePullPolicy Always","description":"Verifies containers on mutable tags set imagePullPolicy: Always so a node cannot silently run a stale cached image."},"sidebar":"docsSidebar","previous":{"title":"Multi-Replica Deployments Should Have A PodDisruptionBudget","permalink":"/docs/aws/audit/awskubernetesmisconfig/rules/aws_multireplica_poddisruptionbudget"},"next":{"title":"Tenant Namespaces Should Have A ResourceQuota","permalink":"/docs/aws/audit/awskubernetesmisconfig/rules/aws_namespace_resourcequota"}}'),l=a(474848),i=a(28453);let t={title:"Mutable Image Tags Should Use imagePullPolicy Always",sidebar_label:"Mutable Image Tags Should Use imagePullPolicy Always",description:"Verifies containers on mutable tags set imagePullPolicy: Always so a node cannot silently run a stale cached image."},o,c={},d=[{value:"More Info:",id:"more-info",level:3},{value:"Risk Level",id:"risk-level",level:3},{value:"Address",id:"address",level:3},{value:"Compliance Standards",id:"compliance-standards",level:3},{value:"Triage and Remediation",id:"triage-and-remediation",level:3},{value:"Remediation",id:"remediation",level:3}];function r(e){let n={code:"code",h3:"h3",li:"li",ol:"ol",p:"p",pre:"pre",ul:"ul",...(0,i.R)(),...e.components},{Accordion:a,AccordionGroup:s,Tab:t,Tabs:o}=n;return a||p("Accordion",!0),s||p("AccordionGroup",!0),t||p("Tab",!0),o||p("Tabs",!0),(0,l.jsxs)(l.Fragment,{children:[(0,l.jsx)(n.h3,{id:"more-info",children:"More Info:"}),"\n",(0,l.jsx)(n.p,{children:"Verifies containers on mutable tags set imagePullPolicy: Always so a node cannot silently run a stale cached image."}),"\n",(0,l.jsx)(n.h3,{id:"risk-level",children:"Risk Level"}),"\n",(0,l.jsx)(n.p,{children:"Low"}),"\n",(0,l.jsx)(n.h3,{id:"address",children:"Address"}),"\n",(0,l.jsx)(n.p,{children:"Security"}),"\n",(0,l.jsx)(n.h3,{id:"compliance-standards",children:"Compliance Standards"}),"\n",(0,l.jsxs)(n.ul,{children:["\n",(0,l.jsx)(n.li,{children:"Cloudanix Best Practice"}),"\n"]}),"\n",(0,l.jsx)(n.h3,{id:"triage-and-remediation",children:"Triage and Remediation"}),"\n",(0,l.jsx)(o,{children:(0,l.jsxs)(t,{title:"Remediation",children:[(0,l.jsx)(n.h3,{id:"remediation",children:"Remediation"}),(0,l.jsxs)(s,{children:[(0,l.jsx)(a,{title:"Manual Steps",defaultOpen:"true",children:(0,l.jsxs)(n.ol,{children:["\n",(0,l.jsxs)(n.li,{children:["\n",(0,l.jsx)(n.p,{children:"Identify noncompliant Pods"}),"\n",(0,l.jsxs)(n.ul,{children:["\n",(0,l.jsxs)(n.li,{children:["Run on any machine with kubectl access:","\n",(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-sh",children:'kubectl get pods --all-namespaces -o json | jq -r \'\n [ .items[]\n | select(.metadata.namespace as $n | ["kube-system","kube-public","kube-node-lease"] | index($n) | not)\n | .metadata as $m\n | (.spec.nodeName // "") as $node\n | (($m.labels // {}) | to_entries | map("\\(.key):\\(.value)") | join(",")) as $labels\n | ([ ($m.ownerReferences // [])[] | select(.controller) ] | first) as $own\n | ((.spec.containers // []) + (.spec.initContainers // []))[]\n | .image as $img\n | (($img | contains("@")) or (($img | split("/") | last | contains(":")) and (($img | endswith(":latest")) | not))) as $immutable\n | ($immutable or (.imagePullPolicy == "Always")) as $ok\n | "kind=Pod ns=\\($m.namespace) name=\\($m.name) uid=\\($m.uid) apiVersion=v1"\n + " container=\\(.name) image=\\($img) imagePullPolicy=\\(.imagePullPolicy // "unset")"\n + " is_compliant=\\(if $ok then "true" else "false" end)"\n ][]\' | grep \'is_compliant=false\'\n'})}),"\n"]}),"\n"]}),"\n"]}),"\n",(0,l.jsxs)(n.li,{children:["\n",(0,l.jsx)(n.p,{children:"Decide how the Pod is managed"}),"\n",(0,l.jsxs)(n.ul,{children:["\n",(0,l.jsxs)(n.li,{children:["For each noncompliant line, note the ",(0,l.jsx)(n.code,{children:"owner="})," field (if present):","\n",(0,l.jsxs)(n.ul,{children:["\n",(0,l.jsxs)(n.li,{children:["If ",(0,l.jsx)(n.code,{children:"owner="})," shows a controller (Deployment, StatefulSet, DaemonSet, Job, CronJob, ReplicaSet, etc.), you must fix that controller\u2019s manifest, not the Pod directly."]}),"\n",(0,l.jsxs)(n.li,{children:["If there is no ",(0,l.jsx)(n.code,{children:"owner="})," field, the Pod is standalone and can be edited directly."]}),"\n"]}),"\n"]}),"\n"]}),"\n"]}),"\n",(0,l.jsxs)(n.li,{children:["\n",(0,l.jsxs)(n.p,{children:["Edit the owning controller manifest to set ",(0,l.jsx)(n.code,{children:"imagePullPolicy: Always"})," (preferred)"]}),"\n",(0,l.jsxs)(n.ul,{children:["\n",(0,l.jsxs)(n.li,{children:["Run on any machine with kubectl access; example for a Deployment (adapt kind/namespace/name as needed):","\n",(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-sh",children:"kubectl -n <namespace> get deployment <name> -o yaml > /tmp/deploy-<name>.yaml\n"})}),"\n"]}),"\n",(0,l.jsxs)(n.li,{children:["Open ",(0,l.jsx)(n.code,{children:"/tmp/deploy-<name>.yaml"})," in an editor and, under every ",(0,l.jsx)(n.code,{children:"spec.template.spec.containers[]"})," and ",(0,l.jsx)(n.code,{children:"spec.template.spec.initContainers[]"})," entry that uses a mutable image tag (e.g. ",(0,l.jsx)(n.code,{children:"image: repo/app:latest"})," or untagged), add or change:","\n",(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-yaml",children:"imagePullPolicy: Always\n"})}),"\n"]}),"\n",(0,l.jsxs)(n.li,{children:["Apply the updated manifest:","\n",(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-sh",children:"kubectl apply -f /tmp/deploy-<name>.yaml\n"})}),"\n"]}),"\n",(0,l.jsxs)(n.li,{children:["Repeat for other controller types (StatefulSet, DaemonSet, Job, CronJob) using the corresponding ",(0,l.jsx)(n.code,{children:"kubectl get <kind>"})," and ",(0,l.jsx)(n.code,{children:"kubectl apply -f"})," commands."]}),"\n"]}),"\n"]}),"\n",(0,l.jsxs)(n.li,{children:["\n",(0,l.jsxs)(n.p,{children:["Edit standalone Pods (if any) to set ",(0,l.jsx)(n.code,{children:"imagePullPolicy: Always"})]}),"\n",(0,l.jsxs)(n.ul,{children:["\n",(0,l.jsxs)(n.li,{children:["Run on any machine with kubectl access:","\n",(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-sh",children:"kubectl -n <namespace> get pod <pod-name> -o yaml > /tmp/pod-<pod-name>.yaml\n"})}),"\n"]}),"\n",(0,l.jsxs)(n.li,{children:["In ",(0,l.jsx)(n.code,{children:"/tmp/pod-<pod-name>.yaml"}),", under each affected ",(0,l.jsx)(n.code,{children:"containers[]"})," and ",(0,l.jsx)(n.code,{children:"initContainers[]"})," entry using a mutable image tag, add or change:","\n",(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-yaml",children:"imagePullPolicy: Always\n"})}),"\n"]}),"\n",(0,l.jsxs)(n.li,{children:["Delete and recreate the Pod with the modified manifest:","\n",(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-sh",children:"kubectl -n <namespace> delete pod <pod-name>\nkubectl apply -f /tmp/pod-<pod-name>.yaml\n"})}),"\n"]}),"\n"]}),"\n"]}),"\n",(0,l.jsxs)(n.li,{children:["\n",(0,l.jsx)(n.p,{children:"Confirm Pods are refreshed (for controllers)"}),"\n",(0,l.jsxs)(n.ul,{children:["\n",(0,l.jsxs)(n.li,{children:["After applying controller changes, ensure new Pods are running with updated templates:","\n",(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-sh",children:"kubectl -n <namespace> rollout status deployment/<name>\n"})}),"\n"]}),"\n",(0,l.jsxs)(n.li,{children:["Use the analogous ",(0,l.jsx)(n.code,{children:"rollout status"})," or describe commands for other controller types, as applicable."]}),"\n"]}),"\n"]}),"\n",(0,l.jsxs)(n.li,{children:["\n",(0,l.jsx)(n.p,{children:"Verify compliance"}),"\n",(0,l.jsxs)(n.ul,{children:["\n",(0,l.jsxs)(n.li,{children:["Run on any machine with kubectl access:","\n",(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-sh",children:'kubectl get pods --all-namespaces -o json | jq -r \'\n [ .items[]\n | select(.metadata.namespace as $n | ["kube-system","kube-public","kube-node-lease"] | index($n) | not)\n | .metadata as $m\n | (.spec.nodeName // "") as $node\n | (($m.labels // {}) | to_entries | map("\\(.key):\\(.value)") | join(",")) as $labels\n | ([ ($m.ownerReferences // [])[] | select(.controller) ] | first) as $own\n | ((.spec.containers // []) + (.spec.initContainers // []))[]\n | .image as $img\n | (($img | contains("@")) or (($img | split("/") | last | contains(":")) and (($img | endswith(":latest")) | not))) as $immutable\n | ($immutable or (.imagePullPolicy == "Always")) as $ok\n | "is_compliant=\\(if $ok then "true" else "false" end)"\n ] as $rows\n | if ($rows | map(select(. == "is_compliant=false")) | length) == 0\n then "is_compliant=true"\n else $rows[]\n end\'\n'})}),"\n"]}),"\n",(0,l.jsxs)(n.li,{children:["Confirm the output is ",(0,l.jsx)(n.code,{children:"is_compliant=true"}
1)," and no lines show ",(0,l.jsx)(n.code,{children:"is_compliant=false"}),"."]}),"\n"]}),"\n"]}),"\n"]})}),(0,l.jsxs)(a,{title:"Using kubectl",children:[(0,l.jsx)(n.p,{children:"On any machine with kubectl access:"}),(0,l.jsxs)(n.ol,{children:["\n",(0,l.jsx)(n.li,{children:"Identify non\u2011compliant Pods (for reference)"}),"\n"]}),(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-bash",children:"kubectl get pods --all-namespaces -o wide\n"})}),(0,l.jsxs)(n.ol,{start:"2",children:["\n",(0,l.jsxs)(n.li,{children:["For each affected Pod, edit its manifest to set ",(0,l.jsx)(n.code,{children:"imagePullPolicy: Always"})," on any container using a mutable tag (e.g. ",(0,l.jsx)(n.code,{children:":latest"})," or untagged). This must be done on the owning workload (Deployment, StatefulSet, DaemonSet, Job, CronJob, etc.), not the Pod itself."]}),"\n"]}),(0,l.jsx)(n.p,{children:"Example for a Deployment:"}),(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-bash",children:"kubectl -n YOUR_NAMESPACE get deployment YOUR_DEPLOYMENT -o yaml > /tmp/deploy.yaml\n"})}),(0,l.jsxs)(n.p,{children:["Edit ",(0,l.jsx)(n.code,{children:"/tmp/deploy.yaml"})," so each mutable image has ",(0,l.jsx)(n.code,{children:"imagePullPolicy: Always"}),", for example:"]}),(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-yaml",children:"apiVersion: apps/v1\nkind: Deployment\nmetadata:\n name: YOUR_DEPLOYMENT\n namespace: YOUR_NAMESPACE\nspec:\n template:\n spec:\n containers:\n - name: app\n image: your-registry/your-image:latest\n imagePullPolicy: Always\n - name: sidecar\n image: your-registry/another-image\n imagePullPolicy: Always\n initContainers:\n - name: init-app\n image: your-registry/init-image:latest\n imagePullPolicy: Always\n"})}),(0,l.jsx)(n.p,{children:"Apply the updated manifest:"}),(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-bash",children:"kubectl apply -f /tmp/deploy.yaml\n"})}),(0,l.jsx)(n.p,{children:"Repeat the same pattern for other controller types:"}),(0,l.jsxs)(n.ul,{children:["\n",(0,l.jsxs)(n.li,{children:["\n",(0,l.jsx)(n.p,{children:"StatefulSet:"}),"\n",(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-bash",children:"kubectl -n YOUR_NAMESPACE get statefulset YOUR_STATEFULSET -o yaml > /tmp/ss.yaml\n# edit /tmp/ss.yaml to add imagePullPolicy: Always where needed\nkubectl apply -f /tmp/ss.yaml\n"})}),"\n"]}),"\n",(0,l.jsxs)(n.li,{children:["\n",(0,l.jsx)(n.p,{children:"DaemonSet:"}),"\n",(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-bash",children:"kubectl -n YOUR_NAMESPACE get daemonset YOUR_DAEMONSET -o yaml > /tmp/ds.yaml\n# edit /tmp/ds.yaml to add imagePullPolicy: Always where needed\nkubectl apply -f /tmp/ds.yaml\n"})}),"\n"]}),"\n",(0,l.jsxs)(n.li,{children:["\n",(0,l.jsx)(n.p,{children:"Job:"}),"\n",(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-bash",children:"kubectl -n YOUR_NAMESPACE get job YOUR_JOB -o yaml > /tmp/job.yaml\n# edit /tmp/job.yaml to add imagePullPolicy: Always where needed\nkubectl apply -f /tmp/job.yaml\n"})}),"\n"]}),"\n",(0,l.jsxs)(n.li,{children:["\n",(0,l.jsx)(n.p,{children:"CronJob:"}),"\n",(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-bash",children:"kubectl -n YOUR_NAMESPACE get cronjob YOUR_CRONJOB -o yaml > /tmp/cj.yaml\n# edit /tmp/cj.yaml to add imagePullPolicy: Always where needed\nkubectl apply -f /tmp/cj.yaml\n"})}),"\n"]}),"\n"]}),(0,l.jsx)(n.p,{children:"For Pods created directly (no controller ownerReference), patch them in place (they will not be recreated automatically if deleted):"}),(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-bash",children:"kubectl -n YOUR_NAMESPACE edit pod YOUR_POD\n"})}),(0,l.jsxs)(n.p,{children:["and add ",(0,l.jsx)(n.code,{children:"imagePullPolicy: Always"})," under each container/initContainer using a mutable tag."]}),(0,l.jsxs)(n.ol,{start:"3",children:["\n",(0,l.jsx)(n.li,{children:"Verification"}),"\n"]}),(0,l.jsxs)(n.p,{children:["Run the same compliance check to confirm all remaining mutable-tag containers now have ",(0,l.jsx)(n.code,{children:"imagePullPolicy: Always"}),":"]}),(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-bash",children:'kubectl get pods --all-namespaces -o json | jq -r \'\n [ .items[]\n | select(.metadata.namespace as $n | ["kube-system","kube-public","kube-node-lease"] | index($n) | not)\n | .metadata as $m\n | (.spec.nodeName // "") as $node\n | (($m.labels // {}) | to_entries | map("\\(.key):\\(.value)") | join(",")) as $labels\n | ([ ($m.ownerReferences // [])[] | select(.controller) ] | first) as $own\n | ((.spec.containers // []) + (.spec.initContainers // []))[]\n | .image as $img\n | (($img | contains("@")) or (($img | split("/") | last | contains(":")) and (($img | endswith(":latest")) | not))) as $immutable\n | ($immutable or (.imagePullPolicy == "Always")) as $ok\n | "kind=Pod ns=\\($m.namespace) name=\\($m.name) uid=\\($m.uid) apiVersion=v1"\n + (if ($m.creationTimestamp // "") == "" then "" else " created=\\($m.creationTimestamp)" end)\n + (if $node == "" then "" else " node=\\($node)" end)\n + (if $labels == "" then "" else " labels=\\($labels)" end)\n + (if $own == null then "" else " owner=\\($own.kind)/\\($m.namespace)/\\($own.name)/\\($own.uid)" end)\n + " container=\\(.name) image=\\($img) imagePullPolicy=\\(.imagePullPolicy // "unset")"\n + " is_compliant=\\(if $ok then "true" else "false" end)"\n ] as $rows\n | if ($rows | length) == 0 then "is_compliant=true" else $rows[] end\'\n'})})]}),(0,l.jsx)(a,{title:"Automation",children:(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-bash",children:'#!/usr/bin/env bash\nset -euo pipefail\n\n# Automation for: Mutable Image Tags Should Use imagePullPolicy Always\n# Scope: any machine with kubectl access to the EKS cluster\n\n# REQUIREMENTS:\n# - kubectl configured with cluster-admin or equivalent rights\n# - jq and yq (https://github.com/mikefarah/yq) installed\n# - kubectl must have access to all namespaces you want to fix\n\n# CONFIGURATION\nD
1RY_RUN="${DRY_RUN:-false}" # set DRY_RUN=true to preview changes\nNAMESPACES_EXCLUDE_REGEX=\'^(kube-system|kube-public|kube-node-lease)$\'\n\ntmpdir="$(mktemp -d)"\ntrap \'rm -rf "$tmpdir"\' EXIT\n\nlog() { printf \'%s\\n\' "$*" >&2; }\n\nif ! command -v kubectl >/dev/null 2>&1; then\n log "kubectl not found in PATH"\n exit 1\nfi\nif ! command -v jq >/dev/null 2>&1; then\n log "jq not found in PATH"\n exit 1\nfi\nif ! command -v yq >/dev/null 2>&1; then\n log "yq not found in PATH (https://github.com/mikefarah/yq)"\n exit 1\nfi\n\n# 1. Discover noncompliant Pods (mutable image + imagePullPolicy != Always)\nlog "Discovering noncompliant Pods..."\nnoncompliant_json="$tmpdir/noncompliant-pods.json"\n\nkubectl get pods --all-namespaces -o json > "$tmpdir/all-pods.json"\n\njq \'\n .items[]\n | select(.metadata.namespace | test("\'"$NAMESPACES_EXCLUDE_REGEX"\'") | not)\n | . as $pod\n | ((.spec.containers // []) + (.spec.initContainers // []))[]\n | . as $c\n | .image as $img\n | (($img | contains("@")) or (($img | split("/") | last | contains(":")) and (($img | endswith(":latest")) | not))) as $immutable\n | select(($immutable | not) and (.imagePullPolicy != "Always"))\n | {\n namespace: $pod.metadata.namespace,\n name: $pod.metadata.name,\n container: .name,\n image: .image\n }\n\' "$tmpdir/all-pods.json" > "$noncompliant_json"\n\nif ! [ -s "$noncompliant_json" ]; then\n log "No noncompliant Pods found. Cluster is already compliant."\n exit 0\nfi\n\nlog "Noncompliant containers:"\njq -r \'. | "ns=\\(.namespace) pod=\\(.name) container=\\(.container) image=\\(.image)"\' "$noncompliant_json" | sort -u >&2\n\n# 2. Group by Pod (ns/name)\npod_keys_file="$tmpdir/pod-keys.txt"\njq -r \'.namespace + "/" + .name\' "$noncompliant_json" | sort -u > "$pod_keys_file"\n\n# 3. Patch each Pod manifest: set imagePullPolicy: Always on mutable-tag containers\nwhile IFS=/ read -r ns pod; do\n [ -n "$ns" ] || continue\n\n log "Processing Pod ${ns}/${pod}..."\n\n pod_yaml="$tmpdir/${ns}_${pod}.yaml"\n kubectl get pod "$pod" -n "$ns" -o yaml > "$pod_yaml"\n\n # Build yq expression to update only containers flagged in noncompliant_json\n # For this Pod, build a JSON list of container names needing change\n containers_json="$tmpdir/${ns}_${pod}_containers.json"\n jq --arg ns "$ns" --arg pod "$pod" \'\n select(.namespace == $ns and .name == $pod)\n | .container\n \' "$noncompliant_json" > "$containers_json"\n\n if ! [ -s "$containers_json" ]; then\n log " No matching containers for ${ns}/${pod} in noncompliant list, skipping."\n continue\n fi\n\n # Turn container names into a CSV string for yq\n container_csv="$(tr \'\\n\' \',\' < "$containers_json" | sed \'s/,$//\')"\n\n # Patch spec.containers and spec.initContainers where container name is in list\n patched_yaml="$tmpdir/${ns}_${pod}_patched.yaml"\n yq \'\n . as $root\n | (\n .spec.containers // [] |\n map(\n if (.name | split(",") | inside([\'"$container_csv"\'])) or (("\'"$container_csv"\'" | contains("," + .name + ","))) then\n .imagePullPolicy = "Always"\n else\n .\n end\n )\n ) as $c\n | (\n .spec.initContainers // [] |\n map(\n if (.name | split(",") | inside([\'"$container_csv"\'])) or (("\'"$container_csv"\'" | contains("," + .name + ","))) then\n .imagePullPolicy = "Always"\n else\n .\n end\n )\n ) as $ic\n | $root\n | .spec.containers = $c\n | .spec.initContainers = $ic\n \' "$pod_yaml" > "$patched_yaml"\n\n if [ "$DRY_RUN" = "true" ]; then\n log " DRY_RUN=true, showing diff for ${ns}/${pod}:"\n diff -u "$pod_yaml" "$patched_yaml" || true\n else\n log " Applying patched manifest for ${ns}/${pod}..."\n kubectl apply -n "$ns" -f "$patched_yaml"\n fi\n\ndone < "$pod_keys_file"\n\nif [ "$DRY_RUN" = "true" ]; then\n log "DRY_RUN=true, no changes were applied."\n exit 0\nfi\n\n# 4. Verification (re-run audit logic, but only print remaining noncompliant items)\nlog "Verifying compliance after remediation..."\nverify_output="$tmpdir/verify.txt"\n\nkubectl get pods --all-namespaces -o json | jq -r \'\n [ .items[]\n | select(.metadata.namespace as $n | ["kube-system","kube-public","kube-node-lease"] | index($n) | not)\n | .metadata as $m\n | (.spec.nodeName // "") as $node\n | (($m.labels // {}) | to_entries | map("\\(.key):\\(.value)") | join(",")) as $labels\n | ([ ($m.ownerReferences // [])[] | select(.controller) ] | first) as $own\n | ((.spec.containers // []) + (.spec.initContainers // []))[]\n | .image as $img\n | (($img | contains("@")) or (($img | split("/") | last | contains(":")) and (($img | endswith(":latest")) | not))) as $immutable\n | ($immutable or (.imagePullPolicy == "Always")) as $ok\n | select($ok | not)\n | "kind=Pod ns=\\($m.namespace) name=\\($m.name) uid=\\($m.uid) apiVersion=v1"\n + (if ($m.creationTimestamp // "") == "" then "" else " created=\\($m.creationTimestamp)" end)\n + (if $node == "" then "" else " node=\\($node)" end)\n + (if $labels == "" then "" else " labels=\\($labels)" end)\n + (if $own == null then "" else " owner=\\($own.kind)/\\($m.namespace)/\\($own.name)/\\($own.uid)" end)\n + " container=\\(.name) image=\\($img) imagePullPolicy=\\(.imagePullPolicy // "unset")"\n + " is_compliant=false"\n ] as $rows\n | if ($rows | length) == 0 then "is_compliant=true" else $rows[] end\n\' > "$verify_output"\n\nif grep -q \'is_compliant=false\' "$verify_output"; then\n log "Some Pods are still noncompliant:"\n grep \'is_compliant=false\' "$verify_output" >&2\n exit 2\nelse\n log "Verification successful: is_compliant=true"\n cat "$verify_output"\nfi\n'})})})]})]})})]})}function m(e={}){let{wrapper:n}={...(0,i.R)(),...e.components};return n?(0,l.jsx)(n,{...e,children:(0,l.jsx)(r,{...e})}):r(e)}function p(e,n){throw Error("Expected "+(n?"component":"object")+" `"+e+"` to be defined: you likely forgot to import, pass, or provide it.")}},28453(e,n,a){a.d(n,{R:()=>t,x:()=>o});var s=a(296540);let l={},i=s.createContext(l);function t(e){let n=s.useContext(i);return s.useMemo(function(){return"function"==typeof e?e(n):{...n,...e}},[n,e])}function o(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(l):e.components||l:t(e.components),s.createElement(i.Provider,{value:n},e.children)}}}]);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.