-
Notifications
You must be signed in to change notification settings - Fork 309
Add ServerCertificateCustomValidationCallback for granular TLS validation control #1710
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
… validation Co-authored-by: tg123 <[email protected]>
|
[APPROVALNOTIFIER] This PR is NOT APPROVED This pull-request has been approved by: Copilot The full list of commands accepted by this bot can be found here. DetailsNeeds approval from an approver in each of these files:Approvers can indicate their approval by writing |
Co-authored-by: tg123 <[email protected]>
Co-authored-by: tg123 <[email protected]>
Co-authored-by: tg123 <[email protected]>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This pull request adds a ServerCertificateCustomValidationCallback property to KubernetesClientConfiguration, enabling fine-grained control over TLS certificate validation. This addresses scenarios where users need to disable only certificate revocation checking while maintaining other security validations, rather than completely disabling all TLS verification with SkipTlsVerify.
- Added
ServerCertificateCustomValidationCallbackproperty that takes precedence overSkipTlsVerifywhen set - Applied the custom callback to both HTTP and WebSocket connections with appropriate platform-specific handling
- Included comprehensive unit tests demonstrating various validation scenarios including revocation checking, certificate pinning, and precedence behavior
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 10 comments.
Show a summary per file
| File | Description |
|---|---|
| src/KubernetesClient/KubernetesClientConfiguration.cs | Added the ServerCertificateCustomValidationCallback property with detailed documentation and usage examples |
| src/KubernetesClient/Kubernetes.ConfigInit.cs | Implemented callback initialization logic with proper precedence handling and platform-specific adaptations for NET5_0_OR_GREATER |
| src/KubernetesClient/Kubernetes.WebSocket.cs | Applied custom validation callback to WebSocket connections with proper precedence over CaCerts and SkipTlsVerify |
| src/KubernetesClient/WebSocketBuilder.cs | Added SetServerCertificateCustomValidationCallback method to support custom validation in WebSocket connections |
| tests/KubernetesClient.Tests/CustomCertificateValidationTests.cs | Added comprehensive tests verifying callback configuration, precedence, and various validation scenarios |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| /// | ||
| /// // Disable revocation checking | ||
| /// chain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck; | ||
| /// return chain.Build((X509Certificate2)cert); |
Copilot
AI
Dec 28, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The cast to X509Certificate2 in the documentation example is redundant since the 'cert' parameter is already typed as X509Certificate2 in the callback signature. The example should use 'cert' directly instead of casting it.
| /// return chain.Build((X509Certificate2)cert); | |
| /// return chain.Build(cert); |
|
|
||
| // Disable revocation checking | ||
| chain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck; | ||
| return chain.Build((X509Certificate2)cert); |
Copilot
AI
Dec 28, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The cast to X509Certificate2 is redundant. Since 'cert' parameter in the callback is already X509Certificate2, you can pass it directly to chain.Build() without casting.
| return chain.Build((X509Certificate2)cert); | |
| return chain.Build(cert); |
| (sender, certificate, chain, sslPolicyErrors) => | ||
| { | ||
| // RemoteCertificateValidationCallback doesn't provide HttpRequestMessage, so pass null | ||
| var cert = certificate as X509Certificate2 ?? new X509Certificate2(certificate); |
Copilot
AI
Dec 28, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Creating a new X509Certificate2 from an existing certificate can lead to resource leaks since the newly created certificate is not disposed. Consider using a cast with null-coalescing instead: 'var cert = certificate as X509Certificate2 ?? throw new ArgumentException("Certificate must be X509Certificate2");' or document that callers should ensure proper disposal if needed.
| var cert = certificate as X509Certificate2 ?? new X509Certificate2(certificate); | |
| var cert = certificate as X509Certificate2 | |
| ?? throw new ArgumentException("Certificate must be X509Certificate2", nameof(certificate)); |
| (sender, certificate, chain, sslPolicyErrors) => | ||
| { | ||
| // Convert to the expected signature (with HttpRequestMessage as first parameter) | ||
| var cert = certificate as X509Certificate2 ?? new X509Certificate2(certificate); |
Copilot
AI
Dec 28, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Creating a new X509Certificate2 from an existing certificate can lead to resource leaks since the newly created certificate is not disposed. Consider using a cast with null-coalescing instead: 'var cert = certificate as X509Certificate2 ?? throw new ArgumentException("Certificate must be X509Certificate2");' or document that callers should ensure proper disposal if needed.
| }; | ||
|
|
||
| // Act | ||
| var client = new Kubernetes(config); |
Copilot
AI
Dec 28, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This assignment to client is useless, since its value is never read.
| }; | ||
|
|
||
| // Act | ||
| var client = new Kubernetes(config); |
Copilot
AI
Dec 28, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This assignment to client is useless, since its value is never read.
| }; | ||
|
|
||
| // Act | ||
| var client = new Kubernetes(config); |
Copilot
AI
Dec 28, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This assignment to client is useless, since its value is never read.
| }; | ||
|
|
||
| // Act | ||
| var client = new Kubernetes(config); |
Copilot
AI
Dec 28, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This assignment to client is useless, since its value is never read.
| }; | ||
|
|
||
| // Act | ||
| var client = new Kubernetes(config); |
Copilot
AI
Dec 28, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This assignment to client is useless, since its value is never read.
| }; | ||
|
|
||
| // Act | ||
| var client = new Kubernetes(config); |
Copilot
AI
Dec 28, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This assignment to client is useless, since its value is never read.
SkipTlsVerify = truedisables all certificate validation (chain, expiration, signature) when users only need to disable revocation checking for certificates where CRL/OCSP endpoints are inaccessible from within clusters.Changes
KubernetesClientConfiguration: Added
ServerCertificateCustomValidationCallbackproperty acceptingFunc<HttpRequestMessage, X509Certificate2, X509Chain, SslPolicyErrors, bool>SkipTlsVerifywhen setKubernetes.ConfigInit.cs: Custom callback checked first, then
SkipTlsVerify, then default validationWebSocketBuilder.cs: Added
SetServerCertificateCustomValidationCallbackfor WebSocket connection supportKubernetes.WebSocket.cs: Applies custom callback to WebSocket connections
Example Usage
Disable revocation checking only while maintaining chain, expiration, and signature validation:
Also supports certificate pinning, custom logging, or any X509Chain-based validation logic.
Warning
Firewall rules blocked me from connecting to one or more addresses (expand for details)
I tried to connect to the following addresses, but was blocked by firewall rules:
crl.comodoca.com/home/REDACTED/work/csharp/.codeql-scratch/dbs/csharp/working/.dotnet/dotnet /home/REDACTED/work/csharp/.codeql-scratch/dbs/csharp/working/.dotnet/dotnet restore --no-dependencies /home/REDACTED/work/csharp/csharp/src/KubernetesClient.Classic/KubernetesClient.Classic.csproj --packages /home/REDACTED/work/csharp/.codeql-scratch/dbs/csharp/working/packages /p:DisableImplicitNuGetFallbackFolder=true --verbosity normal /p:TargetFrameworkRootPath=/home/REDACTED/work/csharp/.codeql-scratch/dbs/csharp/working/emptyFakeDotnetRoot /p:NetCoreTargetingPackRoot=/home/REDACTED/work/csharp/.codeql-scratch/dbs/csharp/working/emptyFakeDotnetRoot(dns block)ocsp.comodoca.com/home/REDACTED/work/csharp/.codeql-scratch/dbs/csharp/working/.dotnet/dotnet /home/REDACTED/work/csharp/.codeql-scratch/dbs/csharp/working/.dotnet/dotnet restore --no-dependencies /home/REDACTED/work/csharp/csharp/src/KubernetesClient.Classic/KubernetesClient.Classic.csproj --packages /home/REDACTED/work/csharp/.codeql-scratch/dbs/csharp/working/packages /p:DisableImplicitNuGetFallbackFolder=true --verbosity normal /p:TargetFrameworkRootPath=/home/REDACTED/work/csharp/.codeql-scratch/dbs/csharp/working/emptyFakeDotnetRoot /p:NetCoreTargetingPackRoot=/home/REDACTED/work/csharp/.codeql-scratch/dbs/csharp/working/emptyFakeDotnetRoot(dns block)If you need me to access, download, or install something from one of these locations, you can either:
Original prompt
💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.