1
+ using System ;
2
+ using System . IO ;
3
+ using System . Linq ;
4
+ using System . Runtime . InteropServices ;
5
+ using System . Security . Cryptography . X509Certificates ;
6
+ using k8s . Exceptions ;
7
+ using k8s . KubeConfigModels ;
8
+ using YamlDotNet . Serialization ;
9
+
10
+ namespace k8s
11
+ {
12
+ public partial class KubernetesClientConfiguration
13
+ {
14
+ /// <summary>
15
+ /// Gets CurrentContext
16
+ /// </summary>
17
+ public string CurrentContext { get ; private set ; }
18
+
19
+ /// <summary>
20
+ /// kubeconfig Default Location
21
+ /// </summary>
22
+ private static readonly string KubeConfigDefaultLocation =
23
+ RuntimeInformation . IsOSPlatform ( OSPlatform . Windows )
24
+ ? Path . Combine ( Environment . GetEnvironmentVariable ( "USERPROFILE" ) , @".kube\config" )
25
+ : Path . Combine ( Environment . GetEnvironmentVariable ( "HOME" ) , ".kube/config" ) ;
26
+
27
+ /// <summary>
28
+ /// Initializes a new instance of the <see cref="KubernetesClientConfiguration"/> class.
29
+ /// </summary>
30
+ /// <param name="kubeconfig">kubeconfig file info</param>
31
+ /// <param name="currentContext">Context to use from kube config</param>
32
+ public KubernetesClientConfiguration ( FileInfo kubeconfig = null , string currentContext = null )
33
+ {
34
+ var k8SConfig = LoadKubeConfig ( kubeconfig ?? new FileInfo ( KubeConfigDefaultLocation ) ) ;
35
+ this . Initialize ( k8SConfig , currentContext ) ;
36
+ }
37
+
38
+ /// <summary>
39
+ /// Initializes a new instance of the <see cref="KubernetesClientConfiguration"/> from config file
40
+ /// </summary>
41
+ /// <param name="masterUrl">kube api server endpoint</param>
42
+ /// <param name="kubeconfigPath">kubeconfig filepath</param>
43
+ /// <returns></returns>
44
+ public static KubernetesClientConfiguration BuildConfigFromConfigFile ( string masterUrl = null , string kubeconfigPath = null )
45
+ {
46
+ var k8SConfig = LoadKubeConfig ( new FileInfo ( kubeconfigPath ?? KubeConfigDefaultLocation ) ) ;
47
+ var k8SConfiguration = new KubernetesClientConfiguration ( ) ;
48
+ k8SConfiguration . Initialize ( k8SConfig ) ;
49
+
50
+ if ( ! string . IsNullOrWhiteSpace ( masterUrl ) )
51
+ {
52
+ k8SConfiguration . Host = masterUrl ;
53
+ }
54
+ return k8SConfiguration ;
55
+ }
56
+
57
+ /// <summary>
58
+ /// Validates and Intializes Client Configuration
59
+ /// </summary>
60
+ /// <param name="k8SConfig">Kubernetes Configuration</param>
61
+ /// <param name="currentContext">Current Context</param>
62
+ private void Initialize ( K8SConfiguration k8SConfig , string currentContext = null )
63
+ {
64
+ if ( k8SConfig . Contexts == null )
65
+ {
66
+ throw new KubeConfigException ( "No contexts found in kubeconfig" ) ;
67
+ }
68
+
69
+ if ( k8SConfig . Clusters == null )
70
+ {
71
+ throw new KubeConfigException ( $ "No clusters found in kubeconfig") ;
72
+ }
73
+
74
+ if ( k8SConfig . Users == null )
75
+ {
76
+ throw new KubeConfigException ( $ "No users found in kubeconfig") ;
77
+ }
78
+
79
+ // current context
80
+ currentContext = currentContext ?? k8SConfig . CurrentContext ;
81
+ Context activeContext =
82
+ k8SConfig . Contexts . FirstOrDefault (
83
+ c => c . Name . Equals ( currentContext , StringComparison . OrdinalIgnoreCase ) ) ;
84
+ if ( activeContext == null )
85
+ {
86
+ throw new KubeConfigException ( $ "CurrentContext: { currentContext } not found in contexts in kubeconfig") ;
87
+ }
88
+
89
+ this . CurrentContext = activeContext . Name ;
90
+
91
+ // cluster
92
+ var clusterDetails =
93
+ k8SConfig . Clusters . FirstOrDefault ( c => c . Name . Equals ( activeContext . ContextDetails . Cluster ,
94
+ StringComparison . OrdinalIgnoreCase ) ) ;
95
+ if ( clusterDetails ? . ClusterEndpoint == null )
96
+ {
97
+ throw new KubeConfigException ( $ "Cluster not found for context { activeContext } in kubeconfig") ;
98
+ }
99
+
100
+ if ( string . IsNullOrWhiteSpace ( clusterDetails . ClusterEndpoint . Server ) )
101
+ {
102
+ throw new KubeConfigException ( $ "Server not found for current-context { activeContext } in kubeconfig") ;
103
+ }
104
+
105
+ if ( ! clusterDetails . ClusterEndpoint . SkipTlsVerify &&
106
+ string . IsNullOrWhiteSpace ( clusterDetails . ClusterEndpoint . CertificateAuthorityData ) &&
107
+ string . IsNullOrWhiteSpace ( clusterDetails . ClusterEndpoint . CertificateAuthority ) )
108
+ {
109
+ throw new KubeConfigException (
110
+ $ "neither certificate-authority-data nor certificate-authority not found for current-context :{ activeContext } in kubeconfig") ;
111
+ }
112
+
113
+ this . Host = clusterDetails . ClusterEndpoint . Server ;
114
+ if ( ! string . IsNullOrEmpty ( clusterDetails . ClusterEndpoint . CertificateAuthorityData ) )
115
+ {
116
+ string data = clusterDetails . ClusterEndpoint . CertificateAuthorityData ;
117
+ this . SslCaCert = new X509Certificate2 ( System . Text . Encoding . UTF8 . GetBytes ( Utils . Base64Decode ( data ) ) ) ;
118
+ }
119
+ else if ( ! string . IsNullOrEmpty ( clusterDetails . ClusterEndpoint . CertificateAuthority ) )
120
+ {
121
+ this . SslCaCert = new X509Certificate2 ( clusterDetails . ClusterEndpoint . CertificateAuthority ) ;
122
+ }
123
+ this . SkipTlsVerify = clusterDetails . ClusterEndpoint . SkipTlsVerify ;
124
+
125
+ // user
126
+ this . SetUserDetails ( k8SConfig , activeContext ) ;
127
+ }
128
+
129
+ private void SetUserDetails ( K8SConfiguration k8SConfig , Context activeContext )
130
+ {
131
+ var userDetails = k8SConfig . Users . FirstOrDefault ( c => c . Name . Equals ( activeContext . ContextDetails . User ,
132
+ StringComparison . OrdinalIgnoreCase ) ) ;
133
+
134
+ if ( userDetails == null )
135
+ {
136
+ throw new KubeConfigException ( "User not found for context {activeContext.Name} in kubeconfig" ) ;
137
+ }
138
+
139
+ if ( userDetails . UserCredentials == null )
140
+ {
141
+ throw new KubeConfigException ( $ "User credentials not found for user: { userDetails . Name } in kubeconfig") ;
142
+ }
143
+
144
+ var userCredentialsFound = false ;
145
+
146
+ // Basic and bearer tokens are mutually exclusive
147
+ if ( ! string . IsNullOrWhiteSpace ( userDetails . UserCredentials . Token ) )
148
+ {
149
+ this . AccessToken = userDetails . UserCredentials . Token ;
150
+ userCredentialsFound = true ;
151
+ }
152
+ else if ( ! string . IsNullOrWhiteSpace ( userDetails . UserCredentials . UserName ) &&
153
+ ! string . IsNullOrWhiteSpace ( userDetails . UserCredentials . Password ) )
154
+ {
155
+ this . Username = userDetails . UserCredentials . UserName ;
156
+ this . Password = userDetails . UserCredentials . Password ;
157
+ userCredentialsFound = true ;
158
+ }
159
+
160
+ // Token and cert based auth can co-exist
161
+ if ( ! string . IsNullOrWhiteSpace ( userDetails . UserCredentials . ClientCertificateData ) &&
162
+ ! string . IsNullOrWhiteSpace ( userDetails . UserCredentials . ClientKeyData ) )
163
+ {
164
+ this . ClientCertificateData = userDetails . UserCredentials . ClientCertificateData ;
165
+ this . ClientCertificateKey = userDetails . UserCredentials . ClientKeyData ;
166
+ userCredentialsFound = true ;
167
+ }
168
+
169
+ if ( ! string . IsNullOrWhiteSpace ( userDetails . UserCredentials . ClientCertificate ) &&
170
+ ! string . IsNullOrWhiteSpace ( userDetails . UserCredentials . ClientKey ) )
171
+ {
172
+ this . ClientCertificate = userDetails . UserCredentials . ClientCertificate ;
173
+ this . ClientKey = userDetails . UserCredentials . ClientKey ;
174
+ userCredentialsFound = true ;
175
+ }
176
+
177
+ if ( ! userCredentialsFound )
178
+ {
179
+ throw new KubeConfigException (
180
+ $ "User: { userDetails . Name } does not have appropriate auth credentials in kubeconfig") ;
181
+ }
182
+ }
183
+
184
+ /// <summary>
185
+ /// Loads Kube Config
186
+ /// </summary>
187
+ /// <param name="config">Kube config file contents</param>
188
+ /// <returns>Instance of the <see cref="K8SConfiguration"/> class</returns>
189
+ private static K8SConfiguration LoadKubeConfig ( FileInfo kubeconfig )
190
+ {
191
+ if ( ! kubeconfig . Exists )
192
+ {
193
+ throw new KubeConfigException ( $ "kubeconfig file not found at { kubeconfig . FullName } ") ;
194
+ }
195
+ var kubeconfigContent = File . ReadAllText ( kubeconfig . FullName ) ;
196
+
197
+ var deserializeBuilder = new DeserializerBuilder ( ) ;
198
+ var deserializer = deserializeBuilder . Build ( ) ;
199
+ return deserializer . Deserialize < K8SConfiguration > ( kubeconfigContent ) ;
200
+ }
201
+ }
202
+ }
0 commit comments