enterprise-2.18.0
April 28, 2025
Linkerd 2.18 is a new major release that adds GitOps-compatible multicluster linking, improved support for the Gateway API, protocol declarations, and a host of other features and bugfixes.
See our Linkerd 2.18 announcement blog post for more details.
Who should upgrade?
This is a feature release. We recommend upgrading to Linkerd 2.18 for customers who want to make use of the new features introduced.
Supported Kubernetes and Gateway API versions
Linkerd 2.18 supports Kubernetes versions 1.22 through 1.32, the latest version available at time of release. (We expect Linkerd 2.18 to be compatible with future versions as they are released.)
Linkerd 2.18 supports Gateway API versions v1.0.0 through v1.2.1, the latest version available at time of release. (We expect Linkerd 2.18 to be compatible with future versions as they are released.)
Upgrade guidance
To upgrade with BEL’s lifecycle automation operator, you will need Buoyant Extension version v0.35.0 or later.
Gateway API changes
This release changes Linkerd’s requirements around the Gateway API in order to provide more flexibility. There are two situations where additional steps will be necessary before an upgrade can proceed:
- If you have Gateway API resources on the cluster and these resources are
owned by something other than Linkerd (e.g. you have previously installed
Linkerd with
enableHttpRoutes=false
), you will need to ensure than the Gateway API version is v1.0.0 or later before upgrading to Linkerd 2.18. - If you have Linkerd installed but do not have the Gateway API resources installed on the cluster (this should be rare), and you are using the CLI to upgrade, you will either need to install the Gateway API resources first, or ensure that you explicitly instruct Linkerd to install the Gateway API resources for you at upgrade time.
In all other Gateway API-related situations, the upgrade process should work seamlessly. In particular, users who use Linkerd to install and manage the Gateway API will see their version of the Gateway API upgraded automatically.
Upgrading Multicluster Link resources
This release improves multicluster capabilities to allow Link resources to be
created purely programmatically. New multicluster Link resources will be created
with the new model. Existing Link resources will continue to function as normal;
however, linkerd check
will warn that these Link resources are of the older
model. After upgrading Linkerd, users may wish to upgrade Link resources when
convenient to avoid this warning. Learn more about how to
upgrade the multicluster extension.
TCP port usage between proxies has changed
In order to facilitate transmission of connection metadata, in Linkerd 2.18, all communication between pairs of proxies now happens over port 4143 exclusively. (Prior to Linkerd 2.18, the proxies would use the destination port.) Customers who have L4 network policies or network monitoring tools that make assumptions about port usage may need to update the configuration of these tools to account for this.
New features
GitOps-compatible multicluster linking
This release improves multicluster Link resources so that they can be created in
a purely declarative manner rather than requiring the use of the
linkerd multicluster link
command, allowing for compatibility with GitOps
approaches. See the
Multicluster doc.
Improved support for the Gateway API
This release updates the Gateway API types to the latest versions and sets the groundwork for no longer installing Gateway API types by default, reducing conflict with other projects as Gateway API adoption spreads. See the Gateway API doc.
Protocol declarations
This release adds protocol declarations, an optional configuration (in the
Service appProtocol
field) which allow users to specify the protocol,
preventing issues with automatic protocol detection under extreme load and
ensuring consistent behavior. See the
Protocol detection doc.
Other notable changes
Federated Service metadata now updates dynamically
In Linkerd 2.18, the labels, annotations, and ports for a federated Service are now updated dynamically to mirror those of the member Service with the oldest (by createdAt timestamp) Link resource. (In earlier versions of Linkerd, this metadata was taken from the member Service that first created the federated Service and was never updated.) See the Federated services doc.
Multicluster service labels and annotations can now be filtered
Users may exclude certain labels and/or annotations from being copied onto mirror services and federated services. This is useful to avoid copying metadata from the remote service that would not be appropriate on the mirror/federated service e.g. labels or annotations which control automation tools like ArgoCD. See the Multicluster doc.
Proxy CPU usage can now be configured in terms of available cores
To improve tuning in CPU-intensive situations, Linkerd 2.18 deprecates the
proxy.cores
configuration value in favor a set of proxy.runtime.workers
configuration values that configure the number of proxy threads. These values
are an alternative to setting CPU limits, and as in previous releases, setting
CPU limits will override them. See the
Configuring proxy concurrency doc.
Breaking changes
Hostname and authority labels are now omitted by default in metrics
In Linkerd 2.18 the hostname
label on egress metrics and the authority
label
on inbound metrics are now omitted by default. This is to prevent situations
where a large number of unique values can blow up proxy memory usage. For use
cases where the cardinality can be controlled, these metrics labels must now be
explicitly enabled. See
here
for the hostname label and
here for the
authority label.
Tracing improvements
With this release, the default tracing protocol has been changed from the (deprecated) OpenCensus to OpenTelemetry. Trace collectors used with Linkerd 2.18 must support the OpenTelemetry protocol. See the Distributed tracing doc.
CVE remediations and updates
- Update Go to 1.24.1 (Backported to enterprise-2.17.1-4)
- Update
jwt
to remediate GHSA-mh63-6h87-95cp (Backported to enterprise-2.17.1-5) - Update
containerd
to remediate GHSA-265r-hfxg-fhmg (Backported to enterprise-2.17.1-5) - Update
libc6
inextension-init
andpolicy-controller
for FIPS, and inproxy
for both non-FIPS and FIPS to remediate CVE-2025-0395 (Backported to enterprise-2.17.1-5) - Update
golang.org/x
deps for GHSA-qxp5-gwg8-xv66 (Backported to enterprise-2.17.1-5) - Update
openssl
to 3.1.8 inextension-init
andpolicy-controller
FIPS images to remediate CVE-2024-9143 and CVE-2024-13176 (Backported to enterprise-2.17.1-4) - Update
libcrypto3
andlibssl3
inproxy-init
for both non-FIPS and FIPS to remediate CVE-2025-26519 (Backported to enterprise-2.17.1-3) - Update Go to 1.23.6 to remediate CVE-2025-22866 (Backported to enterprise-2.17.1-2)
- Update
libcrypto3
andlibssl3
inproxy-init
for both non-FIPS and FIPS to remediate CVE-2024-13176 (Backported to enterprise-2.17.1-1) - Update Go net dependency in
controller
for both non-FIPS and FIPS to remediate GHSA-w32m-9786-jp63 (Backported to enterprise-2.17.0-2) - Update Go crypto dependency in
controller
for both non-FIPS and FIPS to remediate GHSA-v778-237x-gjrc (Backported to enterprise-2.17.0-1)
Full changelog
Control plane
- fix(policy): include TCPRoute policy on opaque appProtocol services by @adleong in #13948
- fix(CLI): Print specific command when prompting to install the Gateway API by @adleong in #13924
- fix(CLI): Check that the Gateway API version includes v1 resources by @adleong in #13938
- feat(tracing): Set correct default port for tracing by @sfleen in #13937
- fix(CLI): streamline error output when gateway api is missing by @adleong in #13912
- feat(multicluster): add –only-controller flag to linkerd mc unlink by @alpeb in #13874
- fix(CLI): Check if installGatewayAPI is true before we error during CRD install by @zaharidichev in #13872
- chore(multicluster): update Prometheus configs and access policy to scrape new multicluster controllers by @alpeb in #13892
- fix(dest): fallback to default proxy inbound port when one could not … by @zaharidichev in #13840
- Remove deprecated ‘authority’ references from tap form by @smuth4 in #13850
- feat(policy): Configure outbound hostname labels in metrics by @sfleen in #13822
- feat(multicluster): add CLI check for legacy service mirror controllers by @alpeb in #13859
- feat(mutlicluster): Add support for excluding labels and annotations from federated and mirror services by @adleong in #13802
- feat(multicluster): add link-gen command, deprecate link and unlink commands by @alpeb in #13858
- feat(CLI): Add errors for invalid Gateway API CRD states by @adleong in #13834
- fix(multicluster): fix stale service resources during event requeue by @adleong in #13849
- feat(multicluster): have linkerd-multicluster chart be responsible for service mirror controllers by @alpeb in #13770
- feat(inject): replace proxy.cores with proxy.runtime.workers by @olix0r in #13767
- feat!(multicluster): Federated services take metadata from member with the oldest Link by @adleong in #13783
- fix(injector): use annotated values for debug container by @vishu42 in #13778
- fix(multicluster): move controller’s permissions from Role to ClusterRole by @alpeb in #13823
- feat(multicluster): Add Link v1alpha3 by @adleong in #13801
- fix(helm): correct installGatewayAPI helm value defaulting by @adleong in #13759
- fix(destination): Do not send admin traffic over opaque transport by @sfleen in #13758
- feat(dest): Default meshed traffic to inbound proxy port by @sfleen in #13715
- feat(policy): Add http protocol configuration by @sfleen in #13721
- feat(destination): introduce transport-protocol outbound TLS mode by @sfleen in #13699
- fix(policy): ensure runtime default features are correct by @olix0r in #13742
- fix(policy): Fix policy controller panic when gateway api is not installed by @adleong in #13741
- feat!(helm): abandon gateway api CRDs after install by @adleong in #13740
- feat!(helm): Add installGatewayAPI helm chart value by @adleong in #13739
- feat(helm): Upgrade Gateway API CRDs to gateway API v1.1.1 by @adleong in #13690
- feat(policy): Add opaque protocol configuration by @sfleen in #13660
- feat(policy): enable kubert runtime metrics by @olix0r in #13675
- feat!(tracing): Change default trace protocol to OpenTelemetry by @sfleen in #13491
- feat(proto-detect): Convert opaque ports to app protocol by @sfleen in #13659
- fix(policy): retry lease creation errors by @olix0r in #13677
- fix(policy): order Server resources deterministically by @olix0r in #13676
- feat(multicluster): propagate service labels to endpoints by @maxbrunet in #13583
- fix(policy): Update outbound policy routes even when parent ref has no port by @adleong in #13584
- Add extra trace attributes from downward API by @sfleen in #13544
- expose issuer certificate TTL as a prometheus metric by @n-oden in #13615
- fix(cli): Don’t require gateway CRDs in linkerd install by @adleong in #13603
- fix(multicluster)!: Link’s probeSpec.period should be formatted as duration by @alpeb in #13586
- chore(just): retry failures when loading pause container by @olix0r in #13415
- feat(helm): Allow specifying podAnnotations per deployment by @mikutas in #13388
- Simplify cni config by @alpeb in #13407
- feat(linkerd-cni): add support for plain iptables commands by @alpeb in #13457
- feat(viz): add option to add labels to web service by @omer2500 in #13305
- fix(helm): add validation for proxyInit.closeWaitTimeoutSecs by @alpeb in #13481
- fix(proxy-injector): handle proxy-log-level with quotes by @olix0r in #13480
- Set minimum TLS version to 1.3 by @sfleen in #13500
- Add pod UID and container name to proxy env by @sfleen in #13501
- Add newlines to port-forward error output by @siggy in #13522
- chore(policy): use rustls-tls instead of openssl-tls by @alpeb in #13502
- chore(dashboard): Make CSWSH protection explicit by @alpeb in #13548
- Relax Pod readiness requirements for destination controller by @tjorri in #13557
Proxy
- fix(client-policy): enable TLS hostnames via overrides by @olix0r in #3871
- chore(deps): group symbolic dependencies by @cratelyn in #3863
- fix(http/prom): record bodies when eos reached by @cratelyn in #3856
- chore(deny): allow Zlib by @olix0r in #3829
- feat(inbound): support unsafe authority labels via configuration by @olix0r in #3830
- feat(app,dns): add prometheus metrics to Dns by @cratelyn in #3822
- fix(dns-resolve): add a lower-bound TTL for dns refreshing by @cratelyn in #3807
- fix(transport): repair IPv6 support by @alpeb in #3793
- chore: use workspace-level package metadata by @cratelyn in #3761
- feat(policy): Allow outbound hostname metrics by @sfleen in #3770
- fix(inbound): correct error message when transport header is missing by @olix0r in #3724
- feat(inbound): include srv_port label in server metrics by @olix0r in #3725
- feat(http/detect)!: error when the socket is closed by @olix0r in #3721
- feat: instrument HTTP protocol detection metrics by @olix0r in #3722
- feat(inbound): instrument transport header metrics by @olix0r in #3723
- feat(outbound): add outbound_tcp_protocol_connections counter by @olix0r in #3733
- chore(linkerd2-proxy): always enable multicore features by @olix0r in #3738
- feat(runtime): support CORES_MIN, CORES_MAX, and CORES_MAX_RATIO by @olix0r in #3731
- fix(inbound): Instrument http requests in tagged transport stack by @sfleen in #3707
- chore(app/spire): make spire compilation possible for non-linux targets by @zaharidichev in #3627
- chore(transport): Ignore TCP_USER_TIMEOUT on non-Linux systems and warn by @zaharidichev in #3628
- chore(transport): Use socket2 to obtain orig_dst by @zaharidichev in #3626
- feat(outbound)!: disable ‘hostname’ metrics label by @olix0r in #3606
- chore(outbound): avoid allocation in TLS route labels by @olix0r in #3605
- Fix missing attributes in OpenTelemetry traces by @sfleen in #3609
- Include pod UID and container name as optional trace labels by @sfleen in #3483
- Support OTEL_RESOURCE_ATTRIBUTES in the proxy by @sfleen in #3580
- metrics: remove authority label on inbound http metrics by @zaharidichev in #3547
- Use correct semantic conventions for trace labels by @sfleen in #3484
Extensions
- Update the linkerd2-cni chart (and the analogous CLI command
linkerd install-cni
) to pull linkerd-cni v1.6.2, which fixes the linkerd-cni daemonset shutdown logic that was leaving nodes in a broken state.