Skip to content

Commit c6a769b

Browse files
Merge pull request #13 from brendandburns/creds
Update credentials for more valid values.
2 parents 7717e65 + 6333784 commit c6a769b

22 files changed

+204
-39
lines changed

examples/simple/PodList.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,15 @@ static void Main(string[] args)
1010
{
1111
var k8sClientConfig = new KubernetesClientConfiguration();
1212
IKubernetes client = new Kubernetes(k8sClientConfig);
13+
Console.WriteLine("Starting Request!");
1314
var listTask = client.ListNamespacedPodWithHttpMessagesAsync("default").Result;
1415
var list = listTask.Body;
1516
foreach (var item in list.Items) {
1617
Console.WriteLine(item.Metadata.Name);
1718
}
19+
if (list.Items.Count == 0) {
20+
Console.WriteLine("Empty!");
21+
}
1822
}
1923
}
2024
}

examples/simple/simple.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
<PropertyGroup>
1010
<OutputType>Exe</OutputType>
11-
<TargetFramework>netcoreapp1.1</TargetFramework>
11+
<TargetFramework>netcoreapp2.0</TargetFramework>
1212
</PropertyGroup>
1313

1414
</Project>

src/KubeConfigModels/ClusterEndpoint.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@
44

55
public class ClusterEndpoint
66
{
7+
[YamlMember(Alias = "certificate-authority")]
8+
public string CertificateAuthority {get; set; }
9+
710
[YamlMember(Alias = "certificate-authority-data")]
811
public string CertificateAuthorityData { get; set; }
912

src/KubeConfigModels/K8SConfiguration.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@
88
/// </summary>
99
public class K8SConfiguration
1010
{
11+
[YamlMember(Alias = "preferences")]
12+
public IDictionary<string, object> preferences{ get; set; }
13+
1114
[YamlMember(Alias = "apiVersion")]
1215
public string ApiVersion { get; set; }
1316

src/KubeConfigModels/UserCredentials.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
namespace k8s.KubeConfigModels
22
{
3+
using System.Collections.Generic;
34
using YamlDotNet.RepresentationModel;
45
using YamlDotNet.Serialization;
56

@@ -8,9 +9,15 @@ public class UserCredentials
89
[YamlMember(Alias = "client-certificate-data")]
910
public string ClientCertificateData { get; set; }
1011

12+
[YamlMember(Alias = "client-certificate")]
13+
public string ClientCertificate { get; set; }
14+
1115
[YamlMember(Alias = "client-key-data")]
1216
public string ClientKeyData { get; set; }
1317

18+
[YamlMember(Alias = "client-key")]
19+
public string ClientKey { get; set; }
20+
1421
[YamlMember(Alias = "token")]
1522
public string Token { get; set; }
1623

@@ -19,5 +26,8 @@ public class UserCredentials
1926

2027
[YamlMember(Alias = "password")]
2128
public string Password { get; set; }
29+
30+
[YamlMember(Alias = "auth-provider")]
31+
public Dictionary<string, dynamic> AuthProvider { get; set; }
2232
}
2333
}

src/Kubernetes.Auth.cs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ public Kubernetes(KubernetesClientConfiguration config)
2121
{
2222
this.Initialize();
2323

24-
this.CaCert = Utils.Base64Decode(config.SslCaCert);
24+
this.CaCert = config.SslCaCert;
2525
this.BaseUri = new Uri(config.Host);
2626

2727
// ssl cert validation
@@ -45,7 +45,7 @@ public Kubernetes(KubernetesClientConfiguration config)
4545
this.InitializeHttpClient(handler);
4646
}
4747

48-
private string CaCert { get; set; }
48+
private X509Certificate2 CaCert { get; set; }
4949

5050
/// <summary>
5151
/// Set credentials for the Client
@@ -65,7 +65,10 @@ private async Task SetCredentialsAsync(KubernetesClientConfiguration config, Htt
6565
this.Credentials = new KubernetesClientCredentials(config.Username, config.Password);
6666
}
6767
// othwerwise set handler for clinet cert based auth
68-
else if (!string.IsNullOrWhiteSpace(config.ClientCertificateData) && !string.IsNullOrWhiteSpace(config.ClientCertificateKey))
68+
else if ((!string.IsNullOrWhiteSpace(config.ClientCertificateData) ||
69+
!string.IsNullOrWhiteSpace(config.ClientCertificate)) &&
70+
(!string.IsNullOrWhiteSpace(config.ClientCertificateKey) ||
71+
!string.IsNullOrWhiteSpace(config.ClientKey)))
6972
{
7073
var pfxFilePath = await Utils.GeneratePfxAsync(config).ConfigureAwait(false);
7174
if (string.IsNullOrWhiteSpace(pfxFilePath))
@@ -110,7 +113,7 @@ private bool CertificateValidationCallBack(
110113
chain0.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck;
111114

112115
// add all your extra certificate chain
113-
chain0.ChainPolicy.ExtraStore.Add(new X509Certificate2(System.Text.Encoding.UTF8.GetBytes(this.CaCert)));
116+
chain0.ChainPolicy.ExtraStore.Add(this.CaCert);
114117
chain0.ChainPolicy.VerificationFlags = X509VerificationFlags.AllowUnknownCertificateAuthority;
115118
var isValid = chain0.Build((X509Certificate2)certificate);
116119
return isValid;

src/KubernetesClientConfiguration.cs

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ namespace k8s
33
using System;
44
using System.IO;
55
using System.Linq;
6+
using System.Security.Cryptography.X509Certificates;
67
using k8s.Exceptions;
78
using k8s.KubeConfigModels;
89
using YamlDotNet.Serialization;
@@ -49,7 +50,7 @@ public KubernetesClientConfiguration(FileInfo kubeconfig = null, string currentC
4950
/// <summary>
5051
/// Gets SslCaCert
5152
/// </summary>
52-
public string SslCaCert { get; private set; }
53+
public X509Certificate2 SslCaCert { get; private set; }
5354

5455
/// <summary>
5556
/// Gets ClientCertificateData
@@ -61,6 +62,16 @@ public KubernetesClientConfiguration(FileInfo kubeconfig = null, string currentC
6162
/// </summary>
6263
public string ClientCertificateKey { get; private set; }
6364

65+
/// <summary>
66+
/// Gets ClientCertificate filename
67+
/// </summary>
68+
public string ClientCertificate { get; private set; }
69+
70+
/// <summary>
71+
/// Gets ClientCertificate Key filename
72+
/// </summary>
73+
public string ClientKey { get; private set; }
74+
6475
/// <summary>
6576
/// Gets a value indicating whether to skip ssl server cert validation
6677
/// </summary>
@@ -145,13 +156,20 @@ private void Initialize(K8SConfiguration k8SConfig, string currentContext = null
145156
}
146157

147158
if (!clusterDetails.ClusterEndpoint.SkipTlsVerify &&
148-
string.IsNullOrWhiteSpace(clusterDetails.ClusterEndpoint.CertificateAuthorityData))
159+
string.IsNullOrWhiteSpace(clusterDetails.ClusterEndpoint.CertificateAuthorityData) &&
160+
string.IsNullOrWhiteSpace(clusterDetails.ClusterEndpoint.CertificateAuthority))
149161
{
150-
throw new KubeConfigException($"certificate-authority-data not found for current-context :{activeContext} in kubeconfig");
162+
throw new KubeConfigException($"neither certificate-authority-data nor certificate-authority not found for current-context :{activeContext} in kubeconfig");
151163
}
152164

153165
this.Host = clusterDetails.ClusterEndpoint.Server;
154-
this.SslCaCert = clusterDetails.ClusterEndpoint.CertificateAuthorityData;
166+
if (!string.IsNullOrEmpty(clusterDetails.ClusterEndpoint.CertificateAuthorityData)) {
167+
string data = clusterDetails.ClusterEndpoint.CertificateAuthorityData;
168+
this.SslCaCert = new X509Certificate2(System.Text.Encoding.UTF8.GetBytes(Utils.Base64Decode(data)));
169+
}
170+
else if (!string.IsNullOrEmpty(clusterDetails.ClusterEndpoint.CertificateAuthority)) {
171+
this.SslCaCert = new X509Certificate2(clusterDetails.ClusterEndpoint.CertificateAuthority, null);
172+
}
155173
this.SkipTlsVerify = clusterDetails.ClusterEndpoint.SkipTlsVerify;
156174
}
157175
else
@@ -202,6 +220,13 @@ private void SetUserDetails(User userDetails)
202220
userCredentialsFound = true;
203221
}
204222

223+
if (!string.IsNullOrWhiteSpace(userDetails.UserCredentials.ClientCertificate) &&
224+
!string.IsNullOrWhiteSpace(userDetails.UserCredentials.ClientKey)) {
225+
this.ClientCertificate = userDetails.UserCredentials.ClientCertificate;
226+
this.ClientKey = userDetails.UserCredentials.ClientKey;
227+
userCredentialsFound = true;
228+
}
229+
205230
if (!userCredentialsFound)
206231
{
207232
throw new KubeConfigException($"User: {userDetails.Name} does not have appropriate auth credentials in kube config");

src/Utils.cs

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -45,23 +45,35 @@ public static async Task<string> GeneratePfxAsync(KubernetesClientConfiguration
4545
var certDirPath = Path.Combine(userHomeDir, ".k8scerts");
4646
Directory.CreateDirectory(certDirPath);
4747

48+
var keyFilePath = "";
49+
var certFilePath = "";
50+
4851
var filePrefix = config.CurrentContext;
49-
var keyFilePath = Path.Combine(certDirPath, filePrefix + "key");
50-
var certFilePath = Path.Combine(certDirPath, filePrefix + "cert");
5152
var pfxFilePath = Path.Combine(certDirPath, filePrefix + "pfx");
52-
53-
using (FileStream fs = File.Create(keyFilePath))
54-
{
55-
byte[] info = Convert.FromBase64String(config.ClientCertificateKey);
56-
await fs.WriteAsync(info, 0, info.Length).ConfigureAwait(false);
53+
if (!string.IsNullOrWhiteSpace(config.ClientCertificateKey)) {
54+
keyFilePath = Path.Combine(certDirPath, filePrefix + "key");
55+
using (FileStream fs = File.Create(keyFilePath))
56+
{
57+
byte[] info = Convert.FromBase64String(config.ClientCertificateKey);
58+
await fs.WriteAsync(info, 0, info.Length).ConfigureAwait(false);
59+
}
5760
}
58-
59-
using (FileStream fs = File.Create(certFilePath))
60-
{
61-
byte[] info = Convert.FromBase64String(config.ClientCertificateData);
62-
await fs.WriteAsync(info, 0, info.Length).ConfigureAwait(false);
61+
if (!string.IsNullOrWhiteSpace(config.ClientKey)) {
62+
keyFilePath = config.ClientKey;
6363
}
6464

65+
if (!string.IsNullOrWhiteSpace(config.ClientCertificateData)) {
66+
certFilePath = Path.Combine(certDirPath, filePrefix + "cert");
67+
68+
using (FileStream fs = File.Create(certFilePath))
69+
{
70+
byte[] info = Convert.FromBase64String(config.ClientCertificateData);
71+
await fs.WriteAsync(info, 0, info.Length).ConfigureAwait(false);
72+
}
73+
}
74+
if (!string.IsNullOrWhiteSpace(config.ClientCertificate)) {
75+
certFilePath = config.ClientCertificate;
76+
}
6577
var process = new Process();
6678
process.StartInfo = new ProcessStartInfo()
6779
{

tests/KubernetesClientConfigurationTests.cs

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,11 @@ namespace k8s.Tests
88
public class KubernetesClientConfigurationTests
99
{
1010

11+
public static string readLine(string fileName) {
12+
StreamReader reader = new StreamReader(new FileStream(fileName, FileMode.Open, FileAccess.Read));
13+
return reader.ReadLine();
14+
}
15+
1116
/// <summary>
1217
/// This file contains a sample kubeconfig file
1318
/// </summary>
@@ -110,16 +115,33 @@ public void ContextUserTokenTest(string context, string token)
110115
/// <param name="clientCertData">'client-certificate-data' node content</param>
111116
/// <param name="clientCertKey">'client-key-data' content</param>
112117
[Theory]
113-
[InlineData("federal-context", "path/to/my/client/cert" ,"path/to/my/client/key")]
114-
public void ContextCertificateTest(string context, string clientCertData, string clientCertKey)
118+
[InlineData("federal-context", "assets/client.crt" ,"assets/client.key")]
119+
public void ContextCertificateTest(string context, string clientCert, string clientCertKey)
120+
{
121+
var fi = new FileInfo(kubeConfigFileName);
122+
var cfg = new KubernetesClientConfiguration(fi, context);
123+
Assert.Equal(context, cfg.CurrentContext);
124+
Assert.Equal(cfg.ClientCertificate, clientCert);
125+
Assert.Equal(cfg.ClientKey, clientCertKey);
126+
}
127+
128+
/// <summary>
129+
/// Checks if certificate-based authentication is loaded properly from the config file, per context
130+
/// </summary>
131+
/// <param name="context">Context to retreive the configuration</param>
132+
[Theory]
133+
[InlineData("victorian-context")]
134+
public void ClientDataTest(string context)
115135
{
116136
var fi = new FileInfo(kubeConfigFileName);
117137
var cfg = new KubernetesClientConfiguration(fi, context);
118138
Assert.Equal(context, cfg.CurrentContext);
119-
Assert.Equal(cfg.ClientCertificateData, clientCertData);
120-
Assert.Equal(cfg.ClientCertificateKey, clientCertKey);
139+
Assert.NotNull(cfg.SslCaCert);
140+
Assert.Equal(readLine("assets/client-certificate-data.txt"), cfg.ClientCertificateData);
141+
Assert.Equal(readLine("assets/client-key-data.txt"), cfg.ClientCertificateKey);
121142
}
122143

144+
123145
/// <summary>
124146
/// Test that an Exception is thrown when initializating a KubernetClientConfiguration whose config file Context is not present
125147
/// </summary>

tests/assets/ca-data.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURERENDQWZTZ0F3SUJBZ0lSQUo5ZCtLeThkTDJVSzRjdXplMmo2WnN3RFFZSktvWklodmNOQVFFTEJRQXcKTHpFdE1Dc0dBMVVFQXhNa1lXRTBZVFV3T0RZdE0yVm1aaTAwWWpCa0xUbGxORGt0WmpNeVpXWXpabUpqWWpNNApNQjRYRFRFM01ESXlOakExTURRek5Gb1hEVEl5TURJeU5UQTFNRFF6TkZvd0x6RXRNQ3NHQTFVRUF4TWtZV0UwCllUVXdPRFl0TTJWbVppMDBZakJrTFRsbE5Ea3Raak15WldZelptSmpZak00TUlJQklqQU5CZ2txaGtpRzl3MEIKQVFFRkFBT0NBUThBTUlJQkNnS0NBUUVBM2dkandhdHNsdCsvQVpqV3hmbkNQeGZqMzNHUUxlOU00VU42VmEwRQpKd0FYL2R3L1ZVa0dvVjlDc3NKRUZMdEdTUnM2K2h0RTEvOUN3ak1USDh2WExKcURHTE9KdFQ5dW9sR2c2Q2k1ClBKNDNKelVLWmJlYVE4Z3hhZndzQjdQU05vTTJOYzROVm9lZzBVTUw0bndGeEhXeTNYWHlFZ0QxTWxTUnVrb3oKTTNoRUVxUjJNVFdrNm9KK3VJNFF4WVZWMnZuWXdXaEJwUDlDR3RWUTlyUW9MVFowcmFpOCtDYURBMVltTWRhbQpRYUVPdURlSFRqU2FYM2dyR0FBVVFWNWl6MC9qVVBuK3lJNm1iV0trbzFzNytPY1dZR2F1aDFaMzFYSjJsc0RTCnU4a3F0d215UEcyUVl2aUQ4YjNOWFAyY0dRK2EwZlpRZnBrbTF0U3IxQnhhaXdJREFRQUJveU13SVRBT0JnTlYKSFE4QkFmOEVCQU1DQWdRd0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBTkJna3Foa2lHOXcwQkFRc0ZBQU9DQVFFQQpuVzFXVXlLbVJ0TlNzU1VzVFBSUnhFRzhhek9kdjdYeUhRL0R5VWNqWm9rUEJVVHY4VjdvNG96RHgyVHV6UEdYCmZ2YlMvT2g0VDd6ZlYxdjJadmU3dTBxelNiRTl5OGpsaDNxYXJEcEd5ZmlTamwycmhIOFBmay9sZGR0VFpVL04KSkVtYW5ReGl6R20xV2pCSklRSE5LZENneVIwN3A1c0MwNnR3K25YUytla1MxMlBUTG45WjBuRDBKVDdQSzRXQgpQc3ZXeDVXN0w5dnJIdVN5SGRSTkt5eEEvbWI1WHdXMDBkZUpmaHZub0p3ZWRYNDVKZVRiME5MczUzaURqVEU1CnRpdU03Z1RVSjlCcGZTL0gvYSt2SmovVWQ2bHM0QndrWmpUNHNhOTA1bnNzdnRqamlwZ1N5a0QzVkxCQ3VueTkKd1NnbE1vSnZNWmg0bC9FVFJPeFE3Zz09Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K

0 commit comments

Comments
 (0)