Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions charts/linkerd-control-plane/templates/destination-rbac.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,29 @@ webhooks:
- serverauthorizations
- servers
- egressnetworks
sideEffects: None
- name: linkerd-policy-validator-gateway.linkerd.io
namespaceSelector:
{{- toYaml .Values.policyValidator.namespaceSelector | trim | nindent 4 }}
{{- if .Values.policyValidator.skipLabeledGatewayAPIRoutes }}
objectSelector:
matchExpressions:
- key: config.linkerd.io/policy-validation
operator: NotIn
values:
- disabled
{{- end }}
clientConfig:
service:
name: linkerd-policy-validator
namespace: {{ .Release.Namespace }}
path: "/"
{{- if and (empty .Values.policyValidator.injectCaFrom) (empty .Values.policyValidator.injectCaFromSecret) }}
caBundle: {{ ternary (b64enc (trim $ca.Cert)) (b64enc (trim .Values.policyValidator.caBundle)) (empty .Values.policyValidator.caBundle) }}
{{- end }}
failurePolicy: {{.Values.webhookFailurePolicy}}
admissionReviewVersions: ["v1", "v1beta1"]
rules:
- operations: ["CREATE", "UPDATE"]
apiGroups: ["gateway.networking.k8s.io"]
apiVersions: ["*"]
Expand Down
3 changes: 3 additions & 0 deletions charts/linkerd-control-plane/templates/destination.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -356,6 +356,9 @@ spec:
{{- if .Values.policyController.probeNetworks }}
- --probe-networks={{.Values.policyController.probeNetworks | join ","}}
{{- end}}
{{- if .Values.policyValidator.skipLabeledGatewayAPIRoutes }}
- --skip-labeled-gateway-api-routes
{{- end}}
{{- range .Values.policyController.additionalArgs }}
- {{ . }}
{{- end }}
Expand Down
10 changes: 10 additions & 0 deletions charts/linkerd-control-plane/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -647,6 +647,16 @@ policyValidator:
values:
- disabled

# -- Skip Gateway API routes (HTTPRoute, GRPCRoute, TLSRoute, TCPRoute) labeled with
# 'config.linkerd.io/policy-validation: disabled' from both webhook validation and
# policy controller watches. Use this to exclude Gateway API routes with unsupported
# features (e.g., v1.3+ CORS filter).
#
# To use this feature:
# 1. Set this to true
# 2. Label routes you want to skip: config.linkerd.io/policy-validation: disabled
skipLabeledGatewayAPIRoutes: false

# -- Certificate for the policy validator. If not provided and not using an external secret
# then Helm will generate one.
crtPEM: |
Expand Down
11 changes: 9 additions & 2 deletions pkg/healthcheck/healthcheck.go
Original file line number Diff line number Diff line change
Expand Up @@ -1781,8 +1781,15 @@ func (hc *HealthChecker) fetchWebhookCaBundle(ctx context.Context, webhook strin
return nil, err
}

if len(vwc.Webhooks) != 1 {
return nil, fmt.Errorf("expected 1 webhooks, found %d", len(vwc.Webhooks))
// Policy validator has 2 webhooks (one for policy.linkerd.io, one for gateway.networking.k8s.io)
// Service profile validator has 1 webhook
expectedWebhooks := 1
if webhook == k8s.PolicyValidatorWebhookConfigName {
expectedWebhooks = 2
}

if len(vwc.Webhooks) != expectedWebhooks {
return nil, fmt.Errorf("expected %d webhooks, found %d", expectedWebhooks, len(vwc.Webhooks))
}

caBundle, err := tls.DecodePEMCertificates(string(vwc.Webhooks[0].ClientConfig.CABundle))
Expand Down
24 changes: 20 additions & 4 deletions policy-controller/runtime/src/args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,12 @@ pub struct Args {

#[clap(long, default_value = "linkerd-egress")]
global_egress_network_namespace: String,

/// Skip Gateway API routes labeled with 'config.linkerd.io/policy-validation: disabled'
/// from being watched and validated. Use this to skip Gateway API routes with
/// unsupported features (e.g., v1.3+ CORS filter).
#[clap(long)]
skip_labeled_gateway_api_routes: bool,
}

impl Args {
Expand Down Expand Up @@ -121,6 +127,7 @@ impl Args {
patch_timeout_ms,
allow_l5d_request_headers,
global_egress_network_namespace,
skip_labeled_gateway_api_routes,
} = self;

let server = if admission_controller_disabled {
Expand Down Expand Up @@ -265,6 +272,15 @@ impl Args {
.push(status_index.clone())
.shared();

// Configure Gateway API resource watches to skip labeled routes
let gateway_watcher_config = if skip_labeled_gateway_api_routes {
let selector = "config.linkerd.io/policy-validation!=disabled";
info!(%selector, "Skipping Gateway API routes with label config.linkerd.io/policy-validation=disabled");
watcher::Config::default().labels(selector)
} else {
watcher::Config::default()
};

if api_resource_exists::<k8s::policy::HttpRoute>(&runtime.client()).await {
let http_routes =
runtime.watch_all::<k8s::policy::HttpRoute>(watcher::Config::default());
Expand All @@ -281,7 +297,7 @@ impl Args {

if api_resource_exists::<gateway::HTTPRoute>(&runtime.client()).await {
let gateway_http_routes =
runtime.watch_all::<gateway::HTTPRoute>(watcher::Config::default());
runtime.watch_all::<gateway::HTTPRoute>(gateway_watcher_config.clone());
tokio::spawn(
kubert::index::namespaced(http_routes_indexes, gateway_http_routes)
.instrument(info_span!("httproutes.gateway.networking.k8s.io")),
Expand All @@ -294,7 +310,7 @@ impl Args {

if api_resource_exists::<gateway::GRPCRoute>(&runtime.client()).await {
let gateway_grpc_routes =
runtime.watch_all::<gateway::GRPCRoute>(watcher::Config::default());
runtime.watch_all::<gateway::GRPCRoute>(gateway_watcher_config.clone());
let gateway_grpc_routes_indexes = IndexList::new(outbound_index.clone())
.push(inbound_index.clone())
.push(status_index.clone())
Expand All @@ -310,7 +326,7 @@ impl Args {
}

if api_resource_exists::<gateway::TLSRoute>(&runtime.client()).await {
let tls_routes = runtime.watch_all::<gateway::TLSRoute>(watcher::Config::default());
let tls_routes = runtime.watch_all::<gateway::TLSRoute>(gateway_watcher_config.clone());
let tls_routes_indexes = IndexList::new(status_index.clone())
.push(outbound_index.clone())
.shared();
Expand All @@ -325,7 +341,7 @@ impl Args {
}

if api_resource_exists::<gateway::TCPRoute>(&runtime.client()).await {
let tcp_routes = runtime.watch_all::<gateway::TCPRoute>(watcher::Config::default());
let tcp_routes = runtime.watch_all::<gateway::TCPRoute>(gateway_watcher_config.clone());
let tcp_routes_indexes = IndexList::new(status_index.clone())
.push(outbound_index.clone())
.shared();
Expand Down