Skip to content

Commit 9bf66d5

Browse files
Add support for insecure connection and manual TLS certificate validation (#42)
* add insecure * Added AcceptInsecureConnection option to skip server cert validation and ServerCertificateCustomValidationCallback to manually perform cert validation. * Updated readme * netstandard 2.0 fix * tests fix --------- Co-authored-by: wizpresso-steve-cy-fan <[email protected]>
1 parent a1ed5c9 commit 9bf66d5

File tree

7 files changed

+262
-26
lines changed

7 files changed

+262
-26
lines changed

README.md

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -112,8 +112,9 @@ Alternatively, you can configure Vault connection using next environment variabl
112112
- `VAULT_TOKEN` : Vault token. Used for token-based authentication. Default value is `root`.
113113
- `VAULT_ROLEID` : Vault AppRole ID. Used for AppRole-based authentication.
114114
- `VAULT_SECRET` : Vault AppRole secret. Used for AppRole-based authentication.
115+
- `VAULT_INSECURE` : Allow insecure SSL connections to Vault. Default value is `false`.
115116

116-
## Configuration using IAuthMethodInfo
117+
## Configuration using code
117118

118119
You can configure Vault connection using any supported auth method (look at https://github.com/rajanadar/VaultSharp#auth-methods):
119120

@@ -128,6 +129,29 @@ config.AddVaultConfiguration(
128129
"secret");
129130
```
130131

132+
You can enable insecure TLS connections to Vault:
133+
134+
```csharp
135+
builder.AddVaultConfiguration(
136+
() => new VaultOptions("https://localhost:8200", "root", insecureConnection: true),
137+
"test",
138+
"secret",
139+
this._logger);
140+
```
141+
142+
Or manually validate TLS certificate:
143+
144+
```csharp
145+
builder.AddVaultConfiguration(
146+
() => new VaultOptions("https://localhost:8200", "root", additionalCharactersForConfigurationPath: new[] { '.' }, insecureConnection: false, serverCertificateCustomValidationCallback: (message, cert, chain, errors) =>
147+
{
148+
return true; //add your validation logic here
149+
}),
150+
"test",
151+
"secret",
152+
this._logger);
153+
```
154+
131155
## Preparing secrets in Vault
132156

133157
You need to store your secrets with special naming rules.
@@ -169,7 +193,7 @@ There are two ways to create nested parameters.
169193

170194
## Limitations
171195

172-
- Currently, only token and AppRole based authentication is supported.
196+
- Currently, only token and AppRole based authentication is supported from configuration. Other types of authentication can be used by code.
173197
- TTL of the secrets is not controlled.
174198

175199
## Contributing

Source/VaultSharp.Extensions.Configuration/VaultConfigurationExtensions.cs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
namespace VaultSharp.Extensions.Configuration
1+
namespace VaultSharp.Extensions.Configuration
22
{
33
#pragma warning disable CA2000
44

@@ -63,12 +63,15 @@ public static IConfigurationBuilder AddVaultConfiguration(
6363
throw new ArgumentNullException(nameof(basePath));
6464
}
6565

66+
var insecureOk = bool.TryParse(Environment.GetEnvironmentVariable(VaultEnvironmentVariableNames.InsecureConnection), out var insecure);
67+
6668
var vaultOptions = new VaultOptions(
6769
Environment.GetEnvironmentVariable(VaultEnvironmentVariableNames.Address) ??
6870
VaultConfigurationSource.DefaultVaultUrl,
6971
Environment.GetEnvironmentVariable(VaultEnvironmentVariableNames.Token) ?? VaultConfigurationSource.DefaultVaultToken,
7072
Environment.GetEnvironmentVariable(VaultEnvironmentVariableNames.Secret),
71-
Environment.GetEnvironmentVariable(VaultEnvironmentVariableNames.RoleId));
73+
Environment.GetEnvironmentVariable(VaultEnvironmentVariableNames.RoleId),
74+
insecureOk && insecure);
7275
configuration.Add(new VaultConfigurationSource(vaultOptions, basePath, mountPoint, logger));
7376
return configuration;
7477
}

Source/VaultSharp.Extensions.Configuration/VaultConfigurationProvider.cs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ namespace VaultSharp.Extensions.Configuration
55
using System.Globalization;
66
using System.Linq;
77
using System.Net;
8+
using System.Net.Http;
89
using System.Text;
910
using System.Text.Json;
1011
using System.Threading.Tasks;
@@ -74,6 +75,25 @@ public override void Load()
7475
{
7576
UseVaultTokenHeaderInsteadOfAuthorizationHeader = true,
7677
Namespace = this.ConfigurationSource.Options.Namespace,
78+
79+
PostProcessHttpClientHandlerAction = handler =>
80+
{
81+
if (handler is HttpClientHandler clientHandler)
82+
{
83+
if (this.ConfigurationSource.Options.AcceptInsecureConnection)
84+
{
85+
#if NETSTANDARD2_0
86+
clientHandler.ServerCertificateCustomValidationCallback = (message, cert, chain, sslPolicyErrors) => true;
87+
#else
88+
clientHandler.ServerCertificateCustomValidationCallback = HttpClientHandler.DangerousAcceptAnyServerCertificateValidator;
89+
#endif
90+
}
91+
else if (this.ConfigurationSource.Options.ServerCertificateCustomValidationCallback != null)
92+
{
93+
clientHandler.ServerCertificateCustomValidationCallback = this.ConfigurationSource.Options.ServerCertificateCustomValidationCallback;
94+
}
95+
}
96+
}
7797
};
7898
this.vaultClient = new VaultClient(vaultClientSettings);
7999
}

Source/VaultSharp.Extensions.Configuration/VaultEnvironmentVariableNames.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,5 +24,10 @@ public static class VaultEnvironmentVariableNames
2424
/// Environment variable name for Vault secret.
2525
/// </summary>
2626
public const string Secret = "VAULT_SECRET";
27+
28+
/// <summary>
29+
/// Environment variable name for disabling server certificate validation for Vault client.
30+
/// </summary>
31+
public const string InsecureConnection = "VAULT_INSECURE";
2732
}
2833
}

Source/VaultSharp.Extensions.Configuration/VaultOptions.cs

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@ namespace VaultSharp.Extensions.Configuration
22
{
33
using System;
44
using System.Collections.Generic;
5+
using System.Net.Http;
6+
using System.Net.Security;
7+
using System.Security.Cryptography.X509Certificates;
58
using VaultSharp.V1.AuthMethods;
69

710
/// <summary>
@@ -22,6 +25,8 @@ public class VaultOptions
2225
/// <param name="additionalCharactersForConfigurationPath">Additional characters for the Configuration path.</param>
2326
/// <param name="namespace">Vault namespace.</param>
2427
/// <param name="alwaysAddTrailingSlashToBasePath">Should a trailing slash be added to the base path. See AlwaysAddTrailingSlashToBasePath property for details </param>
28+
/// <param name="insecureConnection">(Dangerous!) Ignore certificate validation. This implies self-signed certificates are accepted.</param>
29+
/// <param name="serverCertificateCustomValidationCallback">An optional action to post-process the HttpClientHandler. Used to manually validate the server certificate. Ignored if AcceptInsecureConnection is true.</param>
2530
public VaultOptions(
2631
string vaultAddress,
2732
string? vaultToken,
@@ -32,7 +37,9 @@ public VaultOptions(
3237
bool omitVaultKeyName = false,
3338
IEnumerable<char>? additionalCharactersForConfigurationPath = null,
3439
string? @namespace = null,
35-
bool alwaysAddTrailingSlashToBasePath = true)
40+
bool alwaysAddTrailingSlashToBasePath = true,
41+
bool insecureConnection = false,
42+
Func<HttpRequestMessage, X509Certificate2?, X509Chain?, SslPolicyErrors, bool>? serverCertificateCustomValidationCallback = null)
3643
{
3744
this.VaultAddress = vaultAddress;
3845
this.VaultToken = vaultToken;
@@ -44,6 +51,8 @@ public VaultOptions(
4451
this.AdditionalCharactersForConfigurationPath = additionalCharactersForConfigurationPath ?? Array.Empty<char>();
4552
this.Namespace = @namespace;
4653
this.AlwaysAddTrailingSlashToBasePath = alwaysAddTrailingSlashToBasePath;
54+
this.AcceptInsecureConnection = insecureConnection;
55+
this.ServerCertificateCustomValidationCallback = serverCertificateCustomValidationCallback;
4756
}
4857

4958
/// <summary>
@@ -57,6 +66,8 @@ public VaultOptions(
5766
/// <param name="additionalCharactersForConfigurationPath">Additional characters for the Configuration path.</param>
5867
/// <param name="namespace">Vault namespace.</param>
5968
/// <param name="alwaysAddTrailingSlashToBasePath">Should a trailing slash be added to the base path. See AlwaysAddTrailingSlashToBasePath property for details </param>
69+
/// <param name="insecureConnection">(Dangerous!) Ignore certificate validation. This implies self-signed certificates are accepted.</param>
70+
/// <param name="serverCertificateCustomValidationCallback">An optional action to post-process the HttpClientHandler. Used to manually validate the server certificate. Ignored if AcceptInsecureConnection is true.</param>
6071
public VaultOptions(
6172
string vaultAddress,
6273
IAuthMethodInfo authMethod,
@@ -65,7 +76,9 @@ public VaultOptions(
6576
bool omitVaultKeyName = false,
6677
IEnumerable<char>? additionalCharactersForConfigurationPath = null,
6778
string? @namespace = null,
68-
bool alwaysAddTrailingSlashToBasePath = true)
79+
bool alwaysAddTrailingSlashToBasePath = true,
80+
bool insecureConnection = false,
81+
Func<HttpRequestMessage, X509Certificate2?, X509Chain?, SslPolicyErrors, bool>? serverCertificateCustomValidationCallback = null)
6982
{
7083
this.VaultAddress = vaultAddress;
7184
this.AuthMethod = authMethod;
@@ -75,6 +88,8 @@ public VaultOptions(
7588
this.AdditionalCharactersForConfigurationPath = additionalCharactersForConfigurationPath ?? Array.Empty<char>();
7689
this.Namespace = @namespace;
7790
this.AlwaysAddTrailingSlashToBasePath = alwaysAddTrailingSlashToBasePath;
91+
this.AcceptInsecureConnection = insecureConnection;
92+
this.ServerCertificateCustomValidationCallback = serverCertificateCustomValidationCallback;
7893
}
7994

8095
/// <summary>
@@ -116,7 +131,7 @@ public VaultOptions(
116131
/// <summary>
117132
/// Gets a value indicating whether the Vault key should be ommited when generation Configuration key names.
118133
/// </summary>
119-
public bool OmitVaultKeyName { get; }
134+
public bool OmitVaultKeyName { get; }
120135

121136
/// <summary>
122137
/// Gets an array of characters that will be used as a path to form the Configuration.
@@ -134,5 +149,19 @@ public VaultOptions(
134149
/// It is true by default. Set to false if you don't have permissions to list keys in the base path.
135150
/// </summary>
136151
public bool AlwaysAddTrailingSlashToBasePath { get; }
152+
153+
/// <summary>
154+
/// Indicates whether we should disregard the certificate validation (for examples, servers behind Internet aren't likely to have a strong certs but we can't afford to use HTTP either)
155+
/// Previously, the certificate behavior can be set globally, but subsequently removed in .NET Core and onwards due to security reasons.
156+
/// We need to set the behavior to each HttpClient on a case-by-case basis. As such, this option is provided as a resolution.
157+
/// If it is true, a custom PostProcessHttpClientHandlerAction will be injected to the VaultClientSettings to accept any server certificate.
158+
/// Default value: false. Hashicorp also recommend using a proper CA to setup Vault access due to security concerns.
159+
/// </summary>
160+
public bool AcceptInsecureConnection { get; }
161+
162+
/// <summary>
163+
/// An optional action to post-process the HttpClientHandler. Used to manually validate the server certificate. Ignored if AcceptInsecureConnection is true.
164+
/// </summary>
165+
public Func<HttpRequestMessage, X509Certificate2?, X509Chain?, SslPolicyErrors, bool>? ServerCertificateCustomValidationCallback { get; set;}
137166
}
138167
}

0 commit comments

Comments
 (0)