-
Notifications
You must be signed in to change notification settings - Fork 5
fix: security(charts): add IMDS egress NetworkPolicy, remove IMDSv1 g… #192
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,37 @@ | ||||||||||||||||||||
| {{- /* | ||||||||||||||||||||
| Egress NetworkPolicy to mitigate SSRF -> AWS IMDS credential theft (F-17). | ||||||||||||||||||||
|
|
||||||||||||||||||||
| When enabled, this policy blocks egress to the link-local IMDS address | ||||||||||||||||||||
| (169.254.169.254) from every pod deployed by this chart (matched via the | ||||||||||||||||||||
| chart-wide selectorLabels). | ||||||||||||||||||||
|
|
||||||||||||||||||||
| Requires a NetworkPolicy-enforcing CNI (Calico, Cilium, AWS VPC CNI with | ||||||||||||||||||||
| NetworkPolicy support, etc.). Policies that only declare Egress are | ||||||||||||||||||||
| additive — they do not deny unrelated traffic. | ||||||||||||||||||||
| */ -}} | ||||||||||||||||||||
| {{- if .Values.networkPolicy.enabled }} | ||||||||||||||||||||
| apiVersion: networking.k8s.io/v1 | ||||||||||||||||||||
| kind: NetworkPolicy | ||||||||||||||||||||
| metadata: | ||||||||||||||||||||
| name: {{ include "portkey.fullname" . }}-block-imds | ||||||||||||||||||||
| labels: | ||||||||||||||||||||
| {{- include "portkey.labels" . | nindent 4 }} | ||||||||||||||||||||
| spec: | ||||||||||||||||||||
| podSelector: | ||||||||||||||||||||
| matchLabels: | ||||||||||||||||||||
| {{- include "portkey.selectorLabels" . | nindent 6 }} | ||||||||||||||||||||
| policyTypes: | ||||||||||||||||||||
| - Egress | ||||||||||||||||||||
| egress: | ||||||||||||||||||||
| - to: | ||||||||||||||||||||
| - ipBlock: | ||||||||||||||||||||
| cidr: 0.0.0.0/0 | ||||||||||||||||||||
| except: | ||||||||||||||||||||
| - 169.254.169.254/32 | ||||||||||||||||||||
| {{- if .Values.networkPolicy.blockLinkLocal }} | ||||||||||||||||||||
| - 169.254.0.0/16 | ||||||||||||||||||||
| {{- end }} | ||||||||||||||||||||
| {{- with .Values.networkPolicy.additionalBlockedCidrs }} | ||||||||||||||||||||
| {{- toYaml . | nindent 14 }} | ||||||||||||||||||||
| {{- end }} | ||||||||||||||||||||
|
Comment on lines
+35
to
+36
|
||||||||||||||||||||
| {{- toYaml . | nindent 14 }} | |
| {{- end }} | |
| {{- range . }} | |
| {{- if contains ":" . }} | |
| {{- fail (printf "networkPolicy.additionalBlockedCidrs entry %q is IPv6, but charts/portkey-app/templates/networkpolicy.yaml currently renders an IPv4-only ipBlock.cidr (0.0.0.0/0). Use only IPv4 CIDRs here." .) }} | |
| {{- end }} | |
| - {{ . }} | |
| {{- end }} | |
| {{- end }} |
| Original file line number | Diff line number | Diff line change | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -15,6 +15,40 @@ commonLabels: {} | |||||||||||
| # -- Common environment variables that will be applied to all deployments/statefulsets created by the chart. Be careful not to override values already specified by the chart. | ||||||||||||
| commonEnv: [] | ||||||||||||
|
|
||||||||||||
| # -- NetworkPolicy to mitigate SSRF -> AWS IMDS credential theft. | ||||||||||||
| # When enabled, blocks egress to 169.254.169.254 from all pods deployed by this chart. | ||||||||||||
| # Requires a NetworkPolicy-enforcing CNI (Calico, Cilium, etc.). | ||||||||||||
| networkPolicy: | ||||||||||||
| enabled: false | ||||||||||||
| # Also block the full link-local range 169.254.0.0/16. | ||||||||||||
|
||||||||||||
| # Also block the full link-local range 169.254.0.0/16. | |
| # Also block the full link-local range 169.254.0.0/16. | |
| # Warning: enabling this can break NodeLocal DNSCache (commonly 169.254.20.10) | |
| # and other required link-local endpoints. Only enable after verifying your | |
| # cluster does not depend on link-local services for DNS or other networking. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,65 @@ | ||
| {{- /* | ||
| Egress NetworkPolicy to mitigate SSRF -> AWS IMDS credential theft (F-17). | ||
|
|
||
| When enabled, this policy blocks pod egress to the link-local IMDS address | ||
| (169.254.169.254) and, optionally, the full link-local range. It does NOT | ||
| restrict other egress; cluster DNS and normal traffic are allowed via an | ||
| explicit allow-all except-IMDS rule. | ||
|
|
||
| Requires a NetworkPolicy-enforcing CNI (Calico, Cilium, AWS VPC CNI with | ||
| NetworkPolicy support, etc.). Policies that only declare Egress are | ||
| additive — they do not deny unrelated traffic. | ||
| */ -}} | ||
| {{- if .Values.networkPolicy.enabled }} | ||
| apiVersion: networking.k8s.io/v1 | ||
| kind: NetworkPolicy | ||
| metadata: | ||
| name: {{ include "portkeyenterprise.fullname" . }}-block-imds | ||
| labels: | ||
| {{- include "portkeyenterprise.labels" . | nindent 4 }} | ||
| spec: | ||
| podSelector: | ||
| matchLabels: | ||
| {{- include "portkeyenterprise.selectorLabels" . | nindent 6 }} | ||
| policyTypes: | ||
| - Egress | ||
| egress: | ||
| - to: | ||
| - ipBlock: | ||
| cidr: 0.0.0.0/0 | ||
| except: | ||
| - 169.254.169.254/32 | ||
| {{- if .Values.networkPolicy.blockLinkLocal }} | ||
| - 169.254.0.0/16 | ||
| {{- end }} | ||
|
Comment on lines
+31
to
+34
|
||
| {{- with .Values.networkPolicy.additionalBlockedCidrs }} | ||
| {{- toYaml . | nindent 14 }} | ||
| {{- end }} | ||
|
Comment on lines
+27
to
+37
|
||
| {{- if .Values.dataservice.enabled }} | ||
| --- | ||
| apiVersion: networking.k8s.io/v1 | ||
| kind: NetworkPolicy | ||
| metadata: | ||
| name: {{ include "portkeyenterprise.fullname" . }}-{{ .Values.dataservice.name }}-block-imds | ||
| labels: | ||
| {{- include "dataservice.labels" . | nindent 4 }} | ||
| spec: | ||
| podSelector: | ||
| matchLabels: | ||
| {{- include "dataservice.selectorLabels" . | nindent 6 }} | ||
| policyTypes: | ||
| - Egress | ||
| egress: | ||
| - to: | ||
| - ipBlock: | ||
| cidr: 0.0.0.0/0 | ||
| except: | ||
| - 169.254.169.254/32 | ||
| {{- if .Values.networkPolicy.blockLinkLocal }} | ||
| - 169.254.0.0/16 | ||
| {{- end }} | ||
| {{- with .Values.networkPolicy.additionalBlockedCidrs }} | ||
| {{- toYaml . | nindent 14 }} | ||
| {{- end }} | ||
| {{- end }} | ||
| {{- end }} | ||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -165,15 +165,37 @@ podAnnotations: {} | |||||||||||||||||
| podLabels: {} | ||||||||||||||||||
|
|
||||||||||||||||||
| podSecurityContext: {} | ||||||||||||||||||
| # Recommended hardened defaults (uncomment and adapt): | ||||||||||||||||||
| # runAsNonRoot: true | ||||||||||||||||||
| # runAsUser: 1000 | ||||||||||||||||||
| # fsGroup: 2000 | ||||||||||||||||||
| # seccompProfile: | ||||||||||||||||||
| # type: RuntimeDefault | ||||||||||||||||||
|
|
||||||||||||||||||
| securityContext: {} | ||||||||||||||||||
| # capabilities: | ||||||||||||||||||
| # drop: | ||||||||||||||||||
| # - ALL | ||||||||||||||||||
| # Recommended hardened defaults (uncomment and adapt): | ||||||||||||||||||
| # allowPrivilegeEscalation: false | ||||||||||||||||||
| # readOnlyRootFilesystem: true | ||||||||||||||||||
| # runAsNonRoot: true | ||||||||||||||||||
| # runAsUser: 1000 | ||||||||||||||||||
| # capabilities: | ||||||||||||||||||
| # drop: | ||||||||||||||||||
| # - ALL | ||||||||||||||||||
| # seccompProfile: | ||||||||||||||||||
| # type: RuntimeDefault | ||||||||||||||||||
|
|
||||||||||||||||||
| # NetworkPolicy to mitigate SSRF -> AWS IMDS credential theft. | ||||||||||||||||||
| # Blocks pod egress to 169.254.169.254 (EC2 Instance Metadata Service). | ||||||||||||||||||
| # Requires a NetworkPolicy-enforcing CNI (Calico, Cilium, etc.). | ||||||||||||||||||
| networkPolicy: | ||||||||||||||||||
| # Set to true to install egress NetworkPolicies for gateway and dataservice. | ||||||||||||||||||
| enabled: false | ||||||||||||||||||
| # Also block the full link-local range 169.254.0.0/16. | ||||||||||||||||||
|
||||||||||||||||||
| # Also block the full link-local range 169.254.0.0/16. | |
| # WARNING: When enabled, this blocks the full link-local range 169.254.0.0/16. | |
| # This can break clusters that rely on link-local endpoints such as NodeLocal | |
| # DNSCache (commonly 169.254.20.10) and other required local services. | |
| # Only enable this if your cluster does not depend on such endpoints, or if | |
| # required exceptions are handled elsewhere in your NetworkPolicy configuration. |
Copilot
AI
Apr 22, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The values comment suggests adding an IPv6 CIDR (e.g., fd00:ec2::254/128) to networkPolicy.additionalBlockedCidrs, but the rendered policy uses an IPv4 ipBlock (cidr: 0.0.0.0/0). Kubernetes requires ipBlock.except entries to be the same IP family as cidr, so any IPv6 entry here will make the NetworkPolicy invalid and fail to apply. Consider either removing the IPv6 example / explicitly documenting IPv4-only, or adding dual-stack support (separate IPv6 egress rule and separate v6 blocked CIDRs).
| # Additional CIDRs to deny from pod egress (e.g., internal metadata services). | |
| additionalBlockedCidrs: [] | |
| # - 169.254.170.2/32 # ECS task metadata endpoint | |
| # - fd00:ec2::254/128 # IMDS IPv6 | |
| # Additional IPv4 CIDRs to deny from pod egress (e.g., internal metadata services). | |
| # Do not include IPv6 CIDRs here unless the templates are updated with separate IPv6 rules. | |
| additionalBlockedCidrs: [] | |
| # - 169.254.170.2/32 # ECS task metadata endpoint |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
With
blockLinkLocalenabled, this denies all169.254.0.0/16egress. That can break NodeLocal DNSCache (169.254.20.10) and other legitimate link-local traffic. Consider adding an explicit allow rule for NodeLocal DNSCache (ports 53) or documenting the limitation clearly.