diff --git a/api/v1alpha1/paperclipinstance_types.go b/api/v1alpha1/paperclipinstance_types.go index 0b3890b..ba023c1 100644 --- a/api/v1alpha1/paperclipinstance_types.go +++ b/api/v1alpha1/paperclipinstance_types.go @@ -647,6 +647,15 @@ type K8sExecutionSpec struct { // +optional EgressMode string `json:"egressMode,omitempty"` + // EgressPolicy selects the overall egress posture for tenant sandboxes. + // "allowlist" (default) restricts egress to EgressAllowFQDNs/EgressAllowCIDRs. + // "open-internet" allows public internet on ports 80/443 while blocking + // private ranges, link-local metadata, and CGNAT. + // +kubebuilder:default="allowlist" + // +kubebuilder:validation:Enum=allowlist;open-internet + // +optional + EgressPolicy string `json:"egressPolicy,omitempty"` + // EgressAllowFQDNs is the list of fully-qualified domain names tenant agent // pods may reach (e.g. the LLM gateway and required APIs). Enforced exactly // only under EgressMode "cilium". Maps to PAPERCLIP_K8S_EGRESS_ALLOW_FQDNS diff --git a/charts/paperclip-operator/templates/crds/paperclip.inc_instances.yaml b/charts/paperclip-operator/templates/crds/paperclip.inc_instances.yaml index ea4c1c4..3d0fca8 100644 --- a/charts/paperclip-operator/templates/crds/paperclip.inc_instances.yaml +++ b/charts/paperclip-operator/templates/crds/paperclip.inc_instances.yaml @@ -360,6 +360,17 @@ spec: - standard - cilium type: string + egressPolicy: + default: allowlist + description: |- + EgressPolicy selects the overall egress posture for tenant sandboxes. + "allowlist" (default) restricts egress to EgressAllowFQDNs/EgressAllowCIDRs. + "open-internet" allows public internet on ports 80/443 while blocking + private ranges, link-local metadata, and CGNAT. + enum: + - allowlist + - open-internet + type: string namespacePrefix: description: |- NamespacePrefix is prepended to each derived per-tenant namespace name, diff --git a/config/crd/bases/paperclip.inc_instances.yaml b/config/crd/bases/paperclip.inc_instances.yaml index 39e09dc..1dcb699 100644 --- a/config/crd/bases/paperclip.inc_instances.yaml +++ b/config/crd/bases/paperclip.inc_instances.yaml @@ -354,6 +354,17 @@ spec: - standard - cilium type: string + egressPolicy: + default: allowlist + description: |- + EgressPolicy selects the overall egress posture for tenant sandboxes. + "allowlist" (default) restricts egress to EgressAllowFQDNs/EgressAllowCIDRs. + "open-internet" allows public internet on ports 80/443 while blocking + private ranges, link-local metadata, and CGNAT. + enum: + - allowlist + - open-internet + type: string namespacePrefix: description: |- NamespacePrefix is prepended to each derived per-tenant namespace name, diff --git a/internal/resources/resources_test.go b/internal/resources/resources_test.go index ccffb8f..0c64755 100644 --- a/internal/resources/resources_test.go +++ b/internal/resources/resources_test.go @@ -1455,6 +1455,7 @@ func k8sExecutionInstance(name string) *paperclipv1alpha1.Instance { Backend: "job", RuntimeClassName: "gvisor", EgressMode: "cilium", + EgressPolicy: "open-internet", EgressAllowFQDNs: []string{"api.anthropic.com", "gateway.example.com"}, EgressAllowCIDRs: []string{"10.0.0.0/8"}, NamespacePrefix: "pc-tenant", @@ -1481,6 +1482,7 @@ func TestBuildExecutionEnvVars(t *testing.T) { "PAPERCLIP_K8S_BACKEND": "job", "PAPERCLIP_K8S_RUNTIME_CLASS_NAME": "gvisor", "PAPERCLIP_K8S_EGRESS_MODE": "cilium", + "PAPERCLIP_K8S_EGRESS_POLICY": "open-internet", "PAPERCLIP_K8S_EGRESS_ALLOW_FQDNS": "api.anthropic.com,gateway.example.com", "PAPERCLIP_K8S_EGRESS_ALLOW_CIDRS": "10.0.0.0/8", "PAPERCLIP_K8S_NAMESPACE_PREFIX": "pc-tenant", diff --git a/internal/resources/statefulset.go b/internal/resources/statefulset.go index 40e2b91..79a0f7a 100644 --- a/internal/resources/statefulset.go +++ b/internal/resources/statefulset.go @@ -641,6 +641,9 @@ func buildExecutionEnvVars(instance *paperclipv1alpha1.Instance) []corev1.EnvVar if k.EgressMode != "" { vars = append(vars, corev1.EnvVar{Name: "PAPERCLIP_K8S_EGRESS_MODE", Value: k.EgressMode}) } + if k.EgressPolicy != "" { + vars = append(vars, corev1.EnvVar{Name: "PAPERCLIP_K8S_EGRESS_POLICY", Value: k.EgressPolicy}) + } if len(k.EgressAllowFQDNs) > 0 { vars = append(vars, corev1.EnvVar{ Name: "PAPERCLIP_K8S_EGRESS_ALLOW_FQDNS",