mirror of
https://github.com/traefik/traefik.git
synced 2026-10-28 08:36:10 +08:00
Support Gateway backend client certificate
This commit is contained in:
1 parent
f1f227eda7
commit
b46d3ea648
19 files changed
+1711
-46
No files matched your search
@@ -140,6 +140,42 @@ spec:
|
||||
from: Same
|
||||
```
|
||||
|
||||
### Backend Client Certificate
|
||||
|
||||
The `tls.backend.clientCertificateRef` field on a `Gateway` (`spec.tls.backend`, a sibling of `spec.listeners`) sets the client certificate that Traefik presents to backends that require mutual TLS (mTLS), as defined by [GEP-3155](https://gateway-api.sigs.k8s.io/geps/gep-3155/).
|
||||
|
||||
Traefik presents the certificate to the backends selected by a [BackendTLSPolicy](https://gateway-api.sigs.k8s.io/reference/api-types/policy/backendtlspolicy/), for `HTTPRoute` and `GRPCRoute` routes.
|
||||
Backends without a `BackendTLSPolicy` are not affected, because the field does not enable TLS by itself.
|
||||
The listeners of a `ListenerSet` use the certificate of their parent `Gateway`.
|
||||
|
||||
The reference must point to a core `Secret` that contains the `tls.crt` and `tls.key` entries.
|
||||
A `Secret` in another namespace requires a [ReferenceGrant](https://gateway-api.sigs.k8s.io/reference/api-types/referencegrant/) in that namespace.
|
||||
|
||||
```yaml
|
||||
---
|
||||
apiVersion: gateway.networking.k8s.io/v1
|
||||
kind: Gateway
|
||||
metadata:
|
||||
name: mtls-gateway
|
||||
namespace: default
|
||||
spec:
|
||||
gatewayClassName: traefik
|
||||
tls:
|
||||
backend:
|
||||
# Presented to every backend selected by a BackendTLSPolicy.
|
||||
clientCertificateRef:
|
||||
name: backend-client-tls
|
||||
# Set namespace only for a Secret in another namespace, which requires a ReferenceGrant.
|
||||
# namespace: certs
|
||||
listeners:
|
||||
- name: http
|
||||
protocol: HTTP
|
||||
port: 80
|
||||
allowedRoutes:
|
||||
namespaces:
|
||||
from: Same
|
||||
```
|
||||
|
||||
### ListenerSets
|
||||
|
||||
Traefik supports [ListenerSet](https://gateway-api.sigs.k8s.io/geps/gep-1713/) resources, which attach additional listeners to an existing `Gateway`.
|
||||
|
||||
Generated
+22
-5
@@ -15,17 +15,17 @@
|
||||
},
|
||||
"nixpkgs-golangci": {
|
||||
"locked": {
|
||||
"lastModified": 1771861243,
|
||||
"narHash": "sha256-mz05b1VyLWoTkNg8iJr3yXFJF7HDlwIUKI3ln39RacY=",
|
||||
"lastModified": 1790981744,
|
||||
"narHash": "sha256-sm6DclXJudZfP/pcDBQQsRqyMxBcQsuw+7yQr4rBBLE=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "80d901ec0377e19ac3f7bb8c035201e2e098cc97",
|
||||
"rev": "55ba7f49ef2962b42cbd126522b7df5f95037679",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "80d901ec0377e19ac3f7bb8c035201e2e098cc97",
|
||||
"rev": "55ba7f49ef2962b42cbd126522b7df5f95037679",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
@@ -45,11 +45,28 @@
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs-shellcheck": {
|
||||
"locked": {
|
||||
"lastModified": 1790981744,
|
||||
"narHash": "sha256-sm6DclXJudZfP/pcDBQQsRqyMxBcQsuw+7yQr4rBBLE=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "55ba7f49ef2962b42cbd126522b7df5f95037679",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "55ba7f49ef2962b42cbd126522b7df5f95037679",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"root": {
|
||||
"inputs": {
|
||||
"nixpkgs": "nixpkgs",
|
||||
"nixpkgs-golangci": "nixpkgs-golangci",
|
||||
"nixpkgs-kct": "nixpkgs-kct"
|
||||
"nixpkgs-kct": "nixpkgs-kct",
|
||||
"nixpkgs-shellcheck": "nixpkgs-shellcheck"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -5,13 +5,17 @@
|
||||
# Main nixpkgs (used for gnused)
|
||||
nixpkgs.url = "https://channels.nixos.org/nixpkgs-unstable/nixexprs.tar.xz";
|
||||
|
||||
# Pinned nixpkgs for kubernetes-controller-tools
|
||||
# Pinned nixpkgs for kubernetes-controller-tools (0.21.0)
|
||||
# Search: https://www.nixhub.io/packages/kubernetes-controller-tools
|
||||
nixpkgs-kct.url = "github:NixOS/nixpkgs/c27cdad491a991b11ed731760aa2ef8db0cb0410";
|
||||
|
||||
# Pinned nixpkgs for golangci-lint
|
||||
# Pinned nixpkgs for golangci-lint (2.14.0)
|
||||
# Search: https://www.nixhub.io/packages/golangci-lint
|
||||
nixpkgs-golangci.url = "github:NixOS/nixpkgs/80d901ec0377e19ac3f7bb8c035201e2e098cc97";
|
||||
nixpkgs-golangci.url = "github:NixOS/nixpkgs/55ba7f49ef2962b42cbd126522b7df5f95037679";
|
||||
|
||||
# Pinned nixpkgs for shellcheck (0.11.0)
|
||||
# Search: https://www.nixhub.io/packages/shellcheck
|
||||
nixpkgs-shellcheck.url = "github:NixOS/nixpkgs/55ba7f49ef2962b42cbd126522b7df5f95037679";
|
||||
};
|
||||
|
||||
outputs =
|
||||
@@ -19,24 +23,83 @@
|
||||
nixpkgs,
|
||||
nixpkgs-kct,
|
||||
nixpkgs-golangci,
|
||||
nixpkgs-shellcheck,
|
||||
...
|
||||
}:
|
||||
let
|
||||
inherit (nixpkgs.lib) genAttrs;
|
||||
inherit (nixpkgs.lib) genAttrs attrNames;
|
||||
forEachSystem = genAttrs nixpkgs.lib.systems.flakeExposed;
|
||||
|
||||
pkgsForEach = nixpkgs.legacyPackages;
|
||||
pkgsKctForEach = nixpkgs-kct.legacyPackages;
|
||||
pkgsGolangCiForEach = nixpkgs-golangci.legacyPackages;
|
||||
pkgsShellcheckForEach = nixpkgs-shellcheck.legacyPackages;
|
||||
|
||||
# The CI uses the latest Go patch release (setup-go with check-latest),
|
||||
# which nixpkgs does not always provide yet, so the official binary is used.
|
||||
# Hashes: https://go.dev/dl/?mode=json&include=all
|
||||
goVersion = "1.27.3";
|
||||
goBinaries = {
|
||||
x86_64-linux = {
|
||||
platform = "linux-amd64";
|
||||
sha256 = "65efbc80fdc1fa2cd2631cad5b481777a68e8725f34e89f50fc6ac714e379b40";
|
||||
};
|
||||
aarch64-linux = {
|
||||
platform = "linux-arm64";
|
||||
sha256 = "a06e99309dbcbdca1a8ccd2282c3ee146e55930886e26b4f1193269587165f49";
|
||||
};
|
||||
x86_64-darwin = {
|
||||
platform = "darwin-amd64";
|
||||
sha256 = "b6f8e931e4ab497fcde6da8ae4499a58f9d258e55c8a80824a516eae5950a750";
|
||||
};
|
||||
aarch64-darwin = {
|
||||
platform = "darwin-arm64";
|
||||
sha256 = "dd3908cf20959d798c1e06ebe5b72213f0505ce01373b40ce3110975a6cd99c2";
|
||||
};
|
||||
};
|
||||
|
||||
goForEach =
|
||||
system:
|
||||
let
|
||||
pkgs = pkgsForEach.${system};
|
||||
bin = goBinaries.${system};
|
||||
in
|
||||
pkgs.stdenvNoCC.mkDerivation {
|
||||
pname = "go-bin";
|
||||
version = goVersion;
|
||||
|
||||
src = pkgs.fetchurl {
|
||||
url = "https://go.dev/dl/go${goVersion}.${bin.platform}.tar.gz";
|
||||
inherit (bin) sha256;
|
||||
};
|
||||
|
||||
# The official binaries are used as is, fixup would alter them.
|
||||
dontConfigure = true;
|
||||
dontBuild = true;
|
||||
dontFixup = true;
|
||||
|
||||
installPhase = ''
|
||||
runHook preInstall
|
||||
mkdir -p $out/share $out/bin
|
||||
cp -r . $out/share/go
|
||||
ln -s $out/share/go/bin/go $out/share/go/bin/gofmt $out/bin/
|
||||
runHook postInstall
|
||||
'';
|
||||
};
|
||||
in
|
||||
{
|
||||
devShells = forEachSystem (system: {
|
||||
devShells = genAttrs (attrNames goBinaries) (system: {
|
||||
default = pkgsForEach.${system}.mkShell {
|
||||
packages = [
|
||||
pkgsForEach.${system}.gnused
|
||||
(goForEach system)
|
||||
pkgsKctForEach.${system}.kubernetes-controller-tools
|
||||
pkgsGolangCiForEach.${system}.golangci-lint
|
||||
pkgsShellcheckForEach.${system}.shellcheck
|
||||
];
|
||||
|
||||
# Matches the CI workflows (build, integration and conformance tests).
|
||||
CGO_ENABLED = "0";
|
||||
};
|
||||
});
|
||||
|
||||
|
||||
+6
-6
@@ -1,5 +1,5 @@
|
||||
apiVersion: gateway.networking.k8s.io/v1
|
||||
date: "2026-10-26T10:33:25+01:00"
|
||||
date: "2026-10-26T16:48:00+01:00"
|
||||
gatewayAPIChannel: experimental
|
||||
gatewayAPIVersion: v1.7.0-rc.3
|
||||
implementation:
|
||||
@@ -28,6 +28,7 @@ profiles:
|
||||
- BackendTLSPolicy
|
||||
- BackendTLSPolicySANValidation
|
||||
- GatewayAddressEmpty
|
||||
- GatewayBackendClientCertificate
|
||||
- GatewayFrontendClientCertificateValidation
|
||||
- GatewayFrontendClientCertificateValidationInsecureFallback
|
||||
- GatewayHTTPListenerIsolation
|
||||
@@ -40,7 +41,6 @@ profiles:
|
||||
- ClusterTrustBundle
|
||||
- GatewayAddressRoutability
|
||||
- GatewayAddressRoutabilityCluster
|
||||
- GatewayBackendClientCertificate
|
||||
- GatewayListenerFilters
|
||||
- GatewayRouteHostnameIntersectionPrecedence
|
||||
name: GATEWAY-GRPC
|
||||
@@ -55,12 +55,13 @@ profiles:
|
||||
result: success
|
||||
statistics:
|
||||
Failed: 0
|
||||
Passed: 54
|
||||
Passed: 56
|
||||
Skipped: 0
|
||||
supportedFeatures:
|
||||
- BackendTLSPolicy
|
||||
- BackendTLSPolicySANValidation
|
||||
- GatewayAddressEmpty
|
||||
- GatewayBackendClientCertificate
|
||||
- GatewayFrontendClientCertificateValidation
|
||||
- GatewayFrontendClientCertificateValidationInsecureFallback
|
||||
- GatewayHTTPListenerIsolation
|
||||
@@ -94,7 +95,6 @@ profiles:
|
||||
- ClusterTrustBundle
|
||||
- GatewayAddressRoutability
|
||||
- GatewayAddressRoutabilityCluster
|
||||
- GatewayBackendClientCertificate
|
||||
- GatewayListenerFilters
|
||||
- GatewayRouteHostnameIntersectionPrecedence
|
||||
- HTTPRouteRequestMirror
|
||||
@@ -118,6 +118,7 @@ profiles:
|
||||
Skipped: 0
|
||||
supportedFeatures:
|
||||
- GatewayAddressEmpty
|
||||
- GatewayBackendClientCertificate
|
||||
- GatewayFrontendClientCertificateValidation
|
||||
- GatewayFrontendClientCertificateValidationInsecureFallback
|
||||
- GatewayHTTPListenerIsolation
|
||||
@@ -131,7 +132,6 @@ profiles:
|
||||
- ClusterTrustBundle
|
||||
- GatewayAddressRoutability
|
||||
- GatewayAddressRoutabilityCluster
|
||||
- GatewayBackendClientCertificate
|
||||
- GatewayListenerFilters
|
||||
- GatewayRouteHostnameIntersectionPrecedence
|
||||
name: GATEWAY-TCP
|
||||
@@ -152,6 +152,7 @@ profiles:
|
||||
- BackendTLSPolicy
|
||||
- BackendTLSPolicySANValidation
|
||||
- GatewayAddressEmpty
|
||||
- GatewayBackendClientCertificate
|
||||
- GatewayFrontendClientCertificateValidation
|
||||
- GatewayFrontendClientCertificateValidationInsecureFallback
|
||||
- GatewayHTTPListenerIsolation
|
||||
@@ -166,7 +167,6 @@ profiles:
|
||||
- ClusterTrustBundle
|
||||
- GatewayAddressRoutability
|
||||
- GatewayAddressRoutabilityCluster
|
||||
- GatewayBackendClientCertificate
|
||||
- GatewayListenerFilters
|
||||
- GatewayRouteHostnameIntersectionPrecedence
|
||||
name: GATEWAY-TLS
|
||||
|
||||
+6
-6
@@ -1,5 +1,5 @@
|
||||
apiVersion: gateway.networking.k8s.io/v1
|
||||
date: "2026-10-26T10:40:18+01:00"
|
||||
date: "2026-10-26T16:50:54+01:00"
|
||||
gatewayAPIChannel: experimental
|
||||
gatewayAPIVersion: v1.7.0-rc.3
|
||||
implementation:
|
||||
@@ -31,6 +31,7 @@ profiles:
|
||||
supportedFeatures:
|
||||
- BackendTLSPolicy
|
||||
- BackendTLSPolicySANValidation
|
||||
- GatewayBackendClientCertificate
|
||||
- GatewayFrontendClientCertificateValidation
|
||||
- GatewayFrontendClientCertificateValidationInsecureFallback
|
||||
- GatewayHTTPListenerIsolation
|
||||
@@ -43,7 +44,6 @@ profiles:
|
||||
- GatewayAddressEmpty
|
||||
- GatewayAddressRoutability
|
||||
- GatewayAddressRoutabilityCluster
|
||||
- GatewayBackendClientCertificate
|
||||
- GatewayListenerFilters
|
||||
- GatewayRouteHostnameIntersectionPrecedence
|
||||
- GatewayStaticAddresses
|
||||
@@ -68,11 +68,12 @@ profiles:
|
||||
- GatewayInvalidFrontendClientCertificateValidation
|
||||
statistics:
|
||||
Failed: 0
|
||||
Passed: 47
|
||||
Passed: 49
|
||||
Skipped: 5
|
||||
supportedFeatures:
|
||||
- BackendTLSPolicy
|
||||
- BackendTLSPolicySANValidation
|
||||
- GatewayBackendClientCertificate
|
||||
- GatewayFrontendClientCertificateValidation
|
||||
- GatewayFrontendClientCertificateValidationInsecureFallback
|
||||
- GatewayHTTPListenerIsolation
|
||||
@@ -106,7 +107,6 @@ profiles:
|
||||
- GatewayAddressEmpty
|
||||
- GatewayAddressRoutability
|
||||
- GatewayAddressRoutabilityCluster
|
||||
- GatewayBackendClientCertificate
|
||||
- GatewayListenerFilters
|
||||
- GatewayRouteHostnameIntersectionPrecedence
|
||||
- GatewayStaticAddresses
|
||||
@@ -133,6 +133,7 @@ profiles:
|
||||
Passed: 8
|
||||
Skipped: 1
|
||||
supportedFeatures:
|
||||
- GatewayBackendClientCertificate
|
||||
- GatewayFrontendClientCertificateValidation
|
||||
- GatewayFrontendClientCertificateValidationInsecureFallback
|
||||
- GatewayHTTPListenerIsolation
|
||||
@@ -146,7 +147,6 @@ profiles:
|
||||
- GatewayAddressEmpty
|
||||
- GatewayAddressRoutability
|
||||
- GatewayAddressRoutabilityCluster
|
||||
- GatewayBackendClientCertificate
|
||||
- GatewayListenerFilters
|
||||
- GatewayRouteHostnameIntersectionPrecedence
|
||||
- GatewayStaticAddresses
|
||||
@@ -171,6 +171,7 @@ profiles:
|
||||
supportedFeatures:
|
||||
- BackendTLSPolicy
|
||||
- BackendTLSPolicySANValidation
|
||||
- GatewayBackendClientCertificate
|
||||
- GatewayFrontendClientCertificateValidation
|
||||
- GatewayFrontendClientCertificateValidationInsecureFallback
|
||||
- GatewayHTTPListenerIsolation
|
||||
@@ -185,7 +186,6 @@ profiles:
|
||||
- GatewayAddressEmpty
|
||||
- GatewayAddressRoutability
|
||||
- GatewayAddressRoutabilityCluster
|
||||
- GatewayBackendClientCertificate
|
||||
- GatewayListenerFilters
|
||||
- GatewayRouteHostnameIntersectionPrecedence
|
||||
- GatewayStaticAddresses
|
||||
|
||||
@@ -829,6 +829,7 @@ var (
|
||||
gatewayConditionTypes = []string{
|
||||
string(gatev1.GatewayConditionAccepted),
|
||||
string(gatev1.GatewayConditionProgrammed),
|
||||
string(gatev1.GatewayConditionResolvedRefs),
|
||||
}
|
||||
listenerConditionTypes = []string{
|
||||
string(gatev1.ListenerConditionAccepted),
|
||||
|
||||
@@ -398,6 +398,7 @@ func Test_listenerSetStatusEqual(t *testing.T) {
|
||||
func Test_mergeGatewayStatus(t *testing.T) {
|
||||
accepted := metav1.Condition{Type: string(gatev1.GatewayConditionAccepted), Status: metav1.ConditionTrue}
|
||||
staleAccepted := metav1.Condition{Type: string(gatev1.GatewayConditionAccepted), Status: metav1.ConditionFalse}
|
||||
staleResolvedRefs := metav1.Condition{Type: string(gatev1.GatewayConditionResolvedRefs), Status: metav1.ConditionFalse}
|
||||
listenerAccepted := metav1.Condition{Type: string(gatev1.ListenerConditionAccepted), Status: metav1.ConditionTrue}
|
||||
staleConflicted := metav1.Condition{Type: string(gatev1.ListenerConditionConflicted), Status: metav1.ConditionTrue}
|
||||
foreign := metav1.Condition{Type: "example.com/Foreign", Status: metav1.ConditionTrue}
|
||||
@@ -429,6 +430,13 @@ func Test_mergeGatewayStatus(t *testing.T) {
|
||||
Listeners: desired.Listeners,
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "drops owned Gateway condition no longer desired",
|
||||
current: gatev1.GatewayStatus{
|
||||
Conditions: []metav1.Condition{staleAccepted, staleResolvedRefs},
|
||||
},
|
||||
expected: desired,
|
||||
},
|
||||
{
|
||||
desc: "keeps foreign listener condition",
|
||||
current: gatev1.GatewayStatus{
|
||||
|
||||
@@ -36,6 +36,7 @@ func extendedGatewayFeatures() sets.Set[features.Feature] {
|
||||
features.GatewayHTTPListenerIsolationFeature,
|
||||
features.GatewayHTTPSListenerDetectMisdirectedRequestsFeature,
|
||||
features.ListenerSetFeature,
|
||||
features.GatewayBackendClientCertificateFeature,
|
||||
features.GatewayFrontendClientCertificateValidationFeature,
|
||||
features.GatewayFrontendClientCertificateValidationInsecureFallbackFeature,
|
||||
)
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: client-cert
|
||||
namespace: default
|
||||
|
||||
data:
|
||||
tls.crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJxRENDQVU2Z0F3SUJBZ0lVWU9zcjBRZ0hPQnE0a1lSQ0w1K1REZFZ0NmJRd0NnWUlLb1pJemowRUF3SXcKRmpFVU1CSUdBMVVFQXd3TFpYaGhiWEJzWlM1amIyMHdIaGNOTWpVeE1ERXdNRGN4TnpNd1doY05NelV4TURBNApNRGN4TnpNd1dqQVdNUlF3RWdZRFZRUUREQXRsZUdGdGNHeGxMbU52YlRCWk1CTUdCeXFHU000OUFnRUdDQ3FHClNNNDlBd0VIQTBJQUJET3JpdzNaUTd3SWhXcmJQUzZKRlFUM2JUb05DRjAwdlNWNWZhYjZUYlh5TDh0bHNHcmUKVFJJRjJFd2dzdGVNT2t4R0tLU2xEdnVhRHdxOHAvcVYrMHVqZWpCNE1CMEdBMVVkRGdRV0JCUk1Fa3VleFhRaApVdERnUmcxS0J2NzJDRHErRXpBZkJnTlZIU01FR0RBV2dCUk1Fa3VleFhRaFV0RGdSZzFLQnY3MkNEcStFekFQCkJnTlZIUk1CQWY4RUJUQURBUUgvTUNVR0ExVWRFUVFlTUJ5Q0MyVjRZVzF3YkdVdVkyOXRnZzBxTG1WNFlXMXcKYkdVdVkyOXRNQW9HQ0NxR1NNNDlCQU1DQTBnQU1FVUNJUURzODdWazBzd0E2SGdPSmpST3llMW14RDgzcWNHeQpwZUZnb3hWOTNEeStjd0lnVjBNTUVKSmJWc1R5WkszRVErK1hjNXJFTDc4bnJKK1lJRVYrckNVV2o1VT0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQ==
|
||||
tls.key: LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tCk1JR0hBZ0VBTUJNR0J5cUdTTTQ5QWdFR0NDcUdTTTQ5QXdFSEJHMHdhd0lCQVFRZ253Z0w1RFk0VUIxNHNNNmYKRGlrUWR0cWgyUVcxQXJmRjRmYzFVRnppZmRHaFJBTkNBQVF6cTRzTjJVTzhDSVZxMnowdWlSVUU5MjA2RFFoZApOTDBsZVgybStrMjE4aS9MWmJCcTNrMFNCZGhNSUxMWGpEcE1SaWlrcFE3N21nOEt2S2Y2bGZ0TAotLS0tLUVORCBQUklWQVRFIEtFWS0tLS0t
|
||||
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: malformed-cert
|
||||
namespace: default
|
||||
type: Opaque
|
||||
data: {}
|
||||
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: client-cert
|
||||
namespace: bar
|
||||
|
||||
data:
|
||||
tls.crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJwVENDQVV1Z0F3SUJBZ0lVVEVrVUVNQ21acnh4aUVrQ20wUFMrRnF1dXNRd0NnWUlLb1pJemowRUF3SXcKR2pFWU1CWUdBMVVFQXd3UFltRnlMbVY0WVcxd2JHVXVZMjl0TUI0WERUSTJNRGt4TlRFeE5ETXlORm9YRFRNMgpNRGt4TWpFeE5ETXlORm93R2pFWU1CWUdBMVVFQXd3UFltRnlMbVY0WVcxd2JHVXVZMjl0TUZrd0V3WUhLb1pJCnpqMENBUVlJS29aSXpqMERBUWNEUWdBRWJNdytOdEtlSEVuUUxsR0dLV04wQVUySGJ6ckcraTBYVlRMMEFqaTUKaXc2dTlsR1RiNENZQ21xTENzVmF0Q3R6UE0vRVk1dmJadXJ3SlVGVGxmM3lSS052TUcwd0hRWURWUjBPQkJZRQpGTCsvb1lFMkJiRkl1OTBuNjg1bXFEK1E0cFRVTUI4R0ExVWRJd1FZTUJhQUZMKy9vWUUyQmJGSXU5MG42ODVtCnFEK1E0cFRVTUE4R0ExVWRFd0VCL3dRRk1BTUJBZjh3R2dZRFZSMFJCQk13RVlJUFltRnlMbVY0WVcxd2JHVXUKWTI5dE1Bb0dDQ3FHU000OUJBTUNBMGdBTUVVQ0lRREN0UTRzRGtkU0hRZVRYSk44a3BwTmxtNDBWQ2pxOEx2ZAppWGszR0NYbzhBSWdiczUxeVgybHQxZXBwZEhHRnBuNGRyV3g5dDV0UGNEZGR3U1lVUzdPQkpBPQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==
|
||||
tls.key: LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tCk1JR0hBZ0VBTUJNR0J5cUdTTTQ5QWdFR0NDcUdTTTQ5QXdFSEJHMHdhd0lCQVFRZ09Uc2V0ZkxqTDNFbnVrK2gKbDNjV1dKSHZSUTE0UWx5QkI4Y0FycmNwVldHaFJBTkNBQVJzekQ0MjBwNGNTZEF1VVlZcFkzUUJUWWR2T3NiNgpMUmRWTXZRQ09MbUxEcTcyVVpOdmdKZ0thb3NLeFZxMEszTTh6OFJqbTl0bTZ2QWxRVk9WL2ZKRQotLS0tLUVORCBQUklWQVRFIEtFWS0tLS0tCg==
|
||||
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: ungranted-cert
|
||||
namespace: bar
|
||||
|
||||
data:
|
||||
tls.crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJwVENDQVV1Z0F3SUJBZ0lVVEVrVUVNQ21acnh4aUVrQ20wUFMrRnF1dXNRd0NnWUlLb1pJemowRUF3SXcKR2pFWU1CWUdBMVVFQXd3UFltRnlMbVY0WVcxd2JHVXVZMjl0TUI0WERUSTJNRGt4TlRFeE5ETXlORm9YRFRNMgpNRGt4TWpFeE5ETXlORm93R2pFWU1CWUdBMVVFQXd3UFltRnlMbVY0WVcxd2JHVXVZMjl0TUZrd0V3WUhLb1pJCnpqMENBUVlJS29aSXpqMERBUWNEUWdBRWJNdytOdEtlSEVuUUxsR0dLV04wQVUySGJ6ckcraTBYVlRMMEFqaTUKaXc2dTlsR1RiNENZQ21xTENzVmF0Q3R6UE0vRVk1dmJadXJ3SlVGVGxmM3lSS052TUcwd0hRWURWUjBPQkJZRQpGTCsvb1lFMkJiRkl1OTBuNjg1bXFEK1E0cFRVTUI4R0ExVWRJd1FZTUJhQUZMKy9vWUUyQmJGSXU5MG42ODVtCnFEK1E0cFRVTUE4R0ExVWRFd0VCL3dRRk1BTUJBZjh3R2dZRFZSMFJCQk13RVlJUFltRnlMbVY0WVcxd2JHVXUKWTI5dE1Bb0dDQ3FHU000OUJBTUNBMGdBTUVVQ0lRREN0UTRzRGtkU0hRZVRYSk44a3BwTmxtNDBWQ2pxOEx2ZAppWGszR0NYbzhBSWdiczUxeVgybHQxZXBwZEhHRnBuNGRyV3g5dDV0UGNEZGR3U1lVUzdPQkpBPQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==
|
||||
tls.key: LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tCk1JR0hBZ0VBTUJNR0J5cUdTTTQ5QWdFR0NDcUdTTTQ5QXdFSEJHMHdhd0lCQVFRZ09Uc2V0ZkxqTDNFbnVrK2gKbDNjV1dKSHZSUTE0UWx5QkI4Y0FycmNwVldHaFJBTkNBQVJzekQ0MjBwNGNTZEF1VVlZcFkzUUJUWWR2T3NiNgpMUmRWTXZRQ09MbUxEcTcyVVpOdmdKZ0thb3NLeFZxMEszTTh6OFJqbTl0bTZ2QWxRVk9WL2ZKRQotLS0tLUVORCBQUklWQVRFIEtFWS0tLS0tCg==
|
||||
|
||||
---
|
||||
kind: ReferenceGrant
|
||||
apiVersion: gateway.networking.k8s.io/v1
|
||||
metadata:
|
||||
name: secret-from-default
|
||||
namespace: bar
|
||||
spec:
|
||||
from:
|
||||
- group: gateway.networking.k8s.io
|
||||
kind: Gateway
|
||||
namespace: default
|
||||
to:
|
||||
- group: ""
|
||||
kind: Secret
|
||||
name: client-cert
|
||||
+89
@@ -0,0 +1,89 @@
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: client-cert
|
||||
namespace: default
|
||||
|
||||
data:
|
||||
tls.crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJxRENDQVU2Z0F3SUJBZ0lVWU9zcjBRZ0hPQnE0a1lSQ0w1K1REZFZ0NmJRd0NnWUlLb1pJemowRUF3SXcKRmpFVU1CSUdBMVVFQXd3TFpYaGhiWEJzWlM1amIyMHdIaGNOTWpVeE1ERXdNRGN4TnpNd1doY05NelV4TURBNApNRGN4TnpNd1dqQVdNUlF3RWdZRFZRUUREQXRsZUdGdGNHeGxMbU52YlRCWk1CTUdCeXFHU000OUFnRUdDQ3FHClNNNDlBd0VIQTBJQUJET3JpdzNaUTd3SWhXcmJQUzZKRlFUM2JUb05DRjAwdlNWNWZhYjZUYlh5TDh0bHNHcmUKVFJJRjJFd2dzdGVNT2t4R0tLU2xEdnVhRHdxOHAvcVYrMHVqZWpCNE1CMEdBMVVkRGdRV0JCUk1Fa3VleFhRaApVdERnUmcxS0J2NzJDRHErRXpBZkJnTlZIU01FR0RBV2dCUk1Fa3VleFhRaFV0RGdSZzFLQnY3MkNEcStFekFQCkJnTlZIUk1CQWY4RUJUQURBUUgvTUNVR0ExVWRFUVFlTUJ5Q0MyVjRZVzF3YkdVdVkyOXRnZzBxTG1WNFlXMXcKYkdVdVkyOXRNQW9HQ0NxR1NNNDlCQU1DQTBnQU1FVUNJUURzODdWazBzd0E2SGdPSmpST3llMW14RDgzcWNHeQpwZUZnb3hWOTNEeStjd0lnVjBNTUVKSmJWc1R5WkszRVErK1hjNXJFTDc4bnJKK1lJRVYrckNVV2o1VT0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQ==
|
||||
tls.key: LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tCk1JR0hBZ0VBTUJNR0J5cUdTTTQ5QWdFR0NDcUdTTTQ5QXdFSEJHMHdhd0lCQVFRZ253Z0w1RFk0VUIxNHNNNmYKRGlrUWR0cWgyUVcxQXJmRjRmYzFVRnppZmRHaFJBTkNBQVF6cTRzTjJVTzhDSVZxMnowdWlSVUU5MjA2RFFoZApOTDBsZVgybStrMjE4aS9MWmJCcTNrMFNCZGhNSUxMWGpEcE1SaWlrcFE3N21nOEt2S2Y2bGZ0TAotLS0tLUVORCBQUklWQVRFIEtFWS0tLS0t
|
||||
|
||||
---
|
||||
kind: GatewayClass
|
||||
apiVersion: gateway.networking.k8s.io/v1
|
||||
metadata:
|
||||
name: my-gateway-class
|
||||
spec:
|
||||
controllerName: traefik.io/gateway-controller
|
||||
|
||||
---
|
||||
kind: Gateway
|
||||
apiVersion: gateway.networking.k8s.io/v1
|
||||
metadata:
|
||||
name: my-gateway
|
||||
namespace: default
|
||||
spec:
|
||||
gatewayClassName: my-gateway-class
|
||||
listeners:
|
||||
- name: web
|
||||
protocol: HTTP
|
||||
port: 80
|
||||
allowedRoutes:
|
||||
kinds:
|
||||
- kind: GRPCRoute
|
||||
group: gateway.networking.k8s.io
|
||||
namespaces:
|
||||
from: Same
|
||||
tls:
|
||||
backend:
|
||||
clientCertificateRef:
|
||||
group: ""
|
||||
kind: Secret
|
||||
name: client-cert
|
||||
|
||||
---
|
||||
kind: GRPCRoute
|
||||
apiVersion: gateway.networking.k8s.io/v1
|
||||
metadata:
|
||||
name: grpc-app-1
|
||||
namespace: default
|
||||
spec:
|
||||
parentRefs:
|
||||
- name: my-gateway
|
||||
kind: Gateway
|
||||
group: gateway.networking.k8s.io
|
||||
hostnames:
|
||||
- foo.com
|
||||
rules:
|
||||
- backendRefs:
|
||||
- name: whoami
|
||||
port: 80
|
||||
weight: 1
|
||||
|
||||
---
|
||||
kind: BackendTLSPolicy
|
||||
apiVersion: gateway.networking.k8s.io/v1
|
||||
metadata:
|
||||
name: policy-1
|
||||
namespace: default
|
||||
spec:
|
||||
targetRefs:
|
||||
- group: ""
|
||||
kind: Service
|
||||
name: whoami
|
||||
validation:
|
||||
hostname: whoami
|
||||
caCertificateRefs:
|
||||
- group: ""
|
||||
kind: ConfigMap
|
||||
name: ca-file
|
||||
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: ca-file
|
||||
namespace: default
|
||||
data:
|
||||
ca.crt: "CA1"
|
||||
+102
@@ -0,0 +1,102 @@
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: client-cert
|
||||
namespace: default
|
||||
|
||||
data:
|
||||
tls.crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJxRENDQVU2Z0F3SUJBZ0lVWU9zcjBRZ0hPQnE0a1lSQ0w1K1REZFZ0NmJRd0NnWUlLb1pJemowRUF3SXcKRmpFVU1CSUdBMVVFQXd3TFpYaGhiWEJzWlM1amIyMHdIaGNOTWpVeE1ERXdNRGN4TnpNd1doY05NelV4TURBNApNRGN4TnpNd1dqQVdNUlF3RWdZRFZRUUREQXRsZUdGdGNHeGxMbU52YlRCWk1CTUdCeXFHU000OUFnRUdDQ3FHClNNNDlBd0VIQTBJQUJET3JpdzNaUTd3SWhXcmJQUzZKRlFUM2JUb05DRjAwdlNWNWZhYjZUYlh5TDh0bHNHcmUKVFJJRjJFd2dzdGVNT2t4R0tLU2xEdnVhRHdxOHAvcVYrMHVqZWpCNE1CMEdBMVVkRGdRV0JCUk1Fa3VleFhRaApVdERnUmcxS0J2NzJDRHErRXpBZkJnTlZIU01FR0RBV2dCUk1Fa3VleFhRaFV0RGdSZzFLQnY3MkNEcStFekFQCkJnTlZIUk1CQWY4RUJUQURBUUgvTUNVR0ExVWRFUVFlTUJ5Q0MyVjRZVzF3YkdVdVkyOXRnZzBxTG1WNFlXMXcKYkdVdVkyOXRNQW9HQ0NxR1NNNDlCQU1DQTBnQU1FVUNJUURzODdWazBzd0E2SGdPSmpST3llMW14RDgzcWNHeQpwZUZnb3hWOTNEeStjd0lnVjBNTUVKSmJWc1R5WkszRVErK1hjNXJFTDc4bnJKK1lJRVYrckNVV2o1VT0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQ==
|
||||
tls.key: LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tCk1JR0hBZ0VBTUJNR0J5cUdTTTQ5QWdFR0NDcUdTTTQ5QXdFSEJHMHdhd0lCQVFRZ253Z0w1RFk0VUIxNHNNNmYKRGlrUWR0cWgyUVcxQXJmRjRmYzFVRnppZmRHaFJBTkNBQVF6cTRzTjJVTzhDSVZxMnowdWlSVUU5MjA2RFFoZApOTDBsZVgybStrMjE4aS9MWmJCcTNrMFNCZGhNSUxMWGpEcE1SaWlrcFE3N21nOEt2S2Y2bGZ0TAotLS0tLUVORCBQUklWQVRFIEtFWS0tLS0t
|
||||
|
||||
---
|
||||
kind: GatewayClass
|
||||
apiVersion: gateway.networking.k8s.io/v1
|
||||
metadata:
|
||||
name: my-gateway-class
|
||||
spec:
|
||||
controllerName: traefik.io/gateway-controller
|
||||
|
||||
---
|
||||
kind: Gateway
|
||||
apiVersion: gateway.networking.k8s.io/v1
|
||||
metadata:
|
||||
name: my-gateway
|
||||
namespace: default
|
||||
spec:
|
||||
gatewayClassName: my-gateway-class
|
||||
listeners:
|
||||
- name: http
|
||||
protocol: HTTP
|
||||
port: 80
|
||||
allowedRoutes:
|
||||
namespaces:
|
||||
from: Same
|
||||
tls:
|
||||
backend:
|
||||
clientCertificateRef:
|
||||
group: ""
|
||||
kind: Secret
|
||||
name: client-cert
|
||||
|
||||
---
|
||||
kind: HTTPRoute
|
||||
apiVersion: gateway.networking.k8s.io/v1
|
||||
metadata:
|
||||
name: http-app-1
|
||||
namespace: default
|
||||
spec:
|
||||
parentRefs:
|
||||
- name: my-gateway
|
||||
kind: Gateway
|
||||
group: gateway.networking.k8s.io
|
||||
hostnames:
|
||||
- "foo.com"
|
||||
rules:
|
||||
- matches:
|
||||
- path:
|
||||
type: Exact
|
||||
value: /bar
|
||||
backendRefs:
|
||||
- name: whoami
|
||||
port: 80
|
||||
weight: 1
|
||||
kind: Service
|
||||
group: ""
|
||||
- matches:
|
||||
- path:
|
||||
type: Exact
|
||||
value: /foo
|
||||
backendRefs:
|
||||
- name: whoami2
|
||||
port: 8080
|
||||
weight: 1
|
||||
kind: Service
|
||||
group: ""
|
||||
|
||||
---
|
||||
kind: BackendTLSPolicy
|
||||
apiVersion: gateway.networking.k8s.io/v1
|
||||
metadata:
|
||||
name: policy-1
|
||||
namespace: default
|
||||
spec:
|
||||
targetRefs:
|
||||
- group: ""
|
||||
kind: Service
|
||||
name: whoami
|
||||
validation:
|
||||
hostname: whoami
|
||||
caCertificateRefs:
|
||||
- group: ""
|
||||
kind: ConfigMap
|
||||
name: ca-file
|
||||
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: ca-file
|
||||
namespace: default
|
||||
data:
|
||||
ca.crt: "CA1"
|
||||
+122
@@ -0,0 +1,122 @@
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: client-cert
|
||||
namespace: default
|
||||
|
||||
data:
|
||||
tls.crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJxRENDQVU2Z0F3SUJBZ0lVWU9zcjBRZ0hPQnE0a1lSQ0w1K1REZFZ0NmJRd0NnWUlLb1pJemowRUF3SXcKRmpFVU1CSUdBMVVFQXd3TFpYaGhiWEJzWlM1amIyMHdIaGNOTWpVeE1ERXdNRGN4TnpNd1doY05NelV4TURBNApNRGN4TnpNd1dqQVdNUlF3RWdZRFZRUUREQXRsZUdGdGNHeGxMbU52YlRCWk1CTUdCeXFHU000OUFnRUdDQ3FHClNNNDlBd0VIQTBJQUJET3JpdzNaUTd3SWhXcmJQUzZKRlFUM2JUb05DRjAwdlNWNWZhYjZUYlh5TDh0bHNHcmUKVFJJRjJFd2dzdGVNT2t4R0tLU2xEdnVhRHdxOHAvcVYrMHVqZWpCNE1CMEdBMVVkRGdRV0JCUk1Fa3VleFhRaApVdERnUmcxS0J2NzJDRHErRXpBZkJnTlZIU01FR0RBV2dCUk1Fa3VleFhRaFV0RGdSZzFLQnY3MkNEcStFekFQCkJnTlZIUk1CQWY4RUJUQURBUUgvTUNVR0ExVWRFUVFlTUJ5Q0MyVjRZVzF3YkdVdVkyOXRnZzBxTG1WNFlXMXcKYkdVdVkyOXRNQW9HQ0NxR1NNNDlCQU1DQTBnQU1FVUNJUURzODdWazBzd0E2SGdPSmpST3llMW14RDgzcWNHeQpwZUZnb3hWOTNEeStjd0lnVjBNTUVKSmJWc1R5WkszRVErK1hjNXJFTDc4bnJKK1lJRVYrckNVV2o1VT0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQ==
|
||||
tls.key: LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tCk1JR0hBZ0VBTUJNR0J5cUdTTTQ5QWdFR0NDcUdTTTQ5QXdFSEJHMHdhd0lCQVFRZ253Z0w1RFk0VUIxNHNNNmYKRGlrUWR0cWgyUVcxQXJmRjRmYzFVRnppZmRHaFJBTkNBQVF6cTRzTjJVTzhDSVZxMnowdWlSVUU5MjA2RFFoZApOTDBsZVgybStrMjE4aS9MWmJCcTNrMFNCZGhNSUxMWGpEcE1SaWlrcFE3N21nOEt2S2Y2bGZ0TAotLS0tLUVORCBQUklWQVRFIEtFWS0tLS0t
|
||||
|
||||
---
|
||||
kind: GatewayClass
|
||||
apiVersion: gateway.networking.k8s.io/v1
|
||||
metadata:
|
||||
name: my-gateway-class
|
||||
spec:
|
||||
controllerName: traefik.io/gateway-controller
|
||||
|
||||
---
|
||||
kind: Gateway
|
||||
apiVersion: gateway.networking.k8s.io/v1
|
||||
metadata:
|
||||
name: my-gateway
|
||||
namespace: default
|
||||
spec:
|
||||
gatewayClassName: my-gateway-class
|
||||
allowedListeners:
|
||||
namespaces:
|
||||
from: All
|
||||
listeners:
|
||||
- name: http
|
||||
protocol: HTTP
|
||||
port: 80
|
||||
allowedRoutes:
|
||||
namespaces:
|
||||
from: Same
|
||||
tls:
|
||||
backend:
|
||||
clientCertificateRef:
|
||||
group: ""
|
||||
kind: Secret
|
||||
name: client-cert
|
||||
|
||||
---
|
||||
kind: ListenerSet
|
||||
apiVersion: gateway.networking.k8s.io/v1
|
||||
metadata:
|
||||
name: my-listenerset
|
||||
namespace: default
|
||||
spec:
|
||||
parentRef:
|
||||
name: my-gateway
|
||||
namespace: default
|
||||
kind: Gateway
|
||||
group: gateway.networking.k8s.io
|
||||
listeners:
|
||||
- name: http-alt
|
||||
protocol: HTTP
|
||||
port: 8080
|
||||
|
||||
---
|
||||
kind: HTTPRoute
|
||||
apiVersion: gateway.networking.k8s.io/v1
|
||||
metadata:
|
||||
name: http-app-1
|
||||
namespace: default
|
||||
spec:
|
||||
parentRefs:
|
||||
- name: my-listenerset
|
||||
kind: ListenerSet
|
||||
group: gateway.networking.k8s.io
|
||||
hostnames:
|
||||
- "foo.com"
|
||||
rules:
|
||||
- matches:
|
||||
- path:
|
||||
type: Exact
|
||||
value: /bar
|
||||
backendRefs:
|
||||
- name: whoami
|
||||
port: 80
|
||||
weight: 1
|
||||
kind: Service
|
||||
group: ""
|
||||
- matches:
|
||||
- path:
|
||||
type: Exact
|
||||
value: /foo
|
||||
backendRefs:
|
||||
- name: whoami2
|
||||
port: 8080
|
||||
weight: 1
|
||||
kind: Service
|
||||
group: ""
|
||||
|
||||
---
|
||||
kind: BackendTLSPolicy
|
||||
apiVersion: gateway.networking.k8s.io/v1
|
||||
metadata:
|
||||
name: policy-1
|
||||
namespace: default
|
||||
spec:
|
||||
targetRefs:
|
||||
- group: ""
|
||||
kind: Service
|
||||
name: whoami
|
||||
validation:
|
||||
hostname: whoami
|
||||
caCertificateRefs:
|
||||
- group: ""
|
||||
kind: ConfigMap
|
||||
name: ca-file
|
||||
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: ca-file
|
||||
namespace: default
|
||||
data:
|
||||
ca.crt: "CA1"
|
||||
+138
@@ -0,0 +1,138 @@
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: client-cert
|
||||
namespace: default
|
||||
|
||||
data:
|
||||
tls.crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJxRENDQVU2Z0F3SUJBZ0lVWU9zcjBRZ0hPQnE0a1lSQ0w1K1REZFZ0NmJRd0NnWUlLb1pJemowRUF3SXcKRmpFVU1CSUdBMVVFQXd3TFpYaGhiWEJzWlM1amIyMHdIaGNOTWpVeE1ERXdNRGN4TnpNd1doY05NelV4TURBNApNRGN4TnpNd1dqQVdNUlF3RWdZRFZRUUREQXRsZUdGdGNHeGxMbU52YlRCWk1CTUdCeXFHU000OUFnRUdDQ3FHClNNNDlBd0VIQTBJQUJET3JpdzNaUTd3SWhXcmJQUzZKRlFUM2JUb05DRjAwdlNWNWZhYjZUYlh5TDh0bHNHcmUKVFJJRjJFd2dzdGVNT2t4R0tLU2xEdnVhRHdxOHAvcVYrMHVqZWpCNE1CMEdBMVVkRGdRV0JCUk1Fa3VleFhRaApVdERnUmcxS0J2NzJDRHErRXpBZkJnTlZIU01FR0RBV2dCUk1Fa3VleFhRaFV0RGdSZzFLQnY3MkNEcStFekFQCkJnTlZIUk1CQWY4RUJUQURBUUgvTUNVR0ExVWRFUVFlTUJ5Q0MyVjRZVzF3YkdVdVkyOXRnZzBxTG1WNFlXMXcKYkdVdVkyOXRNQW9HQ0NxR1NNNDlCQU1DQTBnQU1FVUNJUURzODdWazBzd0E2SGdPSmpST3llMW14RDgzcWNHeQpwZUZnb3hWOTNEeStjd0lnVjBNTUVKSmJWc1R5WkszRVErK1hjNXJFTDc4bnJKK1lJRVYrckNVV2o1VT0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQ==
|
||||
tls.key: LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tCk1JR0hBZ0VBTUJNR0J5cUdTTTQ5QWdFR0NDcUdTTTQ5QXdFSEJHMHdhd0lCQVFRZ253Z0w1RFk0VUIxNHNNNmYKRGlrUWR0cWgyUVcxQXJmRjRmYzFVRnppZmRHaFJBTkNBQVF6cTRzTjJVTzhDSVZxMnowdWlSVUU5MjA2RFFoZApOTDBsZVgybStrMjE4aS9MWmJCcTNrMFNCZGhNSUxMWGpEcE1SaWlrcFE3N21nOEt2S2Y2bGZ0TAotLS0tLUVORCBQUklWQVRFIEtFWS0tLS0t
|
||||
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: other-client-cert
|
||||
namespace: default
|
||||
|
||||
data:
|
||||
tls.crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJwVENDQVV1Z0F3SUJBZ0lVVEVrVUVNQ21acnh4aUVrQ20wUFMrRnF1dXNRd0NnWUlLb1pJemowRUF3SXcKR2pFWU1CWUdBMVVFQXd3UFltRnlMbVY0WVcxd2JHVXVZMjl0TUI0WERUSTJNRGt4TlRFeE5ETXlORm9YRFRNMgpNRGt4TWpFeE5ETXlORm93R2pFWU1CWUdBMVVFQXd3UFltRnlMbVY0WVcxd2JHVXVZMjl0TUZrd0V3WUhLb1pJCnpqMENBUVlJS29aSXpqMERBUWNEUWdBRWJNdytOdEtlSEVuUUxsR0dLV04wQVUySGJ6ckcraTBYVlRMMEFqaTUKaXc2dTlsR1RiNENZQ21xTENzVmF0Q3R6UE0vRVk1dmJadXJ3SlVGVGxmM3lSS052TUcwd0hRWURWUjBPQkJZRQpGTCsvb1lFMkJiRkl1OTBuNjg1bXFEK1E0cFRVTUI4R0ExVWRJd1FZTUJhQUZMKy9vWUUyQmJGSXU5MG42ODVtCnFEK1E0cFRVTUE4R0ExVWRFd0VCL3dRRk1BTUJBZjh3R2dZRFZSMFJCQk13RVlJUFltRnlMbVY0WVcxd2JHVXUKWTI5dE1Bb0dDQ3FHU000OUJBTUNBMGdBTUVVQ0lRREN0UTRzRGtkU0hRZVRYSk44a3BwTmxtNDBWQ2pxOEx2ZAppWGszR0NYbzhBSWdiczUxeVgybHQxZXBwZEhHRnBuNGRyV3g5dDV0UGNEZGR3U1lVUzdPQkpBPQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==
|
||||
tls.key: LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tCk1JR0hBZ0VBTUJNR0J5cUdTTTQ5QWdFR0NDcUdTTTQ5QXdFSEJHMHdhd0lCQVFRZ09Uc2V0ZkxqTDNFbnVrK2gKbDNjV1dKSHZSUTE0UWx5QkI4Y0FycmNwVldHaFJBTkNBQVJzekQ0MjBwNGNTZEF1VVlZcFkzUUJUWWR2T3NiNgpMUmRWTXZRQ09MbUxEcTcyVVpOdmdKZ0thb3NLeFZxMEszTTh6OFJqbTl0bTZ2QWxRVk9WL2ZKRQotLS0tLUVORCBQUklWQVRFIEtFWS0tLS0tCg==
|
||||
|
||||
---
|
||||
kind: GatewayClass
|
||||
apiVersion: gateway.networking.k8s.io/v1
|
||||
metadata:
|
||||
name: my-gateway-class
|
||||
spec:
|
||||
controllerName: traefik.io/gateway-controller
|
||||
|
||||
---
|
||||
kind: Gateway
|
||||
apiVersion: gateway.networking.k8s.io/v1
|
||||
metadata:
|
||||
name: my-gateway
|
||||
namespace: default
|
||||
spec:
|
||||
gatewayClassName: my-gateway-class
|
||||
listeners:
|
||||
- name: http
|
||||
protocol: HTTP
|
||||
port: 80
|
||||
allowedRoutes:
|
||||
namespaces:
|
||||
from: Same
|
||||
tls:
|
||||
backend:
|
||||
clientCertificateRef:
|
||||
group: ""
|
||||
kind: Secret
|
||||
name: client-cert
|
||||
|
||||
---
|
||||
kind: Gateway
|
||||
apiVersion: gateway.networking.k8s.io/v1
|
||||
metadata:
|
||||
name: my-other-gateway
|
||||
namespace: default
|
||||
spec:
|
||||
gatewayClassName: my-gateway-class
|
||||
listeners:
|
||||
- name: http
|
||||
protocol: HTTP
|
||||
port: 8080
|
||||
allowedRoutes:
|
||||
namespaces:
|
||||
from: Same
|
||||
tls:
|
||||
backend:
|
||||
clientCertificateRef:
|
||||
group: ""
|
||||
kind: Secret
|
||||
name: other-client-cert
|
||||
|
||||
---
|
||||
kind: HTTPRoute
|
||||
apiVersion: gateway.networking.k8s.io/v1
|
||||
metadata:
|
||||
name: http-app-1
|
||||
namespace: default
|
||||
spec:
|
||||
parentRefs:
|
||||
- name: my-gateway
|
||||
kind: Gateway
|
||||
group: gateway.networking.k8s.io
|
||||
- name: my-other-gateway
|
||||
kind: Gateway
|
||||
group: gateway.networking.k8s.io
|
||||
hostnames:
|
||||
- "foo.com"
|
||||
rules:
|
||||
- matches:
|
||||
- path:
|
||||
type: Exact
|
||||
value: /bar
|
||||
backendRefs:
|
||||
- name: whoami
|
||||
port: 80
|
||||
weight: 1
|
||||
kind: Service
|
||||
group: ""
|
||||
- matches:
|
||||
- path:
|
||||
type: Exact
|
||||
value: /foo
|
||||
backendRefs:
|
||||
- name: whoami2
|
||||
port: 8080
|
||||
weight: 1
|
||||
kind: Service
|
||||
group: ""
|
||||
|
||||
---
|
||||
kind: BackendTLSPolicy
|
||||
apiVersion: gateway.networking.k8s.io/v1
|
||||
metadata:
|
||||
name: policy-1
|
||||
namespace: default
|
||||
spec:
|
||||
targetRefs:
|
||||
- group: ""
|
||||
kind: Service
|
||||
name: whoami
|
||||
validation:
|
||||
hostname: whoami
|
||||
caCertificateRefs:
|
||||
- group: ""
|
||||
kind: ConfigMap
|
||||
name: ca-file
|
||||
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: ca-file
|
||||
namespace: default
|
||||
data:
|
||||
ca.crt: "CA1"
|
||||
+105
@@ -0,0 +1,105 @@
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: supersecret
|
||||
namespace: default
|
||||
|
||||
data:
|
||||
tls.crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJxRENDQVU2Z0F3SUJBZ0lVWU9zcjBRZ0hPQnE0a1lSQ0w1K1REZFZ0NmJRd0NnWUlLb1pJemowRUF3SXcKRmpFVU1CSUdBMVVFQXd3TFpYaGhiWEJzWlM1amIyMHdIaGNOTWpVeE1ERXdNRGN4TnpNd1doY05NelV4TURBNApNRGN4TnpNd1dqQVdNUlF3RWdZRFZRUUREQXRsZUdGdGNHeGxMbU52YlRCWk1CTUdCeXFHU000OUFnRUdDQ3FHClNNNDlBd0VIQTBJQUJET3JpdzNaUTd3SWhXcmJQUzZKRlFUM2JUb05DRjAwdlNWNWZhYjZUYlh5TDh0bHNHcmUKVFJJRjJFd2dzdGVNT2t4R0tLU2xEdnVhRHdxOHAvcVYrMHVqZWpCNE1CMEdBMVVkRGdRV0JCUk1Fa3VleFhRaApVdERnUmcxS0J2NzJDRHErRXpBZkJnTlZIU01FR0RBV2dCUk1Fa3VleFhRaFV0RGdSZzFLQnY3MkNEcStFekFQCkJnTlZIUk1CQWY4RUJUQURBUUgvTUNVR0ExVWRFUVFlTUJ5Q0MyVjRZVzF3YkdVdVkyOXRnZzBxTG1WNFlXMXcKYkdVdVkyOXRNQW9HQ0NxR1NNNDlCQU1DQTBnQU1FVUNJUURzODdWazBzd0E2SGdPSmpST3llMW14RDgzcWNHeQpwZUZnb3hWOTNEeStjd0lnVjBNTUVKSmJWc1R5WkszRVErK1hjNXJFTDc4bnJKK1lJRVYrckNVV2o1VT0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQ==
|
||||
tls.key: LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tCk1JR0hBZ0VBTUJNR0J5cUdTTTQ5QWdFR0NDcUdTTTQ5QXdFSEJHMHdhd0lCQVFRZ253Z0w1RFk0VUIxNHNNNmYKRGlrUWR0cWgyUVcxQXJmRjRmYzFVRnppZmRHaFJBTkNBQVF6cTRzTjJVTzhDSVZxMnowdWlSVUU5MjA2RFFoZApOTDBsZVgybStrMjE4aS9MWmJCcTNrMFNCZGhNSUxMWGpEcE1SaWlrcFE3N21nOEt2S2Y2bGZ0TAotLS0tLUVORCBQUklWQVRFIEtFWS0tLS0t
|
||||
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: client-cert
|
||||
namespace: default
|
||||
|
||||
data:
|
||||
tls.crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJxRENDQVU2Z0F3SUJBZ0lVWU9zcjBRZ0hPQnE0a1lSQ0w1K1REZFZ0NmJRd0NnWUlLb1pJemowRUF3SXcKRmpFVU1CSUdBMVVFQXd3TFpYaGhiWEJzWlM1amIyMHdIaGNOTWpVeE1ERXdNRGN4TnpNd1doY05NelV4TURBNApNRGN4TnpNd1dqQVdNUlF3RWdZRFZRUUREQXRsZUdGdGNHeGxMbU52YlRCWk1CTUdCeXFHU000OUFnRUdDQ3FHClNNNDlBd0VIQTBJQUJET3JpdzNaUTd3SWhXcmJQUzZKRlFUM2JUb05DRjAwdlNWNWZhYjZUYlh5TDh0bHNHcmUKVFJJRjJFd2dzdGVNT2t4R0tLU2xEdnVhRHdxOHAvcVYrMHVqZWpCNE1CMEdBMVVkRGdRV0JCUk1Fa3VleFhRaApVdERnUmcxS0J2NzJDRHErRXpBZkJnTlZIU01FR0RBV2dCUk1Fa3VleFhRaFV0RGdSZzFLQnY3MkNEcStFekFQCkJnTlZIUk1CQWY4RUJUQURBUUgvTUNVR0ExVWRFUVFlTUJ5Q0MyVjRZVzF3YkdVdVkyOXRnZzBxTG1WNFlXMXcKYkdVdVkyOXRNQW9HQ0NxR1NNNDlCQU1DQTBnQU1FVUNJUURzODdWazBzd0E2SGdPSmpST3llMW14RDgzcWNHeQpwZUZnb3hWOTNEeStjd0lnVjBNTUVKSmJWc1R5WkszRVErK1hjNXJFTDc4bnJKK1lJRVYrckNVV2o1VT0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQ==
|
||||
tls.key: LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tCk1JR0hBZ0VBTUJNR0J5cUdTTTQ5QWdFR0NDcUdTTTQ5QXdFSEJHMHdhd0lCQVFRZ253Z0w1RFk0VUIxNHNNNmYKRGlrUWR0cWgyUVcxQXJmRjRmYzFVRnppZmRHaFJBTkNBQVF6cTRzTjJVTzhDSVZxMnowdWlSVUU5MjA2RFFoZApOTDBsZVgybStrMjE4aS9MWmJCcTNrMFNCZGhNSUxMWGpEcE1SaWlrcFE3N21nOEt2S2Y2bGZ0TAotLS0tLUVORCBQUklWQVRFIEtFWS0tLS0t
|
||||
|
||||
---
|
||||
kind: GatewayClass
|
||||
apiVersion: gateway.networking.k8s.io/v1
|
||||
metadata:
|
||||
name: my-gateway-class
|
||||
spec:
|
||||
controllerName: traefik.io/gateway-controller
|
||||
|
||||
---
|
||||
kind: Gateway
|
||||
apiVersion: gateway.networking.k8s.io/v1
|
||||
metadata:
|
||||
name: my-gateway
|
||||
namespace: default
|
||||
spec:
|
||||
gatewayClassName: my-gateway-class
|
||||
listeners:
|
||||
- name: tls
|
||||
protocol: TLS
|
||||
port: 9001
|
||||
hostname: foo.com
|
||||
tls:
|
||||
mode: Terminate
|
||||
certificateRefs:
|
||||
- kind: Secret
|
||||
name: supersecret
|
||||
group: ""
|
||||
allowedRoutes:
|
||||
kinds:
|
||||
- kind: TLSRoute
|
||||
group: gateway.networking.k8s.io
|
||||
namespaces:
|
||||
from: Same
|
||||
tls:
|
||||
backend:
|
||||
clientCertificateRef:
|
||||
group: ""
|
||||
kind: Secret
|
||||
name: client-cert
|
||||
|
||||
---
|
||||
kind: TLSRoute
|
||||
apiVersion: gateway.networking.k8s.io/v1
|
||||
metadata:
|
||||
name: tls-app-1
|
||||
namespace: default
|
||||
spec:
|
||||
parentRefs:
|
||||
- name: my-gateway
|
||||
kind: Gateway
|
||||
group: gateway.networking.k8s.io
|
||||
rules:
|
||||
- backendRefs:
|
||||
- name: whoami
|
||||
port: 80
|
||||
weight: 1
|
||||
|
||||
---
|
||||
kind: BackendTLSPolicy
|
||||
apiVersion: gateway.networking.k8s.io/v1
|
||||
metadata:
|
||||
name: policy-1
|
||||
namespace: default
|
||||
spec:
|
||||
targetRefs:
|
||||
- group: ""
|
||||
kind: Service
|
||||
name: whoami
|
||||
validation:
|
||||
hostname: whoami
|
||||
caCertificateRefs:
|
||||
- group: ""
|
||||
kind: ConfigMap
|
||||
name: ca-file
|
||||
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: ca-file
|
||||
namespace: default
|
||||
data:
|
||||
ca.crt: "CA1"
|
||||
@@ -428,7 +428,7 @@ func (p *Provider) loadGRPCServers(gatewayName, gatewayNamespace, namespace stri
|
||||
}
|
||||
|
||||
var resolvedRefCondition metav1.Condition
|
||||
serversTransport, resolvedRefCondition = p.loadServersTransport(namespace, policy)
|
||||
serversTransport, resolvedRefCondition = p.loadServersTransport(namespace, policy, listener.BackendClientCertificates)
|
||||
|
||||
policyAncestorStatus.Conditions = append(policyAncestorStatus.Conditions, resolvedRefCondition)
|
||||
if resolvedRefCondition.Status == metav1.ConditionFalse {
|
||||
|
||||
@@ -612,7 +612,7 @@ func (p *Provider) loadHTTPServers(gatewayName, gatewayNamespace, namespace stri
|
||||
}
|
||||
|
||||
var resolvedRefCondition metav1.Condition
|
||||
serversTransport, resolvedRefCondition = p.loadServersTransport(namespace, policy)
|
||||
serversTransport, resolvedRefCondition = p.loadServersTransport(namespace, policy, listener.BackendClientCertificates)
|
||||
|
||||
policyAncestorStatus.Conditions = append(policyAncestorStatus.Conditions, resolvedRefCondition)
|
||||
if resolvedRefCondition.Status == metav1.ConditionFalse {
|
||||
@@ -678,9 +678,10 @@ func (p *Provider) loadHTTPServers(gatewayName, gatewayNamespace, namespace stri
|
||||
return lb, serversTransport, nil
|
||||
}
|
||||
|
||||
func (p *Provider) loadServersTransport(namespace string, policy *gatev1.BackendTLSPolicy) (*dynamic.ServersTransport, metav1.Condition) {
|
||||
func (p *Provider) loadServersTransport(namespace string, policy *gatev1.BackendTLSPolicy, clientCertificates tls.Certificates) (*dynamic.ServersTransport, metav1.Condition) {
|
||||
st := &dynamic.ServersTransport{
|
||||
ServerName: string(policy.Spec.Validation.Hostname),
|
||||
ServerName: string(policy.Spec.Validation.Hostname),
|
||||
Certificates: clientCertificates,
|
||||
}
|
||||
|
||||
if len(policy.Spec.Validation.SubjectAltNames) > 0 {
|
||||
|
||||
@@ -28,6 +28,7 @@ import (
|
||||
"github.com/traefik/traefik/v3/pkg/tls"
|
||||
"github.com/traefik/traefik/v3/pkg/types"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
ktypes "k8s.io/apimachinery/pkg/types"
|
||||
@@ -173,11 +174,17 @@ type gatewayListener struct {
|
||||
|
||||
// ListenerSet is the ListenerSet declaring this listener, nil when the Gateway declares it itself.
|
||||
ListenerSet *gatev1.ListenerSet
|
||||
|
||||
// BackendClientCertificates are the client certificates the Gateway presents to the backends using TLS.
|
||||
BackendClientCertificates tls.Certificates
|
||||
}
|
||||
|
||||
type gatewayWithListeners struct {
|
||||
gateway *gatev1.Gateway
|
||||
listeners []gatewayListener
|
||||
// errResolvedRefsCondition is the ResolvedRefs condition reporting an unresolved Gateway own reference,
|
||||
// nil when they are all resolved.
|
||||
errResolvedRefsCondition *metav1.Condition
|
||||
}
|
||||
|
||||
// RegisterFilterFuncs registers an allowed Group, Kind, and builder for the Filter ExtensionRef objects.
|
||||
@@ -472,9 +479,17 @@ func (p *Provider) loadConfigurationFromGateways(ctx context.Context) (*dynamic.
|
||||
|
||||
listeners = append(listeners, p.loadListenerSetListeners(logger.WithContext(ctx), gateway, listenerSets, claims, conf, statusReport)...)
|
||||
|
||||
// The backend TLS configuration is defined at the Gateway level,
|
||||
// so the ListenerSet listeners use the one of their parent Gateway.
|
||||
backendClientCertificates, errResolvedRefsCondition := p.loadGatewayBackendTLS(gateway)
|
||||
for i := range listeners {
|
||||
listeners[i].BackendClientCertificates = backendClientCertificates
|
||||
}
|
||||
|
||||
gatewaysWithListeners = append(gatewaysWithListeners, gatewayWithListeners{
|
||||
gateway: gateway,
|
||||
listeners: listeners,
|
||||
gateway: gateway,
|
||||
listeners: listeners,
|
||||
errResolvedRefsCondition: errResolvedRefsCondition,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -508,7 +523,7 @@ func (p *Provider) loadConfigurationFromGateways(ctx context.Context) (*dynamic.
|
||||
return len(listener.Status.Conditions) == 0
|
||||
})
|
||||
|
||||
gatewayStatus, errConditions := p.makeGatewayStatus(gwl.gateway, gwl.listeners, addresses, accepted)
|
||||
gatewayStatus, errConditions := p.makeGatewayStatus(gwl, addresses, accepted)
|
||||
if len(errConditions) > 0 {
|
||||
messages := map[string]struct{}{}
|
||||
for _, condition := range errConditions {
|
||||
@@ -1174,15 +1189,15 @@ func (p *Provider) resolveCACertificateRefs(gateway *gatev1.Gateway, refs []gate
|
||||
return caCert, nil
|
||||
}
|
||||
|
||||
func (p *Provider) makeGatewayStatus(gateway *gatev1.Gateway, listeners []gatewayListener, addresses []gatev1.GatewayStatusAddress, accepted bool) (gatev1.GatewayStatus, []metav1.Condition) {
|
||||
func (p *Provider) makeGatewayStatus(gwl gatewayWithListeners, addresses []gatev1.GatewayStatusAddress, accepted bool) (gatev1.GatewayStatus, []metav1.Condition) {
|
||||
gatewayStatus := gatev1.GatewayStatus{Addresses: addresses}
|
||||
|
||||
// The spec requires the InsecureFrontendValidationMode condition when any validation allows an insecure fallback.
|
||||
if hasInsecureFrontendValidationMode(gateway) {
|
||||
if hasInsecureFrontendValidationMode(gwl.gateway) {
|
||||
gatewayStatus.Conditions = append(gatewayStatus.Conditions, metav1.Condition{
|
||||
Type: string(gatev1.GatewayConditionInsecureFrontendValidationMode),
|
||||
Status: metav1.ConditionTrue,
|
||||
ObservedGeneration: gateway.Generation,
|
||||
ObservedGeneration: gwl.gateway.Generation,
|
||||
LastTransitionTime: metav1.Now(),
|
||||
Reason: string(gatev1.GatewayReasonConfigurationChanged),
|
||||
Message: "FrontendValidationMode is set to AllowInsecureFallback",
|
||||
@@ -1190,7 +1205,8 @@ func (p *Provider) makeGatewayStatus(gateway *gatev1.Gateway, listeners []gatewa
|
||||
}
|
||||
|
||||
var errorConditions []metav1.Condition
|
||||
for _, listener := range listeners {
|
||||
var unresolvedListenerRefs bool
|
||||
for _, listener := range gwl.listeners {
|
||||
// The ListenerSet listeners are reported in their own ListenerSet status.
|
||||
if listener.ListenerSet != nil {
|
||||
continue
|
||||
@@ -1201,7 +1217,7 @@ func (p *Provider) makeGatewayStatus(gateway *gatev1.Gateway, listeners []gatewa
|
||||
metav1.Condition{
|
||||
Type: string(gatev1.ListenerConditionAccepted),
|
||||
Status: metav1.ConditionTrue,
|
||||
ObservedGeneration: gateway.Generation,
|
||||
ObservedGeneration: gwl.gateway.Generation,
|
||||
LastTransitionTime: metav1.Now(),
|
||||
Reason: string(gatev1.ListenerReasonAccepted),
|
||||
Message: conditionNoErrorMessage,
|
||||
@@ -1209,7 +1225,7 @@ func (p *Provider) makeGatewayStatus(gateway *gatev1.Gateway, listeners []gatewa
|
||||
metav1.Condition{
|
||||
Type: string(gatev1.ListenerConditionResolvedRefs),
|
||||
Status: metav1.ConditionTrue,
|
||||
ObservedGeneration: gateway.Generation,
|
||||
ObservedGeneration: gwl.gateway.Generation,
|
||||
LastTransitionTime: metav1.Now(),
|
||||
Reason: string(gatev1.ListenerReasonResolvedRefs),
|
||||
Message: conditionNoErrorMessage,
|
||||
@@ -1217,7 +1233,7 @@ func (p *Provider) makeGatewayStatus(gateway *gatev1.Gateway, listeners []gatewa
|
||||
metav1.Condition{
|
||||
Type: string(gatev1.ListenerConditionProgrammed),
|
||||
Status: metav1.ConditionTrue,
|
||||
ObservedGeneration: gateway.Generation,
|
||||
ObservedGeneration: gwl.gateway.Generation,
|
||||
LastTransitionTime: metav1.Now(),
|
||||
Reason: string(gatev1.ListenerReasonProgrammed),
|
||||
Message: conditionNoErrorMessage,
|
||||
@@ -1231,15 +1247,22 @@ func (p *Provider) makeGatewayStatus(gateway *gatev1.Gateway, listeners []gatewa
|
||||
|
||||
errorConditions = append(errorConditions, listener.Status.Conditions...)
|
||||
gatewayStatus.Listeners = append(gatewayStatus.Listeners, *listener.Status)
|
||||
|
||||
if meta.IsStatusConditionFalse(listener.Status.Conditions, string(gatev1.ListenerConditionResolvedRefs)) {
|
||||
unresolvedListenerRefs = true
|
||||
}
|
||||
}
|
||||
|
||||
// The ResolvedRefs condition does not impact the Accepted and Programmed conditions.
|
||||
gatewayStatus.Conditions = append(gatewayStatus.Conditions, makeGatewayResolvedRefsCondition(gwl, unresolvedListenerRefs))
|
||||
|
||||
// Traefik supports no infrastructure parameters, and the specification requires
|
||||
// a parametersRef that cannot be resolved to be reported instead of ignored.
|
||||
if gateway.Spec.Infrastructure != nil && gateway.Spec.Infrastructure.ParametersRef != nil {
|
||||
if gwl.gateway.Spec.Infrastructure != nil && gwl.gateway.Spec.Infrastructure.ParametersRef != nil {
|
||||
condition := metav1.Condition{
|
||||
Type: string(gatev1.GatewayConditionAccepted),
|
||||
Status: metav1.ConditionFalse,
|
||||
ObservedGeneration: gateway.Generation,
|
||||
ObservedGeneration: gwl.gateway.Generation,
|
||||
LastTransitionTime: metav1.Now(),
|
||||
Reason: string(gatev1.GatewayReasonInvalidParameters),
|
||||
Message: "Gateway infrastructure parametersRef is not supported",
|
||||
@@ -1255,7 +1278,7 @@ func (p *Provider) makeGatewayStatus(gateway *gatev1.Gateway, listeners []gatewa
|
||||
metav1.Condition{
|
||||
Type: string(gatev1.GatewayConditionAccepted),
|
||||
Status: metav1.ConditionFalse,
|
||||
ObservedGeneration: gateway.Generation,
|
||||
ObservedGeneration: gwl.gateway.Generation,
|
||||
Reason: string(gatev1.GatewayReasonListenersNotValid),
|
||||
Message: "At least one Listener must be valid",
|
||||
LastTransitionTime: metav1.Now(),
|
||||
@@ -1264,7 +1287,7 @@ func (p *Provider) makeGatewayStatus(gateway *gatev1.Gateway, listeners []gatewa
|
||||
metav1.Condition{
|
||||
Type: string(gatev1.GatewayConditionProgrammed),
|
||||
Status: metav1.ConditionFalse,
|
||||
ObservedGeneration: gateway.Generation,
|
||||
ObservedGeneration: gwl.gateway.Generation,
|
||||
Reason: string(gatev1.GatewayReasonInvalid),
|
||||
Message: "No Listener is valid",
|
||||
LastTransitionTime: metav1.Now(),
|
||||
@@ -1288,7 +1311,7 @@ func (p *Provider) makeGatewayStatus(gateway *gatev1.Gateway, listeners []gatewa
|
||||
metav1.Condition{
|
||||
Type: string(gatev1.GatewayConditionAccepted),
|
||||
Status: metav1.ConditionTrue,
|
||||
ObservedGeneration: gateway.Generation,
|
||||
ObservedGeneration: gwl.gateway.Generation,
|
||||
Reason: string(acceptedConditionReason),
|
||||
Message: acceptedConditionMessage,
|
||||
LastTransitionTime: metav1.Now(),
|
||||
@@ -1297,7 +1320,7 @@ func (p *Provider) makeGatewayStatus(gateway *gatev1.Gateway, listeners []gatewa
|
||||
metav1.Condition{
|
||||
Type: string(gatev1.GatewayConditionProgrammed),
|
||||
Status: metav1.ConditionTrue,
|
||||
ObservedGeneration: gateway.Generation,
|
||||
ObservedGeneration: gwl.gateway.Generation,
|
||||
Reason: string(gatev1.GatewayReasonProgrammed),
|
||||
Message: programmedConditionMessage,
|
||||
LastTransitionTime: metav1.Now(),
|
||||
@@ -1307,6 +1330,35 @@ func (p *Provider) makeGatewayStatus(gateway *gatev1.Gateway, listeners []gatewa
|
||||
return gatewayStatus, nil
|
||||
}
|
||||
|
||||
// makeGatewayResolvedRefsCondition makes the Gateway ResolvedRefs condition,
|
||||
// which the specification makes a summary of the listeners ResolvedRefs condition too.
|
||||
func makeGatewayResolvedRefsCondition(gwl gatewayWithListeners, unresolvedListenerRefs bool) metav1.Condition {
|
||||
// The Gateway own unresolved references take precedence over the listeners ones.
|
||||
if gwl.errResolvedRefsCondition != nil {
|
||||
return *gwl.errResolvedRefsCondition
|
||||
}
|
||||
|
||||
if unresolvedListenerRefs {
|
||||
return metav1.Condition{
|
||||
Type: string(gatev1.GatewayConditionResolvedRefs),
|
||||
Status: metav1.ConditionFalse,
|
||||
ObservedGeneration: gwl.gateway.Generation,
|
||||
LastTransitionTime: metav1.Now(),
|
||||
Reason: string(gatev1.GatewayReasonListenersNotResolved),
|
||||
Message: "At least one Listener has unresolved references",
|
||||
}
|
||||
}
|
||||
|
||||
return metav1.Condition{
|
||||
Type: string(gatev1.GatewayConditionResolvedRefs),
|
||||
Status: metav1.ConditionTrue,
|
||||
ObservedGeneration: gwl.gateway.Generation,
|
||||
LastTransitionTime: metav1.Now(),
|
||||
Reason: string(gatev1.GatewayReasonResolvedRefs),
|
||||
Message: conditionNoErrorMessage,
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Provider) gatewayAddresses() ([]gatev1.GatewayStatusAddress, error) {
|
||||
if p.StatusAddress == nil {
|
||||
return nil, nil
|
||||
@@ -1392,6 +1444,56 @@ func (p *Provider) isReferenceGranted(fromKind, fromNamespace, toGroup, toKind,
|
||||
return nil
|
||||
}
|
||||
|
||||
// loadGatewayBackendTLS resolves the client certificate the Gateway presents to the backends using TLS.
|
||||
// It returns no certificate when the Gateway does not define one,
|
||||
// and the ResolvedRefs condition to report when the reference cannot be resolved.
|
||||
func (p *Provider) loadGatewayBackendTLS(gateway *gatev1.Gateway) (tls.Certificates, *metav1.Condition) {
|
||||
if gateway.Spec.TLS == nil || gateway.Spec.TLS.Backend == nil || gateway.Spec.TLS.Backend.ClientCertificateRef == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
certRef := gateway.Spec.TLS.Backend.ClientCertificateRef
|
||||
|
||||
group := ptr.Deref(certRef.Group, "")
|
||||
kind := ptr.Deref(certRef.Kind, kindSecret)
|
||||
if (group != "" && group != groupCore) || kind != kindSecret {
|
||||
return nil, &metav1.Condition{
|
||||
Type: string(gatev1.GatewayConditionResolvedRefs),
|
||||
Status: metav1.ConditionFalse,
|
||||
ObservedGeneration: gateway.Generation,
|
||||
LastTransitionTime: metav1.Now(),
|
||||
Reason: string(gatev1.GatewayReasonInvalidClientCertificateRef),
|
||||
Message: fmt.Sprintf("Unsupported ClientCertificateRef group/kind: %s/%s", group, kind),
|
||||
}
|
||||
}
|
||||
|
||||
namespace := string(ptr.Deref(certRef.Namespace, gatev1.Namespace(gateway.Namespace)))
|
||||
if err := p.isReferenceGranted(kindGateway, gateway.Namespace, groupCore, kindSecret, string(certRef.Name), namespace); err != nil {
|
||||
return nil, &metav1.Condition{
|
||||
Type: string(gatev1.GatewayConditionResolvedRefs),
|
||||
Status: metav1.ConditionFalse,
|
||||
ObservedGeneration: gateway.Generation,
|
||||
LastTransitionTime: metav1.Now(),
|
||||
Reason: string(gatev1.GatewayReasonRefNotPermitted),
|
||||
Message: fmt.Sprintf("Cannot reference ClientCertificateRef %s/%s: %s", namespace, certRef.Name, err),
|
||||
}
|
||||
}
|
||||
|
||||
cert, err := p.getTLSCert(certRef.Name, namespace)
|
||||
if err != nil {
|
||||
return nil, &metav1.Condition{
|
||||
Type: string(gatev1.GatewayConditionResolvedRefs),
|
||||
Status: metav1.ConditionFalse,
|
||||
ObservedGeneration: gateway.Generation,
|
||||
LastTransitionTime: metav1.Now(),
|
||||
Reason: string(gatev1.GatewayReasonInvalidClientCertificateRef),
|
||||
Message: fmt.Sprintf("Cannot load ClientCertificateRef %s/%s: %s", namespace, certRef.Name, err),
|
||||
}
|
||||
}
|
||||
|
||||
return tls.Certificates{cert.Certificate}, nil
|
||||
}
|
||||
|
||||
func (p *Provider) getTLSCert(secretName gatev1.ObjectName, namespace string) (*tls.CertAndStores, error) {
|
||||
secret, err := p.client.GetSecret(namespace, string(secretName))
|
||||
if err != nil {
|
||||
|
||||
@@ -66,6 +66,24 @@ MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgnwgL5DY4UB14sM6f
|
||||
DikQdtqh2QW1ArfF4fc1UFzifdGhRANCAAQzq4sN2UO8CIVq2z0uiRUE9206DQhd
|
||||
NL0leX2m+k218i/LZbBq3k0SBdhMILLXjDpMRiikpQ77mg8KvKf6lftL
|
||||
-----END PRIVATE KEY-----`
|
||||
otherClientCert string = `-----BEGIN CERTIFICATE-----
|
||||
MIIBpTCCAUugAwIBAgIUTEkUEMCmZrxxiEkCm0PS+FquusQwCgYIKoZIzj0EAwIw
|
||||
GjEYMBYGA1UEAwwPYmFyLmV4YW1wbGUuY29tMB4XDTI2MDkxNTExNDMyNFoXDTM2
|
||||
MDkxMjExNDMyNFowGjEYMBYGA1UEAwwPYmFyLmV4YW1wbGUuY29tMFkwEwYHKoZI
|
||||
zj0CAQYIKoZIzj0DAQcDQgAEbMw+NtKeHEnQLlGGKWN0AU2HbzrG+i0XVTL0Aji5
|
||||
iw6u9lGTb4CYCmqLCsVatCtzPM/EY5vbZurwJUFTlf3yRKNvMG0wHQYDVR0OBBYE
|
||||
FL+/oYE2BbFIu90n685mqD+Q4pTUMB8GA1UdIwQYMBaAFL+/oYE2BbFIu90n685m
|
||||
qD+Q4pTUMA8GA1UdEwEB/wQFMAMBAf8wGgYDVR0RBBMwEYIPYmFyLmV4YW1wbGUu
|
||||
Y29tMAoGCCqGSM49BAMCA0gAMEUCIQDCtQ4sDkdSHQeTXJN8kppNlm40VCjq8Lvd
|
||||
iXk3GCXo8AIgbs51yX2lt1eppdHGFpn4drWx9t5tPcDddwSYUS7OBJA=
|
||||
-----END CERTIFICATE-----
|
||||
`
|
||||
otherClientKey string = `-----BEGIN PRIVATE KEY-----
|
||||
MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgOTsetfLjL3Enuk+h
|
||||
l3cWWJHvRQ14QlyBB8cArrcpVWGhRANCAARszD420p4cSdAuUYYpY3QBTYdvOsb6
|
||||
LRdVMvQCOLmLDq72UZNvgJgKaosKxVq0K3M8z8Rjm9tm6vAlQVOV/fJE
|
||||
-----END PRIVATE KEY-----
|
||||
`
|
||||
)
|
||||
|
||||
func TestGatewayClassLabelSelector(t *testing.T) {
|
||||
@@ -3429,6 +3447,441 @@ func TestLoadHTTPRoutes(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "HTTPRoute and BackendTLSPolicy with Gateway backend client certificate",
|
||||
paths: []string{"services.yml", "httproute/with_gateway_backend_client_certificate.yml"},
|
||||
entryPoints: map[string]Entrypoint{
|
||||
"web": {Address: ":80"},
|
||||
},
|
||||
expected: &dynamic.Configuration{
|
||||
UDP: &dynamic.UDPConfiguration{
|
||||
Routers: map[string]*dynamic.UDPRouter{},
|
||||
Services: map[string]*dynamic.UDPService{},
|
||||
},
|
||||
TCP: &dynamic.TCPConfiguration{
|
||||
Routers: map[string]*dynamic.TCPRouter{},
|
||||
Middlewares: map[string]*dynamic.TCPMiddleware{},
|
||||
Services: map[string]*dynamic.TCPService{},
|
||||
ServersTransports: map[string]*dynamic.TCPServersTransport{},
|
||||
},
|
||||
HTTP: &dynamic.HTTPConfiguration{
|
||||
Routers: map[string]*dynamic.Router{
|
||||
"httproute-default-http-app-1-gw-default-my-gateway-ep-web-0-799bcbf0c2317c5d1c93": {
|
||||
ParentRefs: []string{"listener-web-http-5b3226d4ebd42b7200f1"},
|
||||
Service: "httproute-default-http-app-1-gw-default-my-gateway-ep-web-0-799bcbf0c2317c5d1c93-wrr",
|
||||
Rule: `Host("foo.com") && Path("/bar")`,
|
||||
Priority: 100009,
|
||||
RuleSyntax: "default",
|
||||
},
|
||||
"httproute-default-http-app-1-gw-default-my-gateway-ep-web-1-37f0249f693ead70647a": {
|
||||
ParentRefs: []string{"listener-web-http-5b3226d4ebd42b7200f1"},
|
||||
Service: "httproute-default-http-app-1-gw-default-my-gateway-ep-web-1-37f0249f693ead70647a-wrr",
|
||||
Rule: `Host("foo.com") && Path("/foo")`,
|
||||
Priority: 100008,
|
||||
RuleSyntax: "default",
|
||||
},
|
||||
"listener-web-http-5b3226d4ebd42b7200f1": {
|
||||
EntryPoints: []string{"web"},
|
||||
Rule: `Host("*")`,
|
||||
},
|
||||
},
|
||||
Middlewares: map[string]*dynamic.Middleware{},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"httproute-default-http-app-1-gw-default-my-gateway-ep-web-0-799bcbf0c2317c5d1c93-svc-default-whoami-0": {
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Strategy: dynamic.BalancerStrategyWRR,
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "https://10.10.0.1:80",
|
||||
},
|
||||
{
|
||||
URL: "https://10.10.0.2:80",
|
||||
},
|
||||
},
|
||||
PassHostHeader: new(true),
|
||||
ResponseForwarding: &dynamic.ResponseForwarding{
|
||||
FlushInterval: ptypes.Duration(100 * time.Millisecond),
|
||||
},
|
||||
ServersTransport: "httproute-default-http-app-1-gw-default-my-gateway-ep-web-0-799bcbf0c2317c5d1c93-svc-default-whoami-0",
|
||||
},
|
||||
},
|
||||
"httproute-default-http-app-1-gw-default-my-gateway-ep-web-0-799bcbf0c2317c5d1c93-wrr": {
|
||||
Weighted: &dynamic.WeightedRoundRobin{
|
||||
Services: []dynamic.WRRService{
|
||||
{
|
||||
Name: "httproute-default-http-app-1-gw-default-my-gateway-ep-web-0-799bcbf0c2317c5d1c93-svc-default-whoami-0",
|
||||
Weight: new(1),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
"httproute-default-http-app-1-gw-default-my-gateway-ep-web-1-37f0249f693ead70647a-svc-default-whoami2-0": {
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Strategy: dynamic.BalancerStrategyWRR,
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://10.10.0.3:8080",
|
||||
},
|
||||
{
|
||||
URL: "http://10.10.0.4:8080",
|
||||
},
|
||||
},
|
||||
PassHostHeader: new(true),
|
||||
ResponseForwarding: &dynamic.ResponseForwarding{
|
||||
FlushInterval: ptypes.Duration(100 * time.Millisecond),
|
||||
},
|
||||
},
|
||||
},
|
||||
"httproute-default-http-app-1-gw-default-my-gateway-ep-web-1-37f0249f693ead70647a-wrr": {
|
||||
Weighted: &dynamic.WeightedRoundRobin{
|
||||
Services: []dynamic.WRRService{
|
||||
{
|
||||
Name: "httproute-default-http-app-1-gw-default-my-gateway-ep-web-1-37f0249f693ead70647a-svc-default-whoami2-0",
|
||||
Weight: new(1),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
ServersTransports: map[string]*dynamic.ServersTransport{
|
||||
"httproute-default-http-app-1-gw-default-my-gateway-ep-web-0-799bcbf0c2317c5d1c93-svc-default-whoami-0": {
|
||||
ServerName: "whoami",
|
||||
RootCAs: []types.FileOrContent{
|
||||
"CA1",
|
||||
},
|
||||
Certificates: tls.Certificates{
|
||||
{
|
||||
CertFile: types.FileOrContent(listenerCert),
|
||||
KeyFile: types.FileOrContent(listenerKey),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
TLS: &dynamic.TLSConfiguration{
|
||||
Options: map[string]tls.Options{},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "HTTPRoute and BackendTLSPolicy attached to two Gateways with different backend client certificates",
|
||||
paths: []string{"services.yml", "httproute/with_gateway_backend_client_certificate_two_gateways.yml"},
|
||||
entryPoints: map[string]Entrypoint{
|
||||
"web": {Address: ":80"},
|
||||
"web-alt": {Address: ":8080"},
|
||||
},
|
||||
expected: &dynamic.Configuration{
|
||||
UDP: &dynamic.UDPConfiguration{
|
||||
Routers: map[string]*dynamic.UDPRouter{},
|
||||
Services: map[string]*dynamic.UDPService{},
|
||||
},
|
||||
TCP: &dynamic.TCPConfiguration{
|
||||
Routers: map[string]*dynamic.TCPRouter{},
|
||||
Middlewares: map[string]*dynamic.TCPMiddleware{},
|
||||
Services: map[string]*dynamic.TCPService{},
|
||||
ServersTransports: map[string]*dynamic.TCPServersTransport{},
|
||||
},
|
||||
HTTP: &dynamic.HTTPConfiguration{
|
||||
Routers: map[string]*dynamic.Router{
|
||||
"httproute-default-http-app-1-gw-default-my-gateway-ep-web-0-799bcbf0c2317c5d1c93": {
|
||||
ParentRefs: []string{"listener-web-http-5b3226d4ebd42b7200f1"},
|
||||
Service: "httproute-default-http-app-1-gw-default-my-gateway-ep-web-0-799bcbf0c2317c5d1c93-wrr",
|
||||
Rule: `Host("foo.com") && Path("/bar")`,
|
||||
Priority: 100009,
|
||||
RuleSyntax: "default",
|
||||
},
|
||||
"httproute-default-http-app-1-gw-default-my-gateway-ep-web-1-37f0249f693ead70647a": {
|
||||
ParentRefs: []string{"listener-web-http-5b3226d4ebd42b7200f1"},
|
||||
Service: "httproute-default-http-app-1-gw-default-my-gateway-ep-web-1-37f0249f693ead70647a-wrr",
|
||||
Rule: `Host("foo.com") && Path("/foo")`,
|
||||
Priority: 100008,
|
||||
RuleSyntax: "default",
|
||||
},
|
||||
"httproute-default-http-app-1-gw-default-my-other-gateway-ep-web-alt-0-8643b4eec05412c1ca31": {
|
||||
ParentRefs: []string{"listener-web-alt-http-f9685282dacd58da3164"},
|
||||
Service: "httproute-default-http-app-1-gw-default-my-other-gateway-ep-web-alt-0-8643b4eec05412c1ca31-wrr",
|
||||
Rule: `Host("foo.com") && Path("/bar")`,
|
||||
Priority: 100009,
|
||||
RuleSyntax: "default",
|
||||
},
|
||||
"httproute-default-http-app-1-gw-default-my-other-gateway-ep-web-alt-1-598fb9b61886d4edc744": {
|
||||
ParentRefs: []string{"listener-web-alt-http-f9685282dacd58da3164"},
|
||||
Service: "httproute-default-http-app-1-gw-default-my-other-gateway-ep-web-alt-1-598fb9b61886d4edc744-wrr",
|
||||
Rule: `Host("foo.com") && Path("/foo")`,
|
||||
Priority: 100008,
|
||||
RuleSyntax: "default",
|
||||
},
|
||||
"listener-web-alt-http-f9685282dacd58da3164": {
|
||||
EntryPoints: []string{"web-alt"},
|
||||
Rule: `Host("*")`,
|
||||
},
|
||||
"listener-web-http-5b3226d4ebd42b7200f1": {
|
||||
EntryPoints: []string{"web"},
|
||||
Rule: `Host("*")`,
|
||||
},
|
||||
},
|
||||
Middlewares: map[string]*dynamic.Middleware{},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"httproute-default-http-app-1-gw-default-my-gateway-ep-web-0-799bcbf0c2317c5d1c93-svc-default-whoami-0": {
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Strategy: dynamic.BalancerStrategyWRR,
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "https://10.10.0.1:80",
|
||||
},
|
||||
{
|
||||
URL: "https://10.10.0.2:80",
|
||||
},
|
||||
},
|
||||
PassHostHeader: new(true),
|
||||
ResponseForwarding: &dynamic.ResponseForwarding{
|
||||
FlushInterval: ptypes.Duration(100 * time.Millisecond),
|
||||
},
|
||||
ServersTransport: "httproute-default-http-app-1-gw-default-my-gateway-ep-web-0-799bcbf0c2317c5d1c93-svc-default-whoami-0",
|
||||
},
|
||||
},
|
||||
"httproute-default-http-app-1-gw-default-my-gateway-ep-web-0-799bcbf0c2317c5d1c93-wrr": {
|
||||
Weighted: &dynamic.WeightedRoundRobin{
|
||||
Services: []dynamic.WRRService{
|
||||
{
|
||||
Name: "httproute-default-http-app-1-gw-default-my-gateway-ep-web-0-799bcbf0c2317c5d1c93-svc-default-whoami-0",
|
||||
Weight: new(1),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
"httproute-default-http-app-1-gw-default-my-gateway-ep-web-1-37f0249f693ead70647a-svc-default-whoami2-0": {
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Strategy: dynamic.BalancerStrategyWRR,
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://10.10.0.3:8080",
|
||||
},
|
||||
{
|
||||
URL: "http://10.10.0.4:8080",
|
||||
},
|
||||
},
|
||||
PassHostHeader: new(true),
|
||||
ResponseForwarding: &dynamic.ResponseForwarding{
|
||||
FlushInterval: ptypes.Duration(100 * time.Millisecond),
|
||||
},
|
||||
},
|
||||
},
|
||||
"httproute-default-http-app-1-gw-default-my-gateway-ep-web-1-37f0249f693ead70647a-wrr": {
|
||||
Weighted: &dynamic.WeightedRoundRobin{
|
||||
Services: []dynamic.WRRService{
|
||||
{
|
||||
Name: "httproute-default-http-app-1-gw-default-my-gateway-ep-web-1-37f0249f693ead70647a-svc-default-whoami2-0",
|
||||
Weight: new(1),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
"httproute-default-http-app-1-gw-default-my-other-gateway-ep-web-alt-0-8643b4eec05412c1ca31-svc-default-whoami-0": {
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Strategy: dynamic.BalancerStrategyWRR,
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "https://10.10.0.1:80",
|
||||
},
|
||||
{
|
||||
URL: "https://10.10.0.2:80",
|
||||
},
|
||||
},
|
||||
PassHostHeader: new(true),
|
||||
ResponseForwarding: &dynamic.ResponseForwarding{
|
||||
FlushInterval: ptypes.Duration(100 * time.Millisecond),
|
||||
},
|
||||
ServersTransport: "httproute-default-http-app-1-gw-default-my-other-gateway-ep-web-alt-0-8643b4eec05412c1ca31-svc-default-whoami-0",
|
||||
},
|
||||
},
|
||||
"httproute-default-http-app-1-gw-default-my-other-gateway-ep-web-alt-0-8643b4eec05412c1ca31-wrr": {
|
||||
Weighted: &dynamic.WeightedRoundRobin{
|
||||
Services: []dynamic.WRRService{
|
||||
{
|
||||
Name: "httproute-default-http-app-1-gw-default-my-other-gateway-ep-web-alt-0-8643b4eec05412c1ca31-svc-default-whoami-0",
|
||||
Weight: new(1),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
"httproute-default-http-app-1-gw-default-my-other-gateway-ep-web-alt-1-598fb9b61886d4edc744-svc-default-whoami2-0": {
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Strategy: dynamic.BalancerStrategyWRR,
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://10.10.0.3:8080",
|
||||
},
|
||||
{
|
||||
URL: "http://10.10.0.4:8080",
|
||||
},
|
||||
},
|
||||
PassHostHeader: new(true),
|
||||
ResponseForwarding: &dynamic.ResponseForwarding{
|
||||
FlushInterval: ptypes.Duration(100 * time.Millisecond),
|
||||
},
|
||||
},
|
||||
},
|
||||
"httproute-default-http-app-1-gw-default-my-other-gateway-ep-web-alt-1-598fb9b61886d4edc744-wrr": {
|
||||
Weighted: &dynamic.WeightedRoundRobin{
|
||||
Services: []dynamic.WRRService{
|
||||
{
|
||||
Name: "httproute-default-http-app-1-gw-default-my-other-gateway-ep-web-alt-1-598fb9b61886d4edc744-svc-default-whoami2-0",
|
||||
Weight: new(1),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
ServersTransports: map[string]*dynamic.ServersTransport{
|
||||
"httproute-default-http-app-1-gw-default-my-gateway-ep-web-0-799bcbf0c2317c5d1c93-svc-default-whoami-0": {
|
||||
ServerName: "whoami",
|
||||
RootCAs: []types.FileOrContent{
|
||||
"CA1",
|
||||
},
|
||||
Certificates: tls.Certificates{
|
||||
{
|
||||
CertFile: types.FileOrContent(listenerCert),
|
||||
KeyFile: types.FileOrContent(listenerKey),
|
||||
},
|
||||
},
|
||||
},
|
||||
"httproute-default-http-app-1-gw-default-my-other-gateway-ep-web-alt-0-8643b4eec05412c1ca31-svc-default-whoami-0": {
|
||||
ServerName: "whoami",
|
||||
RootCAs: []types.FileOrContent{
|
||||
"CA1",
|
||||
},
|
||||
Certificates: tls.Certificates{
|
||||
{
|
||||
CertFile: types.FileOrContent(otherClientCert),
|
||||
KeyFile: types.FileOrContent(otherClientKey),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
TLS: &dynamic.TLSConfiguration{
|
||||
Options: map[string]tls.Options{},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "HTTPRoute and BackendTLSPolicy attached to a ListenerSet with Gateway backend client certificate",
|
||||
paths: []string{"services.yml", "httproute/with_gateway_backend_client_certificate_listenerset.yml"},
|
||||
entryPoints: map[string]Entrypoint{
|
||||
"web": {Address: ":80"},
|
||||
"web-alt": {Address: ":8080"},
|
||||
},
|
||||
expected: &dynamic.Configuration{
|
||||
UDP: &dynamic.UDPConfiguration{
|
||||
Routers: map[string]*dynamic.UDPRouter{},
|
||||
Services: map[string]*dynamic.UDPService{},
|
||||
},
|
||||
TCP: &dynamic.TCPConfiguration{
|
||||
Routers: map[string]*dynamic.TCPRouter{},
|
||||
Middlewares: map[string]*dynamic.TCPMiddleware{},
|
||||
Services: map[string]*dynamic.TCPService{},
|
||||
ServersTransports: map[string]*dynamic.TCPServersTransport{},
|
||||
},
|
||||
HTTP: &dynamic.HTTPConfiguration{
|
||||
Routers: map[string]*dynamic.Router{
|
||||
"httproute-default-http-app-1-gw-default-my-gateway-ep-web-alt-0-6d65ece8c8e5c1272ab8": {
|
||||
ParentRefs: []string{"listener-web-alt-http-f9685282dacd58da3164"},
|
||||
Service: "httproute-default-http-app-1-gw-default-my-gateway-ep-web-alt-0-6d65ece8c8e5c1272ab8-wrr",
|
||||
Rule: `Host("foo.com") && Path("/bar")`,
|
||||
Priority: 100009,
|
||||
RuleSyntax: "default",
|
||||
},
|
||||
"httproute-default-http-app-1-gw-default-my-gateway-ep-web-alt-1-cc507dc61ee70b0f1b77": {
|
||||
ParentRefs: []string{"listener-web-alt-http-f9685282dacd58da3164"},
|
||||
Service: "httproute-default-http-app-1-gw-default-my-gateway-ep-web-alt-1-cc507dc61ee70b0f1b77-wrr",
|
||||
Rule: `Host("foo.com") && Path("/foo")`,
|
||||
Priority: 100008,
|
||||
RuleSyntax: "default",
|
||||
},
|
||||
"listener-web-alt-http-f9685282dacd58da3164": {
|
||||
EntryPoints: []string{"web-alt"},
|
||||
Rule: `Host("*")`,
|
||||
},
|
||||
},
|
||||
Middlewares: map[string]*dynamic.Middleware{},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"httproute-default-http-app-1-gw-default-my-gateway-ep-web-alt-0-6d65ece8c8e5c1272ab8-svc-default-whoami-0": {
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Strategy: dynamic.BalancerStrategyWRR,
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "https://10.10.0.1:80",
|
||||
},
|
||||
{
|
||||
URL: "https://10.10.0.2:80",
|
||||
},
|
||||
},
|
||||
PassHostHeader: new(true),
|
||||
ResponseForwarding: &dynamic.ResponseForwarding{
|
||||
FlushInterval: ptypes.Duration(100 * time.Millisecond),
|
||||
},
|
||||
ServersTransport: "httproute-default-http-app-1-gw-default-my-gateway-ep-web-alt-0-6d65ece8c8e5c1272ab8-svc-default-whoami-0",
|
||||
},
|
||||
},
|
||||
"httproute-default-http-app-1-gw-default-my-gateway-ep-web-alt-0-6d65ece8c8e5c1272ab8-wrr": {
|
||||
Weighted: &dynamic.WeightedRoundRobin{
|
||||
Services: []dynamic.WRRService{
|
||||
{
|
||||
Name: "httproute-default-http-app-1-gw-default-my-gateway-ep-web-alt-0-6d65ece8c8e5c1272ab8-svc-default-whoami-0",
|
||||
Weight: new(1),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
"httproute-default-http-app-1-gw-default-my-gateway-ep-web-alt-1-cc507dc61ee70b0f1b77-svc-default-whoami2-0": {
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Strategy: dynamic.BalancerStrategyWRR,
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://10.10.0.3:8080",
|
||||
},
|
||||
{
|
||||
URL: "http://10.10.0.4:8080",
|
||||
},
|
||||
},
|
||||
PassHostHeader: new(true),
|
||||
ResponseForwarding: &dynamic.ResponseForwarding{
|
||||
FlushInterval: ptypes.Duration(100 * time.Millisecond),
|
||||
},
|
||||
},
|
||||
},
|
||||
"httproute-default-http-app-1-gw-default-my-gateway-ep-web-alt-1-cc507dc61ee70b0f1b77-wrr": {
|
||||
Weighted: &dynamic.WeightedRoundRobin{
|
||||
Services: []dynamic.WRRService{
|
||||
{
|
||||
Name: "httproute-default-http-app-1-gw-default-my-gateway-ep-web-alt-1-cc507dc61ee70b0f1b77-svc-default-whoami2-0",
|
||||
Weight: new(1),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
ServersTransports: map[string]*dynamic.ServersTransport{
|
||||
"httproute-default-http-app-1-gw-default-my-gateway-ep-web-alt-0-6d65ece8c8e5c1272ab8-svc-default-whoami-0": {
|
||||
ServerName: "whoami",
|
||||
RootCAs: []types.FileOrContent{
|
||||
"CA1",
|
||||
},
|
||||
Certificates: tls.Certificates{
|
||||
{
|
||||
CertFile: types.FileOrContent(listenerCert),
|
||||
KeyFile: types.FileOrContent(listenerKey),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
TLS: &dynamic.TLSConfiguration{
|
||||
Options: map[string]tls.Options{},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "Simple HTTPRoute and BackendTLSPolicy with subjectAltNames",
|
||||
paths: []string{"services.yml", "httproute/with_backend_tls_policy_san.yml"},
|
||||
@@ -5402,6 +5855,88 @@ func TestLoadGRPCRoutes(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "GRPCRoute and BackendTLSPolicy with Gateway backend client certificate",
|
||||
paths: []string{"services.yml", "grpcroute/with_gateway_backend_client_certificate.yml"},
|
||||
entryPoints: map[string]Entrypoint{
|
||||
"web": {Address: ":80"},
|
||||
},
|
||||
expected: &dynamic.Configuration{
|
||||
UDP: &dynamic.UDPConfiguration{
|
||||
Routers: map[string]*dynamic.UDPRouter{},
|
||||
Services: map[string]*dynamic.UDPService{},
|
||||
},
|
||||
TCP: &dynamic.TCPConfiguration{
|
||||
Routers: map[string]*dynamic.TCPRouter{},
|
||||
Middlewares: map[string]*dynamic.TCPMiddleware{},
|
||||
Services: map[string]*dynamic.TCPService{},
|
||||
ServersTransports: map[string]*dynamic.TCPServersTransport{},
|
||||
},
|
||||
HTTP: &dynamic.HTTPConfiguration{
|
||||
Routers: map[string]*dynamic.Router{
|
||||
"grpcroute-default-grpc-app-1-gw-default-my-gateway-ep-web-0-0abda411573f19f36296": {
|
||||
ParentRefs: []string{"listener-web-http-5b3226d4ebd42b7200f1"},
|
||||
Service: "grpcroute-default-grpc-app-1-gw-default-my-gateway-ep-web-0-0abda411573f19f36296-wrr",
|
||||
Rule: `Host("foo.com") && PathPrefix("/")`,
|
||||
Priority: 22,
|
||||
RuleSyntax: "default",
|
||||
},
|
||||
"listener-web-http-5b3226d4ebd42b7200f1": {
|
||||
EntryPoints: []string{"web"},
|
||||
Rule: `Host("*")`,
|
||||
},
|
||||
},
|
||||
Middlewares: map[string]*dynamic.Middleware{},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"grpcroute-default-grpc-app-1-gw-default-my-gateway-ep-web-0-0abda411573f19f36296-svc-default-whoami-0": {
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Strategy: dynamic.BalancerStrategyWRR,
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "https://10.10.0.1:80",
|
||||
},
|
||||
{
|
||||
URL: "https://10.10.0.2:80",
|
||||
},
|
||||
},
|
||||
PassHostHeader: new(true),
|
||||
ResponseForwarding: &dynamic.ResponseForwarding{
|
||||
FlushInterval: ptypes.Duration(100 * time.Millisecond),
|
||||
},
|
||||
ServersTransport: "grpcroute-default-grpc-app-1-gw-default-my-gateway-ep-web-0-0abda411573f19f36296-svc-default-whoami-0",
|
||||
},
|
||||
},
|
||||
"grpcroute-default-grpc-app-1-gw-default-my-gateway-ep-web-0-0abda411573f19f36296-wrr": {
|
||||
Weighted: &dynamic.WeightedRoundRobin{
|
||||
Services: []dynamic.WRRService{
|
||||
{
|
||||
Name: "grpcroute-default-grpc-app-1-gw-default-my-gateway-ep-web-0-0abda411573f19f36296-svc-default-whoami-0",
|
||||
Weight: new(1),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
ServersTransports: map[string]*dynamic.ServersTransport{
|
||||
"grpcroute-default-grpc-app-1-gw-default-my-gateway-ep-web-0-0abda411573f19f36296-svc-default-whoami-0": {
|
||||
ServerName: "whoami",
|
||||
RootCAs: []types.FileOrContent{
|
||||
"CA1",
|
||||
},
|
||||
Certificates: tls.Certificates{
|
||||
{
|
||||
CertFile: types.FileOrContent(listenerCert),
|
||||
KeyFile: types.FileOrContent(listenerKey),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
TLS: &dynamic.TLSConfiguration{
|
||||
Options: map[string]tls.Options{},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "Simple GRPCRoute and BackendTLSPolicy with subjectAltNames",
|
||||
paths: []string{"services.yml", "grpcroute/with_backend_tls_policy_san.yml"},
|
||||
@@ -9068,6 +9603,99 @@ func TestLoadTLSRoutes(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "TLSRoute and BackendTLSPolicy with Gateway backend client certificate",
|
||||
paths: []string{"services.yml", "tlsroute/with_gateway_backend_client_certificate.yml"},
|
||||
entryPoints: map[string]Entrypoint{
|
||||
"tls": {Address: ":9001"},
|
||||
},
|
||||
expected: &dynamic.Configuration{
|
||||
UDP: &dynamic.UDPConfiguration{
|
||||
Routers: map[string]*dynamic.UDPRouter{},
|
||||
Services: map[string]*dynamic.UDPService{},
|
||||
},
|
||||
TCP: &dynamic.TCPConfiguration{
|
||||
Routers: map[string]*dynamic.TCPRouter{
|
||||
"deny-unknown-host": {
|
||||
Rule: "HostSNI(`*`) && !ALPN(`h2`) && !ALPN(`http/1.1`)",
|
||||
Priority: 1,
|
||||
Service: "deny-unknown-host",
|
||||
TLS: &dynamic.RouterTCPTLSConfig{},
|
||||
},
|
||||
"tlsroute-default-tls-app-1-gw-default-my-gateway-ep-tls-0-5c999a999d12ac0531c5": {
|
||||
EntryPoints: []string{"tls"},
|
||||
Service: "tlsroute-default-tls-app-1-gw-default-my-gateway-ep-tls-0-5c999a999d12ac0531c5-wrr",
|
||||
Rule: `HostSNI("foo.com")`,
|
||||
Priority: 7,
|
||||
RuleSyntax: "default",
|
||||
TLS: &dynamic.RouterTCPTLSConfig{},
|
||||
},
|
||||
},
|
||||
Middlewares: map[string]*dynamic.TCPMiddleware{},
|
||||
Services: map[string]*dynamic.TCPService{
|
||||
"deny-unknown-host": {
|
||||
LoadBalancer: &dynamic.TCPServersLoadBalancer{},
|
||||
},
|
||||
"tlsroute-default-tls-app-1-gw-default-my-gateway-ep-tls-0-5c999a999d12ac0531c5-svc-default-whoami-0": {
|
||||
LoadBalancer: &dynamic.TCPServersLoadBalancer{
|
||||
Servers: []dynamic.TCPServer{
|
||||
{
|
||||
Address: "10.10.0.1:80",
|
||||
TLS: true,
|
||||
},
|
||||
{
|
||||
Address: "10.10.0.2:80",
|
||||
TLS: true,
|
||||
},
|
||||
},
|
||||
ServersTransport: "tlsroute-default-tls-app-1-gw-default-my-gateway-ep-tls-0-5c999a999d12ac0531c5-svc-default-whoami-0",
|
||||
},
|
||||
},
|
||||
"tlsroute-default-tls-app-1-gw-default-my-gateway-ep-tls-0-5c999a999d12ac0531c5-wrr": {
|
||||
Weighted: &dynamic.TCPWeightedRoundRobin{
|
||||
Services: []dynamic.TCPWRRService{
|
||||
{
|
||||
Name: "tlsroute-default-tls-app-1-gw-default-my-gateway-ep-tls-0-5c999a999d12ac0531c5-svc-default-whoami-0",
|
||||
Weight: new(1),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
ServersTransports: map[string]*dynamic.TCPServersTransport{
|
||||
"tlsroute-default-tls-app-1-gw-default-my-gateway-ep-tls-0-5c999a999d12ac0531c5-svc-default-whoami-0": {
|
||||
TLS: &dynamic.TLSClientConfig{
|
||||
ServerName: "whoami",
|
||||
RootCAs: []types.FileOrContent{
|
||||
"CA1",
|
||||
},
|
||||
Certificates: tls.Certificates{
|
||||
{
|
||||
CertFile: types.FileOrContent(listenerCert),
|
||||
KeyFile: types.FileOrContent(listenerKey),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
HTTP: &dynamic.HTTPConfiguration{
|
||||
Routers: map[string]*dynamic.Router{},
|
||||
Middlewares: map[string]*dynamic.Middleware{},
|
||||
Services: map[string]*dynamic.Service{},
|
||||
ServersTransports: map[string]*dynamic.ServersTransport{},
|
||||
},
|
||||
TLS: &dynamic.TLSConfiguration{
|
||||
Options: map[string]tls.Options{},
|
||||
Certificates: []*tls.CertAndStores{
|
||||
{
|
||||
CertFile: types.FileOrContent(listenerCert),
|
||||
KeyFile: types.FileOrContent(listenerKey),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "Simple TLSRoute and BackendTLSPolicy with subjectAltNames",
|
||||
paths: []string{"services.yml", "tlsroute/with_backend_tls_policy_san.yml"},
|
||||
@@ -13278,7 +13906,9 @@ func Test_makeGatewayStatus(t *testing.T) {
|
||||
p := Provider{}
|
||||
gateway := &gatev1.Gateway{Spec: gatev1.GatewaySpec{Infrastructure: test.infrastructure}}
|
||||
|
||||
status, _ := p.makeGatewayStatus(gateway, test.listeners, nil, slices.ContainsFunc(test.listeners, func(listener gatewayListener) bool {
|
||||
gwl := gatewayWithListeners{gateway: gateway, listeners: test.listeners}
|
||||
|
||||
status, _ := p.makeGatewayStatus(gwl, nil, slices.ContainsFunc(test.listeners, func(listener gatewayListener) bool {
|
||||
return len(listener.Status.Conditions) == 0
|
||||
}))
|
||||
|
||||
@@ -13513,6 +14143,109 @@ func Test_resolveFrontendValidation(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func Test_loadGatewayBackendTLS(t *testing.T) {
|
||||
k8sObjects, gwObjects := readResources(t, []string{"gateway_backend_client_certificate_refs.yml"})
|
||||
|
||||
kubeClient := kubefake.NewClientset(k8sObjects...)
|
||||
gwClient := newGatewaySimpleClientSet(t, gwObjects...)
|
||||
|
||||
client := newClientImpl(kubeClient, gwClient)
|
||||
|
||||
eventCh, err := client.WatchAll(nil, make(chan struct{}))
|
||||
require.NoError(t, err)
|
||||
|
||||
// just wait for the first event
|
||||
<-eventCh
|
||||
|
||||
p := Provider{client: client}
|
||||
|
||||
testCases := []struct {
|
||||
desc string
|
||||
certRef *gatev1.SecretObjectReference
|
||||
expectedCerts tls.Certificates
|
||||
expectedReason gatev1.GatewayConditionReason
|
||||
}{
|
||||
{
|
||||
desc: "no client certificate reference",
|
||||
},
|
||||
{
|
||||
desc: "Secret in the Gateway namespace",
|
||||
certRef: &gatev1.SecretObjectReference{Name: "client-cert"},
|
||||
expectedCerts: tls.Certificates{
|
||||
{CertFile: types.FileOrContent(listenerCert), KeyFile: types.FileOrContent(listenerKey)},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "Secret with an explicit core group",
|
||||
certRef: &gatev1.SecretObjectReference{Group: new(gatev1.Group("")), Name: "client-cert"},
|
||||
expectedCerts: tls.Certificates{
|
||||
{CertFile: types.FileOrContent(listenerCert), KeyFile: types.FileOrContent(listenerKey)},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "Secret in another namespace with ReferenceGrant",
|
||||
certRef: &gatev1.SecretObjectReference{Name: "client-cert", Namespace: new(gatev1.Namespace("bar"))},
|
||||
expectedCerts: tls.Certificates{
|
||||
{CertFile: types.FileOrContent(otherClientCert), KeyFile: types.FileOrContent(otherClientKey)},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "Secret in another namespace without ReferenceGrant",
|
||||
certRef: &gatev1.SecretObjectReference{Name: "ungranted-cert", Namespace: new(gatev1.Namespace("bar"))},
|
||||
expectedReason: gatev1.GatewayReasonRefNotPermitted,
|
||||
},
|
||||
{
|
||||
desc: "missing Secret",
|
||||
certRef: &gatev1.SecretObjectReference{Name: "missing-cert"},
|
||||
expectedReason: gatev1.GatewayReasonInvalidClientCertificateRef,
|
||||
},
|
||||
{
|
||||
desc: "malformed Secret",
|
||||
certRef: &gatev1.SecretObjectReference{Name: "malformed-cert"},
|
||||
expectedReason: gatev1.GatewayReasonInvalidClientCertificateRef,
|
||||
},
|
||||
{
|
||||
desc: "unsupported kind",
|
||||
certRef: &gatev1.SecretObjectReference{Kind: new(gatev1.Kind("ConfigMap")), Name: "client-cert"},
|
||||
expectedReason: gatev1.GatewayReasonInvalidClientCertificateRef,
|
||||
},
|
||||
{
|
||||
desc: "unsupported group",
|
||||
certRef: &gatev1.SecretObjectReference{Group: new(gatev1.Group("apps")), Name: "client-cert"},
|
||||
expectedReason: gatev1.GatewayReasonInvalidClientCertificateRef,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range testCases {
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
gateway := &gatev1.Gateway{
|
||||
Name: "my-gateway",
|
||||
Namespace: "default",
|
||||
Generation: 1,
|
||||
}
|
||||
if test.certRef != nil {
|
||||
gateway.Spec.TLS = &gatev1.GatewayTLSConfig{
|
||||
Backend: &gatev1.GatewayBackendTLS{ClientCertificateRef: test.certRef},
|
||||
}
|
||||
}
|
||||
|
||||
certs, errCondition := p.loadGatewayBackendTLS(gateway)
|
||||
|
||||
assert.Equal(t, test.expectedCerts, certs)
|
||||
|
||||
if test.expectedReason == "" {
|
||||
assert.Nil(t, errCondition)
|
||||
return
|
||||
}
|
||||
|
||||
require.NotNil(t, errCondition)
|
||||
assert.Equal(t, string(gatev1.GatewayConditionResolvedRefs), errCondition.Type)
|
||||
assert.Equal(t, metav1.ConditionFalse, errCondition.Status)
|
||||
assert.Equal(t, string(test.expectedReason), errCondition.Reason)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_loadGatewayListeners(t *testing.T) {
|
||||
k8sObjects, gwObjects := readResources(t, []string{"frontend_validation_ca_refs.yml"})
|
||||
|
||||
@@ -14187,6 +14920,95 @@ func Test_loadConfigurationFromGateways_BackendTLSPolicyAncestorNamespace(t *tes
|
||||
}
|
||||
}
|
||||
|
||||
func Test_makeGatewayStatus_resolvedRefs(t *testing.T) {
|
||||
resolvedListener := func() gatewayListener {
|
||||
return gatewayListener{Status: &gatev1.ListenerStatus{Name: "resolved"}}
|
||||
}
|
||||
unresolvedListener := func() gatewayListener {
|
||||
return gatewayListener{Status: &gatev1.ListenerStatus{
|
||||
Name: "unresolved",
|
||||
Conditions: []metav1.Condition{{
|
||||
Type: string(gatev1.ListenerConditionResolvedRefs),
|
||||
Status: metav1.ConditionFalse,
|
||||
Reason: string(gatev1.ListenerReasonInvalidCertificateRef),
|
||||
}},
|
||||
}}
|
||||
}
|
||||
unresolvedListenerSetListener := func() gatewayListener {
|
||||
listener := unresolvedListener()
|
||||
listener.ListenerSet = &gatev1.ListenerSet{}
|
||||
return listener
|
||||
}
|
||||
clientCertificateCondition := &metav1.Condition{
|
||||
Type: string(gatev1.GatewayConditionResolvedRefs),
|
||||
Status: metav1.ConditionFalse,
|
||||
Reason: string(gatev1.GatewayReasonInvalidClientCertificateRef),
|
||||
}
|
||||
|
||||
testCases := []struct {
|
||||
desc string
|
||||
listeners []gatewayListener
|
||||
errResolvedRefsCondition *metav1.Condition
|
||||
wantStatus metav1.ConditionStatus
|
||||
wantReason gatev1.GatewayConditionReason
|
||||
}{
|
||||
{
|
||||
desc: "all references resolved",
|
||||
listeners: []gatewayListener{resolvedListener()},
|
||||
wantStatus: metav1.ConditionTrue,
|
||||
wantReason: gatev1.GatewayReasonResolvedRefs,
|
||||
},
|
||||
{
|
||||
desc: "unresolved listener of a Gateway not accepted",
|
||||
listeners: []gatewayListener{unresolvedListener()},
|
||||
wantStatus: metav1.ConditionFalse,
|
||||
wantReason: gatev1.GatewayReasonListenersNotResolved,
|
||||
},
|
||||
{
|
||||
desc: "unresolved ListenerSet listener",
|
||||
listeners: []gatewayListener{resolvedListener(), unresolvedListenerSetListener()},
|
||||
wantStatus: metav1.ConditionTrue,
|
||||
wantReason: gatev1.GatewayReasonResolvedRefs,
|
||||
},
|
||||
{
|
||||
desc: "unresolved client certificate",
|
||||
listeners: []gatewayListener{resolvedListener()},
|
||||
errResolvedRefsCondition: clientCertificateCondition,
|
||||
wantStatus: metav1.ConditionFalse,
|
||||
wantReason: gatev1.GatewayReasonInvalidClientCertificateRef,
|
||||
},
|
||||
{
|
||||
desc: "unresolved client certificate and listener",
|
||||
listeners: []gatewayListener{resolvedListener(), unresolvedListener()},
|
||||
errResolvedRefsCondition: clientCertificateCondition,
|
||||
wantStatus: metav1.ConditionFalse,
|
||||
wantReason: gatev1.GatewayReasonInvalidClientCertificateRef,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range testCases {
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
p := Provider{}
|
||||
gwl := gatewayWithListeners{
|
||||
gateway: &gatev1.Gateway{},
|
||||
listeners: test.listeners,
|
||||
errResolvedRefsCondition: test.errResolvedRefsCondition,
|
||||
}
|
||||
|
||||
status, _ := p.makeGatewayStatus(gwl, nil, slices.ContainsFunc(test.listeners, func(listener gatewayListener) bool {
|
||||
return len(listener.Status.Conditions) == 0
|
||||
}))
|
||||
|
||||
condition := meta.FindStatusCondition(status.Conditions, string(gatev1.GatewayConditionResolvedRefs))
|
||||
require.NotNil(t, condition)
|
||||
assert.Equal(t, test.wantStatus, condition.Status)
|
||||
assert.Equal(t, string(test.wantReason), condition.Reason)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func certificateCommonName(t *testing.T, certFile types.FileOrContent) string {
|
||||
t.Helper()
|
||||
|
||||
|
||||
@@ -416,7 +416,7 @@ func (p *Provider) loadTLSServers(gatewayName, gatewayNamespace, namespace strin
|
||||
}
|
||||
|
||||
var resolvedRefCondition metav1.Condition
|
||||
serversTransport, resolvedRefCondition = p.loadTCPServersTransport(namespace, policy)
|
||||
serversTransport, resolvedRefCondition = p.loadTCPServersTransport(namespace, policy, listener.BackendClientCertificates)
|
||||
|
||||
policyAncestorStatus.Conditions = append(policyAncestorStatus.Conditions, resolvedRefCondition)
|
||||
if resolvedRefCondition.Status == metav1.ConditionFalse {
|
||||
@@ -478,10 +478,11 @@ func (p *Provider) loadTLSServers(gatewayName, gatewayNamespace, namespace strin
|
||||
return lb, serversTransport, nil
|
||||
}
|
||||
|
||||
func (p *Provider) loadTCPServersTransport(namespace string, policy *gatev1.BackendTLSPolicy) (*dynamic.TCPServersTransport, metav1.Condition) {
|
||||
func (p *Provider) loadTCPServersTransport(namespace string, policy *gatev1.BackendTLSPolicy, clientCertificates tls.Certificates) (*dynamic.TCPServersTransport, metav1.Condition) {
|
||||
st := &dynamic.TCPServersTransport{
|
||||
TLS: &dynamic.TLSClientConfig{
|
||||
ServerName: string(policy.Spec.Validation.Hostname),
|
||||
ServerName: string(policy.Spec.Validation.Hostname),
|
||||
Certificates: clientCertificates,
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user